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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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