1 /*
2 * packet-winsrepl.c
3 *
4 * Routines for WINS Replication packet dissection
5 *
6 * Copyright 2005 Stefan Metzmacher <metze@samba.org>
7 *
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
11 *
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 */
14
15 #include "config.h"
16
17 #include <epan/packet.h>
18 #include <epan/expert.h>
19 #include <epan/exceptions.h>
20 #include <epan/prefs.h>
21 #include <epan/to_str.h>
22
23 #include "packet-netbios.h"
24
25 #include "packet-tcp.h"
26
27 void proto_register_winsrepl(void);
28 void proto_reg_handoff_winsrepl(void);
29
30 static gboolean winsrepl_reassemble = TRUE;
31
32 static int proto_winsrepl = -1;
33
34 static int hf_winsrepl_size = -1;
35 static int hf_winsrepl_opcode = -1;
36 static int hf_winsrepl_assoc_ctx = -1;
37 static int hf_winsrepl_mess_type = -1;
38
39 static int hf_winsrepl_start_minor_version = -1;
40 static int hf_winsrepl_start_major_version = -1;
41
42 static int hf_winsrepl_stop_reason = -1;
43
44 static int hf_winsrepl_replication_command = -1;
45
46 static int hf_winsrepl_owner_address = -1;
47 static int hf_winsrepl_owner_max_version = -1;
48 static int hf_winsrepl_owner_min_version = -1;
49 static int hf_winsrepl_owner_type = -1;
50
51 static int hf_winsrepl_table_partner_count = -1;
52 static int hf_winsrepl_table_initiator = -1;
53
54 static int hf_winsrepl_ip_owner = -1;
55 static int hf_winsrepl_ip_ip = -1;
56 static int hf_winsrepl_addr_list_num_ips = -1;
57
58 static int hf_winsrepl_name_len = -1;
59 static int hf_winsrepl_name_flags = -1;
60 static int hf_winsrepl_name_flags_rectype = -1;
61 static int hf_winsrepl_name_flags_recstate = -1;
62 static int hf_winsrepl_name_flags_local = -1;
63 static int hf_winsrepl_name_flags_hosttype = -1;
64 static int hf_winsrepl_name_flags_static = -1;
65 static int hf_winsrepl_name_group_flag = -1;
66 static int hf_winsrepl_name_version_id = -1;
67 static int hf_winsrepl_name_unknown = -1;
68
69 static int hf_winsrepl_reply_num_names = -1;
70
71 static gint ett_winsrepl = -1;
72
73 static gint ett_winsrepl_start = -1;
74 static gint ett_winsrepl_stop = -1;
75 static gint ett_winsrepl_replication = -1;
76
77 static gint ett_winsrepl_owner = -1;
78 static gint ett_winsrepl_table_reply = -1;
79
80 static gint ett_winsrepl_ip = -1;
81 static gint ett_winsrepl_addr_list = -1;
82
83 static gint ett_winsrepl_name = -1;
84 static gint ett_winsrepl_send_reply = -1;
85
86 static gint ett_winsrepl_flags = -1;
87
88 static expert_field ei_winsrepl_name_len = EI_INIT;
89
90 #define WINS_REPLICATION_PORT ( 42 )
91 #define WREPL_OPCODE_BITS ( 0x7800 )
92
93 enum wrepl_replication_cmd {
94 WREPL_REPL_TABLE_QUERY=0,
95 WREPL_REPL_TABLE_REPLY=1,
96 WREPL_REPL_SEND_REQUEST=2,
97 WREPL_REPL_SEND_REPLY=3,
98 WREPL_REPL_UPDATE=4,
99 WREPL_REPL_UPDATE2=5,
100 WREPL_REPL_INFORM=8,
101 WREPL_REPL_INFORM2=9
102 };
103
104 enum wrepl_mess_type {
105 WREPL_START_ASSOCIATION=0,
106 WREPL_START_ASSOCIATION_REPLY=1,
107 WREPL_STOP_ASSOCIATION=2,
108 WREPL_REPLICATION=3
109 };
110
111 static const value_string replication_cmd_vals[] = {
112 {WREPL_REPL_TABLE_QUERY, "WREPL_REPL_TABLE_QUERY"},
113 {WREPL_REPL_TABLE_REPLY, "WREPL_REPL_TABLE_REPLY"},
114 {WREPL_REPL_SEND_REQUEST, "WREPL_REPL_SEND_REQUEST"},
115 {WREPL_REPL_SEND_REPLY, "WREPL_REPL_SEND_REPLY"},
116 {WREPL_REPL_UPDATE, "WREPL_REPL_UPDATE"},
117 {WREPL_REPL_UPDATE2, "WREPL_REPL_UPDATE2"},
118 {WREPL_REPL_INFORM, "WREPL_REPL_INFORM"},
119 {WREPL_REPL_INFORM2, "WREPL_REPL_INFORM2"},
120 {0, NULL}
121 };
122
123 static const value_string message_type_vals[] = {
124 {WREPL_START_ASSOCIATION, "WREPL_START_ASSOCIATION"},
125 {WREPL_START_ASSOCIATION_REPLY, "WREPL_START_ASSOCIATION_REPLY"},
126 {WREPL_STOP_ASSOCIATION, "WREPL_STOP_ASSOCIATION"},
127 {WREPL_REPLICATION, "WREPL_REPLICATION"},
128 {0, NULL}
129 };
130
131 #define WREPL_NAME_TYPE_MASK 0x03
132
133 #define WREPL_NAME_TYPE_UNIQUE 0x00
134 #define WREPL_NAME_TYPE_NORMAL_GROUP 0x01
135 #define WREPL_NAME_TYPE_SPECIAL_GROUP 0x02
136 #define WREPL_NAME_TYPE_MULTIHOMED 0x03
137
138 static const value_string rectype_vals[] = {
139 {WREPL_NAME_TYPE_UNIQUE, "Unique"},
140 {WREPL_NAME_TYPE_NORMAL_GROUP, "Normal group"},
141 {WREPL_NAME_TYPE_SPECIAL_GROUP, "Special group"},
142 {WREPL_NAME_TYPE_MULTIHOMED, "Multihomed"},
143 {0, NULL}
144 };
145
146 static const value_string recstate_vals[] = {
147 {0x00, "Active"},
148 {0x01, "Released"},
149 {0x02, "Tombstoned"},
150 {0x03, "Deleted"},
151 {0, NULL}
152 };
153
154 static const value_string hosttype_vals[] = {
155 {0x00, "B-node"},
156 {0x01, "P-node"},
157 {0x02, "M-node"},
158 {0x03, "H-node"},
159 {0, NULL}
160 };
161
162 static int
dissect_winsrepl_start(tvbuff_t * winsrepl_tvb,_U_ packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)163 dissect_winsrepl_start(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
164 int winsrepl_offset, proto_tree *winsrepl_tree)
165 {
166 proto_tree *start_tree;
167
168 start_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
169 ett_winsrepl_start, NULL, "WREPL_START_ASSOCIATION");
170
171 /* ASSOC_CTX */
172 proto_tree_add_item(start_tree, hf_winsrepl_assoc_ctx, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
173 winsrepl_offset += 4;
174
175 /* MINOR VERSION */
176 proto_tree_add_item(start_tree, hf_winsrepl_start_minor_version, winsrepl_tvb, winsrepl_offset, 2, ENC_BIG_ENDIAN);
177 winsrepl_offset += 2;
178
179 /* MAJOR VERSION */
180 proto_tree_add_item(start_tree, hf_winsrepl_start_major_version, winsrepl_tvb, winsrepl_offset, 2, ENC_BIG_ENDIAN);
181 winsrepl_offset += 2;
182
183 return winsrepl_offset;
184 }
185
186 static int
dissect_winsrepl_stop(tvbuff_t * winsrepl_tvb,_U_ packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)187 dissect_winsrepl_stop(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
188 int winsrepl_offset, proto_tree *winsrepl_tree)
189 {
190 guint32 reason;
191 proto_item *stop_item;
192 proto_tree *stop_tree;
193
194 stop_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
195 ett_winsrepl_stop, &stop_item, "WREPL_STOP_ASSOCIATION");
196
197 /* REASON */
198 reason = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
199 proto_tree_add_uint(stop_tree, hf_winsrepl_stop_reason, winsrepl_tvb, winsrepl_offset, 4, reason);
200 winsrepl_offset += 4;
201
202 proto_item_append_text(stop_item, ", Reason: 0x%08X", reason);
203
204 return winsrepl_offset;
205 }
206
207 static int
dissect_winsrepl_table_query(tvbuff_t * winsrepl_tvb _U_,packet_info * pinfo _U_,int winsrepl_offset,proto_tree * winsrepl_tree _U_)208 dissect_winsrepl_table_query(tvbuff_t *winsrepl_tvb _U_, packet_info *pinfo _U_,
209 int winsrepl_offset, proto_tree *winsrepl_tree _U_)
210 {
211 /* Nothing to do here */
212 return winsrepl_offset;
213 }
214
215 static int
dissect_winsrepl_wins_owner(tvbuff_t * winsrepl_tvb,_U_ packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree,proto_tree * sub_tree,guint32 idx)216 dissect_winsrepl_wins_owner(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
217 int winsrepl_offset, proto_tree *winsrepl_tree,
218 proto_tree *sub_tree, guint32 idx)
219 {
220 proto_tree *owner_tree = NULL;
221
222 if (sub_tree) {
223 owner_tree = proto_tree_add_subtree_format(sub_tree, winsrepl_tvb, winsrepl_offset, 24,
224 ett_winsrepl_owner, NULL, "WINS Owner [%u]", idx);
225 } else if (winsrepl_tree) {
226 owner_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 24,
227 ett_winsrepl_owner, NULL, "WINS Owner");
228 }
229
230 /* ADDRESS */
231 proto_tree_add_item(owner_tree, hf_winsrepl_owner_address, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
232 winsrepl_offset += 4;
233
234 /* MAX_VERSION */
235 proto_tree_add_item(owner_tree, hf_winsrepl_owner_max_version, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
236 winsrepl_offset += 8;
237
238 /* MIN_VERSION */
239 proto_tree_add_item(owner_tree, hf_winsrepl_owner_min_version, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
240 winsrepl_offset += 8;
241
242 /* TYPE */
243 proto_tree_add_item(owner_tree, hf_winsrepl_owner_type, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
244 winsrepl_offset += 4;
245
246 return winsrepl_offset;
247 }
248
249 static int
dissect_winsrepl_table_reply(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)250 dissect_winsrepl_table_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
251 int winsrepl_offset, proto_tree *winsrepl_tree)
252 {
253 proto_tree *table_tree;
254 guint32 partner_count;
255 guint32 i;
256
257 table_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
258 ett_winsrepl_table_reply, NULL, "WREPL_REPL_TABLE_REPLY");
259
260 /* PARTNER COUNT */
261 partner_count = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
262 proto_tree_add_uint(table_tree, hf_winsrepl_table_partner_count, winsrepl_tvb, winsrepl_offset, 4, partner_count);
263 winsrepl_offset += 4;
264
265 for (i=0; i < partner_count; i++) {
266 winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
267 winsrepl_offset, table_tree,
268 table_tree, i);
269 }
270
271 /* INITIATOR */
272 proto_tree_add_item(table_tree, hf_winsrepl_table_initiator, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
273 winsrepl_offset += 4;
274
275 return winsrepl_offset;
276 }
277
278 static int
dissect_winsrepl_send_request(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)279 dissect_winsrepl_send_request(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
280 int winsrepl_offset, proto_tree *winsrepl_tree)
281 {
282 winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
283 winsrepl_offset, winsrepl_tree,
284 NULL, 0);
285
286 return winsrepl_offset;
287 }
288
289 static int
dissect_winsrepl_wins_ip(tvbuff_t * winsrepl_tvb,_U_ packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree,guint32 * addr,proto_tree * sub_tree,guint32 idx)290 dissect_winsrepl_wins_ip(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
291 int winsrepl_offset, proto_tree *winsrepl_tree,
292 guint32 *addr, proto_tree *sub_tree, guint32 idx)
293 {
294 proto_item *ip_item = NULL;
295 proto_tree *ip_tree = NULL;
296
297 if (sub_tree) {
298 ip_tree = proto_tree_add_subtree_format(sub_tree, winsrepl_tvb, winsrepl_offset, 8,
299 ett_winsrepl_ip, &ip_item, "WINS IP [%u]", idx);
300 } else if (winsrepl_tree) {
301 ip_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 8,
302 ett_winsrepl_ip, &ip_item, "WINS IP");
303 }
304
305 /* OWNER */
306 proto_tree_add_item(ip_tree, hf_winsrepl_ip_owner, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
307 winsrepl_offset += 4;
308
309 /* IP */
310 *addr = tvb_get_ipv4(winsrepl_tvb, winsrepl_offset);
311 proto_tree_add_ipv4(ip_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, *addr);
312 proto_item_append_text(ip_item, ": %s", tvb_ip_to_str(pinfo->pool, winsrepl_tvb, winsrepl_offset));
313 winsrepl_offset += 4;
314
315 return winsrepl_offset;
316 }
317
318 static int
dissect_winsrepl_wins_address_list(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree,proto_item * parent_item)319 dissect_winsrepl_wins_address_list(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
320 int winsrepl_offset, proto_tree *winsrepl_tree,
321 proto_item *parent_item)
322 {
323 proto_item *addr_list_item;
324 proto_tree *addr_list_tree;
325 int old_offset = winsrepl_offset;
326 guint32 num_ips;
327 guint32 ip;
328 guint32 i;
329 address addr;
330 gchar* addr_str;
331
332 addr_list_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
333 ett_winsrepl_addr_list, &addr_list_item, "WINS Address List");
334
335 /* NUM_IPS */
336 num_ips = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
337 proto_tree_add_uint(addr_list_tree, hf_winsrepl_addr_list_num_ips, winsrepl_tvb, winsrepl_offset, 4, num_ips);
338 winsrepl_offset += 4;
339
340 for (i=0; i < num_ips; i++) {
341 winsrepl_offset = dissect_winsrepl_wins_ip(winsrepl_tvb, pinfo,
342 winsrepl_offset, addr_list_tree,
343 &ip, addr_list_tree, i);
344 set_address(&addr, AT_IPv4, 4, &ip);
345 addr_str = address_to_str(pinfo->pool, &addr);
346 if (i == 0) {
347 proto_item_append_text(parent_item, ": %s", addr_str);
348 proto_item_append_text(addr_list_item, ": %s", addr_str);
349 } else {
350 proto_item_append_text(parent_item, ", %s", addr_str);
351 proto_item_append_text(addr_list_item, ", %s", addr_str);
352 }
353 }
354
355 proto_item_set_len(addr_list_item, winsrepl_offset - old_offset);
356
357 return winsrepl_offset;
358 }
359
360 static int
dissect_winsrepl_wins_name(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree,proto_tree * sub_tree,guint32 idx)361 dissect_winsrepl_wins_name(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
362 int winsrepl_offset, proto_tree *winsrepl_tree,
363 proto_tree *sub_tree, guint32 idx)
364 {
365 proto_item *name_item = NULL, *ti;
366 proto_tree *name_tree = NULL;
367 int old_offset = winsrepl_offset;
368 tvbuff_t *name_tvb = NULL;
369 guint32 name_len;
370 char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
371 int name_type;
372 guint32 flags;
373 static int * const name_flags[] = {
374 &hf_winsrepl_name_flags_rectype,
375 &hf_winsrepl_name_flags_recstate,
376 &hf_winsrepl_name_flags_local,
377 &hf_winsrepl_name_flags_hosttype,
378 &hf_winsrepl_name_flags_static,
379 NULL
380 };
381
382 if (sub_tree) {
383 name_tree = proto_tree_add_subtree_format(sub_tree, winsrepl_tvb, winsrepl_offset, -1,
384 ett_winsrepl_name, &name_item, "WINS Name [%u]", idx);
385 } else if (winsrepl_tree) {
386 name_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
387 ett_winsrepl_name, &name_item, "WINS Name");
388 }
389
390 /* NAME_LEN */
391 name_len = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
392 ti = proto_tree_add_uint(name_tree, hf_winsrepl_name_len, winsrepl_tvb, winsrepl_offset, 4, name_len);
393 winsrepl_offset += 4;
394 if (name_len == 0) {
395 expert_add_info(pinfo, ti, &ei_winsrepl_name_len);
396 return winsrepl_offset;
397 }
398
399 /* NAME: TODO! */
400 /*
401 * XXX - apparently, according to the Samba code for handling
402 * WINS replication, there's a bug in a lot of versions of Windows,
403 * including W2K SP2, wherein the first and last bytes of the
404 * name (the last byte being the name type) are swapped if
405 * the type is 0x1b. I think I've seen this in at least
406 * one capture.
407 */
408 name_tvb = tvb_new_subset_length(winsrepl_tvb, winsrepl_offset, name_len);
409 netbios_add_name("Name", name_tvb, 0, name_tree);
410 name_type = get_netbios_name(name_tvb, 0, name_str, (NETBIOS_NAME_LEN - 1)*4 + 1);
411 proto_item_append_text(name_item, ": %s<%02x>", name_str, name_type);
412 winsrepl_offset += name_len;
413
414 /* ALIGN to 4 Byte */
415 /* winsrepl_offset += ((winsrepl_offset & (4-1)) == 0 ? 0 : (4 - (winsrepl_offset & (4-1)))); */
416 /* Windows including w2k8 add 4 padding bytes, when it's already 4 byte
417 * aligned... This happens when the name has a "scope" part
418 */
419 winsrepl_offset += 4 - (winsrepl_offset & (4-1));
420
421 /* FLAGS */
422 /*
423 * XXX - there appear to be more flag bits, but I didn't see
424 * anything in the Samba code about them.
425 */
426 flags = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
427 proto_tree_add_bitmask(name_tree, winsrepl_tvb, winsrepl_offset, hf_winsrepl_name_flags, ett_winsrepl_flags, name_flags, ENC_BIG_ENDIAN);
428 winsrepl_offset += 4;
429
430 /* GROUP_FLAG */
431 /* XXX - is this just a Boolean? */
432 proto_tree_add_item(name_tree, hf_winsrepl_name_group_flag, winsrepl_tvb, winsrepl_offset, 4, ENC_LITTLE_ENDIAN);
433 winsrepl_offset += 4;
434
435 /* Version ID */
436 proto_tree_add_item(name_tree, hf_winsrepl_name_version_id, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
437 winsrepl_offset += 8;
438
439 switch (flags & WREPL_NAME_TYPE_MASK) {
440
441 case WREPL_NAME_TYPE_UNIQUE:
442 case WREPL_NAME_TYPE_NORMAL_GROUP:
443 /* Single address */
444 proto_tree_add_item(name_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
445 proto_item_append_text(name_item, ": %s", tvb_ip_to_str(pinfo->pool, winsrepl_tvb, winsrepl_offset));
446 winsrepl_offset += 4;
447 break;
448
449 case WREPL_NAME_TYPE_SPECIAL_GROUP:
450 case WREPL_NAME_TYPE_MULTIHOMED:
451 /* Address list */
452 winsrepl_offset = dissect_winsrepl_wins_address_list(winsrepl_tvb, pinfo,
453 winsrepl_offset, name_tree,
454 name_item);
455 break;
456 }
457
458 /* UNKNOWN, little or big endian??? */
459 proto_tree_add_item(name_tree, hf_winsrepl_name_unknown, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
460 winsrepl_offset += 4;
461
462 proto_item_set_len(name_item, winsrepl_offset - old_offset);
463
464 return winsrepl_offset;
465 }
466
467 static int
dissect_winsrepl_send_reply(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)468 dissect_winsrepl_send_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
469 int winsrepl_offset, proto_tree *winsrepl_tree)
470 {
471 proto_tree *rep_tree;
472 guint32 num_names;
473 guint32 i;
474
475 rep_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
476 ett_winsrepl_send_reply, NULL, "WREPL_REPL_SEND_REPLY");
477
478 /* NUM NAMES */
479 num_names = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
480 proto_tree_add_uint(rep_tree, hf_winsrepl_reply_num_names, winsrepl_tvb, winsrepl_offset, 4, num_names);
481 winsrepl_offset += 4;
482
483 for (i=0; i < num_names; i++) {
484 winsrepl_offset = dissect_winsrepl_wins_name(winsrepl_tvb, pinfo,
485 winsrepl_offset, rep_tree,
486 rep_tree, i);
487 }
488
489 return winsrepl_offset;
490 }
491
492 static int
dissect_winsrepl_update(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)493 dissect_winsrepl_update(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
494 int winsrepl_offset, proto_tree *winsrepl_tree)
495 {
496 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
497 winsrepl_offset, winsrepl_tree);
498 return winsrepl_offset;
499 }
500
501 static int
dissect_winsrepl_update2(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)502 dissect_winsrepl_update2(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
503 int winsrepl_offset, proto_tree *winsrepl_tree)
504 {
505 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
506 winsrepl_offset, winsrepl_tree);
507 return winsrepl_offset;
508 }
509
510 static int
dissect_winsrepl_inform(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)511 dissect_winsrepl_inform(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
512 int winsrepl_offset, proto_tree *winsrepl_tree)
513 {
514 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
515 winsrepl_offset, winsrepl_tree);
516 return winsrepl_offset;
517 }
518
519 static int
dissect_winsrepl_inform2(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_tree * winsrepl_tree)520 dissect_winsrepl_inform2(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
521 int winsrepl_offset, proto_tree *winsrepl_tree)
522 {
523 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
524 winsrepl_offset, winsrepl_tree);
525 return winsrepl_offset;
526 }
527
528 static int
dissect_winsrepl_replication(tvbuff_t * winsrepl_tvb,packet_info * pinfo,int winsrepl_offset,proto_item * winsrepl_item,proto_tree * winsrepl_tree)529 dissect_winsrepl_replication(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
530 int winsrepl_offset, proto_item *winsrepl_item, proto_tree *winsrepl_tree)
531 {
532 proto_item *repl_item;
533 proto_tree *repl_tree;
534 enum wrepl_replication_cmd command;
535
536 repl_tree = proto_tree_add_subtree(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1,
537 ett_winsrepl_replication, &repl_item, "WREPL_REPLICATION");
538
539 /* REPLICATION_CMD */
540 command = (enum wrepl_replication_cmd)tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
541 proto_tree_add_uint(repl_tree, hf_winsrepl_replication_command, winsrepl_tvb, winsrepl_offset, 4, command);
542 winsrepl_offset += 4;
543
544 switch (command) {
545 case WREPL_REPL_TABLE_QUERY:
546 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_TABLE_QUERY");
547 proto_item_append_text(winsrepl_item, ", WREPL_REPL_TABLE_QUERY");
548 proto_item_append_text(repl_item, ", WREPL_REPL_TABLE_QUERY");
549 winsrepl_offset = dissect_winsrepl_table_query(winsrepl_tvb, pinfo,
550 winsrepl_offset, repl_tree);
551 break;
552 case WREPL_REPL_TABLE_REPLY:
553 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_TABLE_REPLY");
554 proto_item_append_text(winsrepl_item, ", WREPL_REPL_TABLE_REPLY");
555 proto_item_append_text(repl_item, ", WREPL_REPL_TABLE_REPLY");
556 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
557 winsrepl_offset, repl_tree);
558 break;
559 case WREPL_REPL_SEND_REQUEST:
560 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_SEND_REQUEST");
561 proto_item_append_text(winsrepl_item, ", WREPL_REPL_SEND_REQUEST");
562 proto_item_append_text(repl_item, ", WREPL_REPL_SEND_REQUEST");
563 winsrepl_offset = dissect_winsrepl_send_request(winsrepl_tvb, pinfo,
564 winsrepl_offset, repl_tree);
565 break;
566 case WREPL_REPL_SEND_REPLY:
567 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_SEND_REPLY");
568 proto_item_append_text(winsrepl_item, ", WREPL_REPL_SEND_REPLY");
569 proto_item_append_text(repl_item, ", WREPL_REPL_SEND_REPLY");
570 winsrepl_offset = dissect_winsrepl_send_reply(winsrepl_tvb, pinfo,
571 winsrepl_offset, repl_tree);
572 break;
573 case WREPL_REPL_UPDATE:
574 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_UPDATE");
575 proto_item_append_text(winsrepl_item, ", WREPL_REPL_UPDATE");
576 proto_item_append_text(repl_item, ", WREPL_REPL_UPDATE");
577 winsrepl_offset = dissect_winsrepl_update(winsrepl_tvb, pinfo,
578 winsrepl_offset, repl_tree);
579 break;
580 case WREPL_REPL_UPDATE2:
581 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_UPDATE2");
582 proto_item_append_text(winsrepl_item, ",WREPL_REPL_UPDATE2");
583 proto_item_append_text(repl_item, ",WREPL_REPL_UPDATE2");
584 winsrepl_offset = dissect_winsrepl_update2(winsrepl_tvb, pinfo,
585 winsrepl_offset, repl_tree);
586 break;
587 case WREPL_REPL_INFORM:
588 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_INFORM");
589 proto_item_append_text(winsrepl_item, ", WREPL_REPL_INFORM");
590 proto_item_append_text(repl_item, ", WREPL_REPL_INFORM");
591 winsrepl_offset = dissect_winsrepl_inform(winsrepl_tvb, pinfo,
592 winsrepl_offset, repl_tree);
593 break;
594 case WREPL_REPL_INFORM2:
595 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_INFORM2");
596 proto_item_append_text(winsrepl_item, ", WREPL_REPL_INFORM2");
597 proto_item_append_text(repl_item, ", WREPL_REPL_INFORM2");
598 winsrepl_offset = dissect_winsrepl_inform2(winsrepl_tvb, pinfo,
599 winsrepl_offset, repl_tree);
600 break;
601 }
602
603 return winsrepl_offset;
604 }
605
606 static int
dissect_winsrepl_pdu(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data _U_)607 dissect_winsrepl_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
608 {
609 int offset = 0;
610 proto_item *winsrepl_item;
611 proto_tree *winsrepl_tree;
612 enum wrepl_mess_type mess_type;
613
614 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WINS-Replication");
615 col_clear(pinfo->cinfo, COL_INFO);
616
617 winsrepl_item = proto_tree_add_item(parent_tree, proto_winsrepl, tvb, offset, -1, ENC_NA);
618 winsrepl_tree = proto_item_add_subtree(winsrepl_item, ett_winsrepl);
619
620 /* SIZE */
621 proto_tree_add_item(winsrepl_tree, hf_winsrepl_size, tvb, offset, 4, ENC_BIG_ENDIAN);
622 offset += 4;
623
624 /* OPCODE */
625 proto_tree_add_item(winsrepl_tree, hf_winsrepl_opcode, tvb, offset, 4, ENC_BIG_ENDIAN);
626 offset += 4;
627
628 /* ASSOC_CTX */
629 proto_tree_add_item(winsrepl_tree, hf_winsrepl_assoc_ctx, tvb, offset, 4, ENC_BIG_ENDIAN);
630 offset += 4;
631
632 /* MESSAGE_TYPE */
633 mess_type = (enum wrepl_mess_type)tvb_get_ntohl(tvb, offset);
634 proto_tree_add_uint(winsrepl_tree, hf_winsrepl_mess_type, tvb, offset, 4, mess_type);
635 offset += 4;
636
637 switch (mess_type) {
638 case WREPL_START_ASSOCIATION:
639 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_START_ASSOCIATION");
640 proto_item_append_text(winsrepl_item, ", WREPL_START_ASSOCIATION");
641 dissect_winsrepl_start(tvb, pinfo,
642 offset, winsrepl_tree);
643 break;
644 case WREPL_START_ASSOCIATION_REPLY:
645 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_START_ASSOCIATION_REPLY");
646 proto_item_append_text(winsrepl_item, ", WREPL_START_ASSOCIATION_REPLY");
647 dissect_winsrepl_start(tvb, pinfo,
648 offset, winsrepl_tree);
649 break;
650 case WREPL_STOP_ASSOCIATION:
651 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_STOP_ASSOCIATION");
652 proto_item_append_text(winsrepl_item, ", WREPL_STOP_ASSOCIATION");
653 dissect_winsrepl_stop(tvb, pinfo,
654 offset, winsrepl_tree);
655 break;
656 case WREPL_REPLICATION:
657 dissect_winsrepl_replication(tvb, pinfo,
658 offset, winsrepl_item, winsrepl_tree);
659 break;
660 }
661
662 return tvb_captured_length(tvb);
663 }
664
665 static guint
get_winsrepl_pdu_len(packet_info * pinfo _U_,tvbuff_t * tvb,int offset,void * data _U_)666 get_winsrepl_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
667 int offset, void *data _U_)
668 {
669 guint pdu_len;
670
671 pdu_len=tvb_get_ntohl(tvb, offset);
672 return pdu_len+4;
673 }
674
675 static int
dissect_winsrepl(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data)676 dissect_winsrepl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
677 {
678 tcp_dissect_pdus(tvb, pinfo, parent_tree, winsrepl_reassemble, 4, get_winsrepl_pdu_len, dissect_winsrepl_pdu, data);
679 return tvb_captured_length(tvb);
680 }
681
682 void
proto_register_winsrepl(void)683 proto_register_winsrepl(void)
684 {
685 static hf_register_info hf[] = {
686 { &hf_winsrepl_size, {
687 "Packet Size", "winsrepl.size",
688 FT_UINT32, BASE_DEC, NULL, 0x0,
689 "WINS Replication Packet Size", HFILL }},
690
691 { &hf_winsrepl_opcode, {
692 "Opcode", "winsrepl.opcode",
693 FT_UINT32, BASE_HEX, NULL, 0x0,
694 "WINS Replication Opcode", HFILL }},
695
696 { &hf_winsrepl_assoc_ctx, {
697 "Assoc_Ctx", "winsrepl.assoc_ctx",
698 FT_UINT32, BASE_HEX, NULL, 0x0,
699 "WINS Replication Assoc_Ctx", HFILL }},
700
701 { &hf_winsrepl_mess_type, {
702 "Message_Type", "winsrepl.message_type",
703 FT_UINT32, BASE_DEC, VALS(message_type_vals), 0x0,
704 "WINS Replication Message_Type", HFILL }},
705
706 { &hf_winsrepl_start_minor_version, {
707 "Minor Version", "winsrepl.minor_version",
708 FT_UINT16, BASE_DEC, NULL, 0x0,
709 "WINS Replication Minor Version", HFILL }},
710
711 { &hf_winsrepl_start_major_version, {
712 "Major Version", "winsrepl.major_version",
713 FT_UINT16, BASE_DEC, NULL, 0x0,
714 "WINS Replication Major Version", HFILL }},
715
716 { &hf_winsrepl_stop_reason, {
717 "Reason", "winsrepl.reason",
718 FT_UINT32, BASE_HEX, NULL, 0x0,
719 "WINS Replication Reason", HFILL }},
720
721 { &hf_winsrepl_replication_command, {
722 "Replication Command", "winsrepl.repl_cmd",
723 FT_UINT32, BASE_HEX, VALS(replication_cmd_vals), 0x0,
724 "WINS Replication Command", HFILL }},
725
726 { &hf_winsrepl_owner_address, {
727 "Owner Address", "winsrepl.owner_address",
728 FT_IPv4, BASE_NONE, NULL, 0x0,
729 "WINS Replication Owner Address", HFILL }},
730
731 { &hf_winsrepl_owner_max_version, {
732 "Max Version", "winsrepl.max_version",
733 FT_UINT64, BASE_DEC, NULL, 0x0,
734 "WINS Replication Max Version", HFILL }},
735
736 { &hf_winsrepl_owner_min_version, {
737 "Min Version", "winsrepl.min_version",
738 FT_UINT64, BASE_DEC, NULL, 0x0,
739 "WINS Replication Min Version", HFILL }},
740
741 { &hf_winsrepl_owner_type, {
742 "Owner Type", "winsrepl.owner_type",
743 FT_UINT32, BASE_DEC, NULL, 0x0,
744 "WINS Replication Owner Type", HFILL }},
745
746 { &hf_winsrepl_table_partner_count, {
747 "Partner Count", "winsrepl.partner_count",
748 FT_UINT32, BASE_DEC, NULL, 0x0,
749 "WINS Replication Partner Count", HFILL }},
750
751 { &hf_winsrepl_table_initiator, {
752 "Initiator", "winsrepl.initiator",
753 FT_IPv4, BASE_NONE, NULL, 0x0,
754 "WINS Replication Initiator", HFILL }},
755
756 { &hf_winsrepl_ip_owner, {
757 "IP Owner", "winsrepl.ip_owner",
758 FT_IPv4, BASE_NONE, NULL, 0x0,
759 "WINS Replication IP Owner", HFILL }},
760
761 { &hf_winsrepl_ip_ip, {
762 "IP Address", "winsrepl.ip_address",
763 FT_IPv4, BASE_NONE, NULL, 0x0,
764 "WINS Replication IP Address", HFILL }},
765
766 { &hf_winsrepl_addr_list_num_ips, {
767 "Num IPs", "winsrepl.num_ips",
768 FT_UINT32, BASE_DEC, NULL, 0x0,
769 "WINS Replication Num IPs", HFILL }},
770
771 { &hf_winsrepl_name_len, {
772 "Name Len", "winsrepl.name_len",
773 FT_UINT32, BASE_DEC, NULL, 0x0,
774 "WINS Replication Name Len", HFILL }},
775
776 { &hf_winsrepl_name_flags, {
777 "Name Flags", "winsrepl.name_flags",
778 FT_UINT32, BASE_HEX, NULL, 0x0,
779 "WINS Replication Name Flags", HFILL }},
780
781 { &hf_winsrepl_name_flags_rectype, {
782 "Record Type", "winsrepl.name_flags.rectype",
783 FT_UINT32, BASE_HEX, VALS(rectype_vals), 0x00000003,
784 "WINS Replication Name Flags Record Type", HFILL }},
785
786 { &hf_winsrepl_name_flags_recstate, {
787 "Record State", "winsrepl.name_flags.recstate",
788 FT_UINT32, BASE_HEX, VALS(recstate_vals), 0x0000000C,
789 "WINS Replication Name Flags Record State", HFILL }},
790
791 { &hf_winsrepl_name_flags_local, {
792 "Local", "winsrepl.name_flags.local",
793 FT_BOOLEAN, 32, NULL, 0x00000010,
794 "WINS Replication Name Flags Local Flag", HFILL }},
795
796 { &hf_winsrepl_name_flags_hosttype, {
797 "Host Type", "winsrepl.name_flags.hosttype",
798 FT_UINT32, BASE_HEX, VALS(hosttype_vals), 0x00000060,
799 "WINS Replication Name Flags Host Type", HFILL }},
800
801 { &hf_winsrepl_name_flags_static, {
802 "Static", "winsrepl.name_flags.static",
803 FT_BOOLEAN, 32, NULL, 0x00000080,
804 "WINS Replication Name Flags Static Flag", HFILL }},
805
806 { &hf_winsrepl_name_group_flag, {
807 "Name Group Flag", "winsrepl.name_group_flag",
808 FT_UINT32, BASE_HEX, NULL, 0x0,
809 "WINS Replication Name Group Flag", HFILL }},
810
811 { &hf_winsrepl_name_version_id, {
812 "Name Version Id", "winsrepl.name_version_id",
813 FT_UINT64, BASE_DEC, NULL, 0x0,
814 "WINS Replication Name Version Id", HFILL }},
815
816 { &hf_winsrepl_name_unknown, {
817 "Unknown IP", "winsrepl.unknown",
818 FT_IPv4, BASE_NONE, NULL, 0x0,
819 "WINS Replication Unknown IP", HFILL }},
820
821 { &hf_winsrepl_reply_num_names, {
822 "Num Names", "winsrepl.num_names",
823 FT_UINT32, BASE_DEC, NULL, 0x0,
824 "WINS Replication Num Names", HFILL }},
825 };
826
827 static gint *ett[] = {
828 &ett_winsrepl,
829 &ett_winsrepl_start,
830 &ett_winsrepl_stop,
831 &ett_winsrepl_replication,
832 &ett_winsrepl_owner,
833 &ett_winsrepl_table_reply,
834 &ett_winsrepl_ip,
835 &ett_winsrepl_addr_list,
836 &ett_winsrepl_name,
837 &ett_winsrepl_send_reply,
838 &ett_winsrepl_flags,
839 };
840
841 static ei_register_info ei[] = {
842 { &ei_winsrepl_name_len, { "winsrepl.name_len.invalid", PI_MALFORMED, PI_ERROR, "Bad name length", EXPFILL }},
843 };
844
845 module_t *winsrepl_module;
846 expert_module_t* expert_winsrepl;
847
848 proto_winsrepl = proto_register_protocol("WINS (Windows Internet Name Service) Replication",
849 "WINS-Replication", "winsrepl");
850 proto_register_subtree_array(ett, array_length(ett));
851 proto_register_field_array(proto_winsrepl, hf, array_length(hf));
852 expert_winsrepl = expert_register_protocol(proto_winsrepl);
853 expert_register_field_array(expert_winsrepl, ei, array_length(ei));
854
855 winsrepl_module = prefs_register_protocol(proto_winsrepl, NULL);
856 prefs_register_bool_preference(winsrepl_module, "reassemble",
857 "Reassemble WINS-Replication messages spanning multiple TCP segments",
858 "Whether the WINS-Replication dissector should reassemble messages spanning multiple TCP segments."
859 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
860 &winsrepl_reassemble);
861 }
862
863 void
proto_reg_handoff_winsrepl(void)864 proto_reg_handoff_winsrepl(void)
865 {
866 dissector_handle_t winsrepl_handle;
867
868 winsrepl_handle = create_dissector_handle(dissect_winsrepl, proto_winsrepl);
869 dissector_add_uint_with_preference("tcp.port", WINS_REPLICATION_PORT, winsrepl_handle);
870 }
871
872 /*
873 * Editor modelines - https://www.wireshark.org/tools/modelines.html
874 *
875 * Local variables:
876 * c-basic-offset: 8
877 * tab-width: 8
878 * indent-tabs-mode: t
879 * End:
880 *
881 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
882 * :indentSize=8:tabSize=8:noTabs=false:
883 */
884