2 * Routines for MS NLB dissection
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
14 #include <epan/etypes.h>
15 #include <epan/to_str.h>
17 #include <wsutil/array.h>
18 #include "packet-smb-common.h"
20 void proto_register_msnlb(void);
21 void proto_reg_handoff_msnlb(void);
23 static dissector_handle_t msnlb_handle
;
25 /* Initialize the protocol and registered fields */
26 static int proto_msnlb
;
28 static int hf_msnlb_signature
;
29 static int hf_msnlb_version
;
30 static int hf_msnlb_uniquehostid
;
31 static int hf_msnlb_clusterip
;
32 static int hf_msnlb_dedicatedip
;
33 static int hf_msnlb_signature_data
;
35 static int hf_msnlb_myhostid
;
36 static int hf_msnlb_defaulthostid
;
37 static int hf_msnlb_convergencestate
;
38 static int hf_msnlb_numberofportrules
;
39 static int hf_msnlb_uniquehostcode
;
40 static int hf_msnlb_packetshandled
;
41 static int hf_msnlb_teamingcfg
;
42 static int hf_msnlb_teamingcfg_reserved
;
43 static int hf_msnlb_teamingcfg_xorclusterip
;
44 static int hf_msnlb_teamingcfg_numberofparticipants
;
45 static int hf_msnlb_teamingcfg_hashing
;
46 static int hf_msnlb_teamingcfg_master
;
47 static int hf_msnlb_teamingcfg_active
;
48 static int hf_msnlb_reserved
;
49 static int hf_msnlb_portruleconfiguration
;
50 static int hf_msnlb_portruleconfiguration_data
;
51 static int hf_msnlb_currentmap
;
52 static int hf_msnlb_currentmap_data
;
53 static int hf_msnlb_newmap
;
54 static int hf_msnlb_newmap_data
;
55 static int hf_msnlb_idlemap
;
56 static int hf_msnlb_idlemap_data
;
57 static int hf_msnlb_readymap
;
58 static int hf_msnlb_readymap_data
;
59 static int hf_msnlb_loadweights
;
60 static int hf_msnlb_loadweights_data
;
61 static int hf_msnlb_reserved2
;
62 static int hf_msnlb_reserved2_data
;
64 static int hf_msnlb_extended_hb
;
65 static int hf_msnlb_extended_hb_type
;
66 static int hf_msnlb_length
;
67 static int hf_msnlb_address_family
;
68 static int hf_msnlb_host_name
;
69 static int hf_msnlb_host_ipv4
;
70 static int hf_msnlb_host_ipv6
;
71 static int hf_msnlb_host_unknown
;
72 static int hf_msnlb_padding
;
73 static int hf_msnlb_extended_hb_unknown
;
76 static int ett_msnlb_signature
;
77 static int ett_msnlb_teamingcfg
;
78 static int ett_msnlb_portruleconfiguration
;
79 static int ett_msnlb_currentmap
;
80 static int ett_msnlb_newmap
;
81 static int ett_msnlb_idlemap
;
82 static int ett_msnlb_readymap
;
83 static int ett_msnlb_loadweights
;
84 static int ett_msnlb_reserved
;
85 static int ett_msnlb_extended_hb
;
87 #define NLB_CLUSTER_MEMBERSHIP_HB 0xC0DE01BF
88 #define NLB_EXTENDED_HB 0xC0DE01C0
89 #define NLB_RELIABLE_PROTOCOL 0xC0DE01DE
91 static const value_string nlb_signature_vals
[] = {
92 { NLB_CLUSTER_MEMBERSHIP_HB
, "NLB Cluster Membership HeartBeat" },
93 { NLB_EXTENDED_HB
, "NLB Extended HeartBeat" },
94 { NLB_RELIABLE_PROTOCOL
, "NLB Reliable Protocol" },
98 static const value_string nlb_extended_hb_type_vals
[] = {
104 static const value_string nlb_address_family_vals
[] = {
110 static true_false_string tfs_reverse_normal
= { "Reverse", "Normal" };
113 version_base_custom(char *result
, uint32_t version
)
115 snprintf(result
, ITEM_LABEL_LENGTH
, "%d.%d", (version
>> 8) & 0xFF, (version
& 0xFF));
119 dissect_msnlb(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
122 proto_tree
*msnlb_tree
= NULL
, *msnlb_subtree
;
126 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MS NLB");
128 col_set_str(pinfo
->cinfo
, COL_INFO
, "MS NLB heartbeat");
131 ti
= proto_tree_add_item(tree
, proto_msnlb
, tvb
, 0, -1, ENC_NA
);
132 msnlb_tree
= proto_item_add_subtree(ti
, ett_msnlb
);
135 proto_tree_add_item(msnlb_tree
, hf_msnlb_signature
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
136 signature
= tvb_get_letohl(tvb
, offset
);
139 proto_tree_add_item(msnlb_tree
, hf_msnlb_version
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
142 proto_tree_add_item(msnlb_tree
, hf_msnlb_uniquehostid
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
145 proto_tree_add_item(msnlb_tree
, hf_msnlb_clusterip
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
148 proto_tree_add_item(msnlb_tree
, hf_msnlb_dedicatedip
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
151 ti
= proto_tree_add_item(msnlb_tree
, hf_msnlb_signature_data
, tvb
, offset
, -1, ENC_NA
);
152 proto_item_append_text(ti
, " - %s", val_to_str(signature
, nlb_signature_vals
, "Unknown (%u)"));
153 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " - %s", val_to_str(signature
, nlb_signature_vals
, "Unknown (%u)"));
154 msnlb_subtree
= proto_item_add_subtree(ti
, ett_msnlb_signature
);
157 case NLB_CLUSTER_MEMBERSHIP_HB
:{
159 proto_tree
*teamingcfg_tree
, *subtree
;
161 proto_tree_add_item(msnlb_subtree
, hf_msnlb_myhostid
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
164 proto_tree_add_item(msnlb_subtree
, hf_msnlb_defaulthostid
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
167 proto_tree_add_item(msnlb_subtree
, hf_msnlb_convergencestate
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
170 proto_tree_add_item(msnlb_subtree
, hf_msnlb_numberofportrules
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
173 proto_tree_add_item(msnlb_subtree
, hf_msnlb_uniquehostcode
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
176 proto_tree_add_item(msnlb_subtree
, hf_msnlb_packetshandled
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
179 /* Teaming configuration/state code, which is of the form:
181 -------------------------------------
182 |XXXXXXXX|PPPPPPPP|PPPPPPPP|NNNNNHMA|
183 -------------------------------------
186 P: XOR of the least significant 16 bits of each participant's cluster IP address
187 N: Number of participants
188 H: Hashing (Reverse=1, Normal=0)
189 M: Master (Yes=1, No=0)
190 A: Teaming active (Yes=1, No=0)
193 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_teamingcfg
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
194 teamingcfg_tree
= proto_item_add_subtree(ti
, ett_msnlb_teamingcfg
);
195 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_reserved
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
196 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_xorclusterip
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
197 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_numberofparticipants
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
198 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_hashing
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
199 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_master
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
200 proto_tree_add_item(teamingcfg_tree
, hf_msnlb_teamingcfg_active
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
203 proto_tree_add_item(msnlb_subtree
, hf_msnlb_reserved
, tvb
, offset
, 4, ENC_NA
);
206 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_portruleconfiguration
, tvb
, offset
, 4*33, ENC_NA
);
207 subtree
= proto_item_add_subtree(ti
, ett_msnlb_portruleconfiguration
);
208 for(i
= 1; i
<= 33; i
++){
209 proto_tree_add_item(subtree
, hf_msnlb_portruleconfiguration_data
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
213 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_currentmap
, tvb
, offset
, 8*33, ENC_NA
);
214 subtree
= proto_item_add_subtree(ti
, ett_msnlb_currentmap
);
215 for(i
= 1; i
<= 33; i
++){
216 proto_tree_add_item(subtree
, hf_msnlb_currentmap_data
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
220 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_newmap
, tvb
, offset
, 8*33, ENC_NA
);
221 subtree
= proto_item_add_subtree(ti
, ett_msnlb_newmap
);
222 for(i
= 1; i
<= 33; i
++){
223 proto_tree_add_item(subtree
, hf_msnlb_newmap_data
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
227 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_idlemap
, tvb
, offset
, 8*33, ENC_NA
);
228 subtree
= proto_item_add_subtree(ti
, ett_msnlb_idlemap
);
229 for(i
= 1; i
<= 33; i
++){
230 proto_tree_add_item(subtree
, hf_msnlb_idlemap_data
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
234 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_readymap
, tvb
, offset
, 8*33, ENC_NA
);
235 subtree
= proto_item_add_subtree(ti
, ett_msnlb_readymap
);
236 for(i
= 1; i
<= 33; i
++){
237 proto_tree_add_item(subtree
, hf_msnlb_readymap_data
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
241 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_loadweights
, tvb
, offset
, 4*33, ENC_NA
);
242 subtree
= proto_item_add_subtree(ti
, ett_msnlb_loadweights
);
243 for(i
= 1; i
<= 33; i
++){
244 proto_tree_add_item(subtree
, hf_msnlb_loadweights_data
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
248 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_reserved2
, tvb
, offset
, 4*33, ENC_NA
);
249 subtree
= proto_item_add_subtree(ti
, ett_msnlb_reserved
);
250 for(i
= 1; i
<= 33; i
++){
251 proto_tree_add_item(subtree
, hf_msnlb_reserved2_data
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
256 case NLB_EXTENDED_HB
:{
259 while (tvb_reported_length_remaining(tvb
, offset
) > 0) {
260 ti
= proto_tree_add_item(msnlb_subtree
, hf_msnlb_extended_hb
, tvb
, offset
, -1, ENC_NA
);
261 hb_tree
= proto_item_add_subtree(ti
, ett_msnlb_extended_hb
);
263 proto_tree_add_item(hb_tree
, hf_msnlb_extended_hb_type
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
264 hb_type
= tvb_get_uint8(tvb
, offset
);
265 proto_item_append_text(ti
, " - %s", val_to_str(hb_type
, nlb_extended_hb_type_vals
, "Unknown (%u)"));
271 proto_tree_add_item(hb_tree
, hf_msnlb_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
273 proto_tree_add_item(hb_tree
, hf_msnlb_reserved
, tvb
, offset
, 2, ENC_NA
);
275 proto_tree_add_item(hb_tree
, hf_msnlb_reserved
, tvb
, offset
, 4, ENC_NA
);
277 offset
= display_unicode_string(tvb
, pinfo
, hb_tree
, offset
, hf_msnlb_host_name
, &fqdn
);
279 proto_item_append_text(ti
, ": %s", fqdn
);
283 uint16_t address_family
;
284 proto_tree_add_item(hb_tree
, hf_msnlb_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
286 proto_tree_add_item(hb_tree
, hf_msnlb_reserved
, tvb
, offset
, 2, ENC_NA
);
288 proto_tree_add_item(hb_tree
, hf_msnlb_reserved
, tvb
, offset
, 4, ENC_NA
);
290 proto_tree_add_item(hb_tree
, hf_msnlb_address_family
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
291 address_family
= tvb_get_letohs(tvb
, offset
);
293 switch(address_family
){
295 proto_tree_add_item(hb_tree
, hf_msnlb_host_ipv4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
296 proto_item_append_text(ti
, ": %s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
299 case 0x17: /* IPv6 */
300 proto_tree_add_item(hb_tree
, hf_msnlb_host_ipv6
, tvb
, offset
, 16, ENC_NA
);
301 proto_item_append_text(ti
, ": %s", tvb_ip6_to_str(pinfo
->pool
, tvb
, offset
));
304 default: /* Unknown */
305 proto_tree_add_item(hb_tree
, hf_msnlb_host_unknown
, tvb
, offset
, -1, ENC_NA
);
306 offset
+= tvb_reported_length_remaining(tvb
, offset
);
309 proto_tree_add_item(hb_tree
, hf_msnlb_padding
, tvb
, offset
, -1, ENC_NA
);
310 offset
+= tvb_reported_length_remaining(tvb
, offset
);
313 default: /* default ?! */
314 proto_tree_add_item(hb_tree
, hf_msnlb_extended_hb_unknown
, tvb
, offset
, -1, ENC_NA
);
315 offset
+= tvb_reported_length_remaining(tvb
, offset
);
328 return tvb_captured_length(tvb
);
332 proto_register_msnlb(void)
334 static hf_register_info hf
[] = {
335 { &hf_msnlb_signature
,
336 { "Signature", "msnlb.signature",
338 VALS(nlb_signature_vals
), 0,
342 { "Version", "msnlb.version",
343 FT_UINT32
, BASE_CUSTOM
,
344 CF_FUNC(version_base_custom
), 0,
347 { &hf_msnlb_uniquehostid
,
348 { "Unique Host ID", "msnlb.unique_host_id",
353 { &hf_msnlb_clusterip
,
354 { "Cluster IP", "msnlb.cluster_ip",
359 { &hf_msnlb_dedicatedip
,
360 { "Host IP", "msnlb.host_ip",
365 { &hf_msnlb_signature_data
,
366 { "Signature Data", "msnlb.signature_data",
371 { &hf_msnlb_myhostid
,
372 { "My Host id", "msnlb.my_host_ip",
377 { &hf_msnlb_defaulthostid
,
378 { "Default Host id", "msnlb.default_host_ip",
383 { &hf_msnlb_convergencestate
,
384 { "Convergence State", "msnlb.convergence_state",
389 { &hf_msnlb_numberofportrules
,
390 { "Number of Port Rules", "msnlb.number_of_port_rules",
395 { &hf_msnlb_uniquehostcode
,
396 { "Unique Host Code", "msnlb.unique_host_code",
401 { &hf_msnlb_packetshandled
,
402 { "Packets Handled", "msnlb.packets_handled",
407 { &hf_msnlb_teamingcfg
,
408 { "Teaming Configuration", "msnlb.teamincfg",
413 { &hf_msnlb_teamingcfg_reserved
,
414 { "Reserved", "msnlb.teamincfg.reserved",
417 "Must be zero", HFILL
}
419 { &hf_msnlb_teamingcfg_xorclusterip
,
420 { "XOR of the least significant 16 bits of each participant's cluster IP address", "msnlb.teamingcfg.xorclusterip",
425 { &hf_msnlb_teamingcfg_numberofparticipants
,
426 { "Number of Participants", "msnlb.teamingcfg.number_of_participants",
431 { &hf_msnlb_teamingcfg_hashing
,
432 { "Hashing", "msnlb.teamingcfg.hashing",
434 TFS(&tfs_reverse_normal
), 0x00000004,
437 { &hf_msnlb_teamingcfg_master
,
438 { "Master", "msnlb.teamingcfg.master",
443 { &hf_msnlb_teamingcfg_active
,
444 { "Active", "msnlb.teamingcfg.active",
449 { &hf_msnlb_reserved
,
450 { "Reserved", "msnlb.reserved",
455 { &hf_msnlb_portruleconfiguration
,
456 { "Port Rule Configuration", "msnlb.portruleconfiguration",
461 { &hf_msnlb_portruleconfiguration_data
,
462 { "Port Rule Configuration Data", "msnlb.portruleconfiguration.data",
463 FT_UINT32
, BASE_DEC_HEX
,
467 { &hf_msnlb_currentmap
,
468 { "Current Map", "msnlb.currentmap",
473 { &hf_msnlb_currentmap_data
,
474 { "Current Map Data", "msnlb.currentmap.data",
475 FT_UINT64
, BASE_DEC_HEX
,
480 { "New Map", "msnlb.newmap",
485 { &hf_msnlb_newmap_data
,
486 { "New Map Data", "msnlb.newmap.data",
487 FT_UINT64
, BASE_DEC_HEX
,
492 { "Idle Map", "msnlb.idlemap",
497 { &hf_msnlb_idlemap_data
,
498 { "Idle Map Data", "msnlb.idlemap.data",
499 FT_UINT64
, BASE_DEC_HEX
,
503 { &hf_msnlb_readymap
,
504 { "Ready Map", "msnlb.readymap",
509 { &hf_msnlb_readymap_data
,
510 { "Ready Map Data", "msnlb.readymap.data",
511 FT_UINT64
, BASE_DEC_HEX
,
515 { &hf_msnlb_loadweights
,
516 { "Load Weights", "msnlb.loadweights",
521 { &hf_msnlb_loadweights_data
,
522 { "Load Weights Data", "msnlb.loadweights.data",
523 FT_UINT32
, BASE_DEC_HEX
,
527 { &hf_msnlb_reserved2
,
528 { "Reserved", "msnlb.reserved2",
533 { &hf_msnlb_reserved2_data
,
534 { "Reserved Data", "msnlb.reserved2.data",
535 FT_UINT32
, BASE_DEC_HEX
,
540 { &hf_msnlb_extended_hb
,
541 { "Extended HB", "msnlb.extended_hb",
547 { &hf_msnlb_extended_hb_type
,
548 { "Type", "msnlb.extended_hb.type",
550 VALS(nlb_extended_hb_type_vals
), 0,
554 { "Length", "msnlb.length",
559 { &hf_msnlb_address_family
,
560 { "Address Family", "msnlb.address_family",
561 FT_UINT16
, BASE_HEX_DEC
,
562 VALS(nlb_address_family_vals
), 0,
565 { &hf_msnlb_host_name
,
566 { "Host name", "msnlb.host_name",
567 FT_STRING
, BASE_NONE
,
571 { &hf_msnlb_host_ipv4
,
572 { "Host IPv4", "msnlb.host_ipv4",
577 { &hf_msnlb_host_ipv6
,
578 { "Host IPv6", "msnlb.host_ipv6",
583 { &hf_msnlb_host_unknown
,
584 { "Host Unknown", "msnlb.host_unknown",
590 { "Padding", "msnlb.padding",
595 { &hf_msnlb_extended_hb_unknown
,
596 { "Unknown HB Data", "msnlb.extended_hb.unknown",
603 static int *ett
[] = {
605 &ett_msnlb_signature
,
606 &ett_msnlb_teamingcfg
,
607 &ett_msnlb_portruleconfiguration
,
608 &ett_msnlb_currentmap
,
612 &ett_msnlb_loadweights
,
614 &ett_msnlb_extended_hb
617 proto_msnlb
= proto_register_protocol("MS Network Load Balancing", "MS NLB", "msnlb");
618 proto_register_field_array(proto_msnlb
, hf
, array_length(hf
));
619 proto_register_subtree_array(ett
, array_length(ett
));
621 msnlb_handle
= register_dissector("msnlb", dissect_msnlb
, proto_msnlb
);
625 proto_reg_handoff_msnlb(void)
627 dissector_add_uint("ethertype", ETHERTYPE_MS_NLB_HEARTBEAT
, msnlb_handle
);
636 * indent-tabs-mode: nil
639 * ex: set shiftwidth=2 tabstop=8 expandtab:
640 * :indentSize=2:tabSize=8:noTabs=true: