3 * Cisco's GLBP: Gateway Load Balancing Protocol
7 * Copyright 2007 Joerg Mayer (see AUTHORS file)
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 * http://www.cisco.com/en/US/docs/ios/12_2t/12_2t15/feature/guide/ft_glbp.pdf
32 * TODO: This dissector has been written without specs, so much of it is
33 * guesswork. Also, there are still unknown elements in the message.
35 * GLBP: Fa0/0 Grp 1020 Hello out VG Active pri 100 vIP FE80::C800:8FF:FE64:AAAA
36 * hello 3000, hold 10000 VF 1 Active pri 167 vMAC 0007.b403.fc01
37 * GLBP: Fa0/0 Grp 1021 Hello out VG Active pri 100 vIP 10.20.20.100
38 * hello 3000, hold 10000 VF 1 Active pri 167 vMAC 0007.b403.fd01
44 #include <epan/packet.h>
45 #include <epan/expert.h>
47 static int proto_glbp
= -1;
49 static gint hf_glbp_version
= -1;
50 static gint hf_glbp_unknown1
= -1;
51 static gint hf_glbp_group
= -1;
52 static gint hf_glbp_unknown2
= -1;
53 static gint hf_glbp_ownerid
= -1;
54 static gint hf_glbp_tlv
= -1;
55 static gint hf_glbp_type
= -1;
56 static gint hf_glbp_length
= -1;
57 /* glbp type = 1 - hello */
58 static gint hf_glbp_hello_unknown10
= -1;
59 static gint hf_glbp_hello_vgstate
= -1;
60 static gint hf_glbp_hello_unknown11
= -1;
61 static gint hf_glbp_hello_priority
= -1;
62 static gint hf_glbp_hello_unknown12
= -1;
63 static gint hf_glbp_hello_helloint
= -1;
64 static gint hf_glbp_hello_holdint
= -1;
65 static gint hf_glbp_hello_redirect
= -1;
66 static gint hf_glbp_hello_timeout
= -1;
67 static gint hf_glbp_hello_unknown13
= -1;
68 static gint hf_glbp_hello_addrtype
= -1;
69 static gint hf_glbp_hello_addrlen
= -1;
70 static gint hf_glbp_hello_virtualipv4
= -1;
71 static gint hf_glbp_hello_virtualipv6
= -1;
72 static gint hf_glbp_hello_virtualunk
= -1;
73 /* glbp type = 2 - Request/Response??? */
74 static gint hf_glbp_reqresp_forwarder
= -1;
75 static gint hf_glbp_reqresp_vfstate
= -1;
76 static gint hf_glbp_reqresp_unknown21
= -1;
77 static gint hf_glbp_reqresp_priority
= -1;
78 static gint hf_glbp_reqresp_weight
= -1;
79 static gint hf_glbp_reqresp_unknown22
= -1;
80 static gint hf_glbp_reqresp_virtualmac
= -1;
81 /* glbp type = 3 - Auth */
82 static gint hf_glbp_auth_authtype
= -1;
83 static gint hf_glbp_auth_authlength
= -1;
84 static gint hf_glbp_auth_plainpass
= -1;
85 static gint hf_glbp_auth_md5hash
= -1;
86 static gint hf_glbp_auth_md5chainindex
= -1;
87 static gint hf_glbp_auth_md5chainhash
= -1;
88 static gint hf_glbp_auth_authunknown
= -1;
90 static gint hf_glbp_unknown_data
= -1;
92 static gint ett_glbp
= -1;
93 static gint ett_glbp_tlv
= -1;
95 /* filterable expert infos */
96 static expert_field ei_glbp_ipv4_wrong_length
= EI_INIT
;
97 static expert_field ei_glbp_ipv6_wrong_length
= EI_INIT
;
98 static expert_field ei_glbp_tlv_length_too_small
= EI_INIT
;
99 static expert_field ei_glbp_tlv_invalid_bytes_used
= EI_INIT
;
101 static const value_string glbp_type_vals
[] = {
103 { 2, "Request/Response?" },
110 static const value_string glbp_reqresp_forwarder_vals
[] = {
118 static const value_string glbp_addr_type_vals
[] = {
125 static const value_string glbp_auth_type_vals
[] = {
135 static const value_string glbp_loadbalancing_vals
[] = {
136 { x
, "None (AVG only)" },
138 { x
, "Host dependent" },
139 { x
, "Round robin" },
145 static const value_string glbp_vgstate_vals
[] = {
158 static const value_string glbp_vfstate_vals
[] = {
170 dissect_glbp_hello(tvbuff_t
*tvb
, int offset
,
171 packet_info
*pinfo
, proto_tree
*tlv_tree
)
176 proto_tree_add_item(tlv_tree
, hf_glbp_hello_unknown10
, tvb
, offset
, 1, ENC_NA
);
178 proto_tree_add_item(tlv_tree
, hf_glbp_hello_vgstate
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
180 proto_tree_add_item(tlv_tree
, hf_glbp_hello_unknown11
, tvb
, offset
, 1, ENC_NA
);
182 proto_tree_add_item(tlv_tree
, hf_glbp_hello_priority
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
184 proto_tree_add_item(tlv_tree
, hf_glbp_hello_unknown12
, tvb
, offset
, 2, ENC_NA
);
186 proto_tree_add_item(tlv_tree
, hf_glbp_hello_helloint
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
188 proto_tree_add_item(tlv_tree
, hf_glbp_hello_holdint
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
190 proto_tree_add_item(tlv_tree
, hf_glbp_hello_redirect
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
192 proto_tree_add_item(tlv_tree
, hf_glbp_hello_timeout
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
194 proto_tree_add_item(tlv_tree
, hf_glbp_hello_unknown13
, tvb
, offset
, 2, ENC_NA
);
196 proto_tree_add_item(tlv_tree
, hf_glbp_hello_addrtype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
197 addrtype
= tvb_get_guint8( tvb
, offset
);
199 proto_tree_add_item(tlv_tree
, hf_glbp_hello_addrlen
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
200 addrlen
= tvb_get_guint8(tvb
, offset
);
205 expert_add_info_format(pinfo
, NULL
, &ei_glbp_ipv4_wrong_length
,
206 "Wrong IPv4 address length: %u", addrlen
);
207 return offset
+ addrlen
;
209 proto_tree_add_item(tlv_tree
, hf_glbp_hello_virtualipv4
, tvb
, offset
, addrlen
, ENC_BIG_ENDIAN
);
213 expert_add_info_format(pinfo
, NULL
, &ei_glbp_ipv6_wrong_length
,
214 "Wrong IPv6 address length: %u", addrlen
);
215 return offset
+ addrlen
;
217 proto_tree_add_item(tlv_tree
, hf_glbp_hello_virtualipv6
, tvb
, offset
, addrlen
, ENC_NA
);
220 proto_tree_add_item(tlv_tree
, hf_glbp_hello_virtualunk
, tvb
, offset
, addrlen
, ENC_NA
);
225 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
226 val_to_str(addrtype
, glbp_addr_type_vals
, "%d"));
233 dissect_glbp_reqresp(tvbuff_t
*tvb
, int offset
,
234 packet_info
*pinfo _U_
, proto_tree
*tlv_tree
)
236 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_forwarder
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
238 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_vfstate
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
240 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_unknown21
, tvb
, offset
, 1, ENC_NA
);
242 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_priority
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
244 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_weight
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
246 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_unknown22
, tvb
, offset
, 7, ENC_NA
);
248 proto_tree_add_item(tlv_tree
, hf_glbp_reqresp_virtualmac
, tvb
, offset
, 6, ENC_NA
);
255 dissect_glbp_auth(tvbuff_t
*tvb
, int offset
,
256 packet_info
*pinfo _U_
, proto_tree
*tlv_tree
)
261 proto_tree_add_item(tlv_tree
, hf_glbp_auth_authtype
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
262 authtype
= tvb_get_guint8(tvb
, offset
);
264 proto_tree_add_item(tlv_tree
, hf_glbp_auth_authlength
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
265 authlength
= tvb_get_guint8(tvb
, offset
);
269 proto_tree_add_item(tlv_tree
, hf_glbp_auth_plainpass
, tvb
, offset
, authlength
, ENC_ASCII
|ENC_NA
);
270 offset
+= authlength
;
273 proto_tree_add_item(tlv_tree
, hf_glbp_auth_md5hash
, tvb
, offset
, authlength
, ENC_NA
);
274 offset
+= authlength
;
277 proto_tree_add_item(tlv_tree
, hf_glbp_auth_md5chainindex
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
278 proto_tree_add_item(tlv_tree
, hf_glbp_auth_md5chainhash
, tvb
, offset
+4, authlength
-4, ENC_NA
);
279 offset
+= authlength
;
282 proto_tree_add_item(tlv_tree
, hf_glbp_auth_authunknown
, tvb
, offset
, authlength
, ENC_NA
);
283 offset
+= authlength
;
291 dissect_glbp_unknown(tvbuff_t
*tvb
, int offset
, guint32 length
,
292 packet_info
*pinfo _U_
, proto_tree
*tlv_tree
)
294 proto_tree_add_item(tlv_tree
, hf_glbp_unknown_data
, tvb
, offset
, length
, ENC_NA
);
301 dissect_glbp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
303 proto_tree
*glbp_tree
;
304 proto_tree
*tlv_tree
;
312 group
= tvb_get_ntohs(tvb
, 2);
314 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "GLBP");
315 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "G: %d", group
);
317 ti
= proto_tree_add_item(tree
, proto_glbp
, tvb
, 0, -1, ENC_NA
);
318 glbp_tree
= proto_item_add_subtree(ti
, ett_glbp
);
321 proto_tree_add_item(glbp_tree
, hf_glbp_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
323 proto_tree_add_item(glbp_tree
, hf_glbp_unknown1
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
325 proto_tree_add_item(glbp_tree
, hf_glbp_group
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
327 proto_tree_add_item(glbp_tree
, hf_glbp_unknown2
, tvb
, offset
, 2, ENC_NA
);
329 proto_tree_add_item(glbp_tree
, hf_glbp_ownerid
, tvb
, offset
, 6, ENC_NA
);
331 while (tvb_length_remaining(tvb
, offset
) > 0) {
333 type
= tvb_get_guint8(tvb
, offset
);
334 length
= tvb_get_guint8(tvb
, offset
+1);
336 expert_add_info_format(pinfo
, NULL
, &ei_glbp_tlv_length_too_small
,
337 "Length %u too small", length
);
342 ti
= proto_tree_add_item(glbp_tree
, hf_glbp_tlv
, tvb
, offset
, length
+2, ENC_BIG_ENDIAN
);
343 tlv_tree
= proto_item_add_subtree(ti
, ett_glbp_tlv
);
344 proto_item_append_text(ti
, " l=%d, t=%s", length
+2,
345 val_to_str(type
, glbp_type_vals
, "%d"));
347 proto_tree_add_item(tlv_tree
, hf_glbp_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
349 proto_tree_add_item(tlv_tree
, hf_glbp_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
351 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
352 val_to_str(type
, glbp_type_vals
, "%d"));
357 offset
= dissect_glbp_hello(tvb
, offset
, pinfo
, tlv_tree
);
359 case 2: /* Request/Response */
360 offset
= dissect_glbp_reqresp(tvb
, offset
, pinfo
, tlv_tree
);
362 case 3: /* Plaintext auth */
363 offset
= dissect_glbp_auth(tvb
, offset
, pinfo
, tlv_tree
);
366 offset
= dissect_glbp_unknown(tvb
, offset
, length
, pinfo
, tlv_tree
);
369 if (lastoffset
>= offset
) {
370 expert_add_info(pinfo
, NULL
, &ei_glbp_tlv_invalid_bytes_used
);
373 /* Skip over trailing bytes before starting with the next element */
374 if (lastoffset
+ length
> offset
)
375 offset
= lastoffset
+ length
;
381 test_glbp(tvbuff_t
*tvb
, packet_info
*pinfo
)
384 if ( tvb_length(tvb
) < 2)
386 unknown1
= tvb_get_guint8(tvb
, 1);
387 if (tvb_get_guint8(tvb
, 0) != 1 /* version? */
389 || pinfo
->srcport
!= pinfo
->destport
391 || unknown1
== 0 && pinfo
->net_dst
!= ipv4
:224.0.0.102
392 && pinfo
->net_dst
!= ipv6
:...
393 || unknown1
== 0 && pinfo
->dl_src
!= ether
:c2
-00-7c
-b8
-00-00
402 dissect_glbp_static(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
404 if ( !test_glbp(tvb
, pinfo
) ) {
407 return dissect_glbp(tvb
, pinfo
, tree
);
412 proto_register_glbp(void)
414 static hf_register_info hf
[] = {
417 { "Version?", "glbp.version", FT_UINT8
, BASE_DEC
, NULL
,
421 { "Unknown1", "glbp.unknown1", FT_UINT8
, BASE_DEC
, NULL
,
425 { "Group", "glbp.group", FT_UINT16
, BASE_DEC
, NULL
,
429 { "Unknown2", "glbp.unknown2", FT_BYTES
, BASE_NONE
, NULL
,
433 { "Owner ID", "glbp.ownerid", FT_ETHER
, BASE_NONE
, NULL
,
437 { "TLV", "glbp.tlv", FT_PROTOCOL
, BASE_NONE
, NULL
,
441 { "Type", "glbp.type", FT_UINT8
, BASE_DEC
, VALS(glbp_type_vals
),
445 { "Length", "glbp.length", FT_UINT8
, BASE_DEC
, NULL
,
448 /* type = 1 - hello */
449 { &hf_glbp_hello_unknown10
,
450 { "Unknown1-0", "glbp.hello.unknown10", FT_BYTES
, BASE_NONE
, NULL
,
453 { &hf_glbp_hello_vgstate
,
454 { "VG state?", "glbp.hello.vgstate", FT_UINT8
, BASE_DEC
, VALS(glbp_vgstate_vals
),
457 { &hf_glbp_hello_unknown11
,
458 { "Unknown1-1", "glbp.hello.unknown11", FT_BYTES
, BASE_NONE
, NULL
,
461 { &hf_glbp_hello_priority
,
462 { "Priority", "glbp.hello.priority", FT_UINT8
, BASE_DEC
, NULL
,
465 { &hf_glbp_hello_unknown12
,
466 { "Unknown1-2", "glbp.hello.unknown12", FT_BYTES
, BASE_NONE
, NULL
,
469 { &hf_glbp_hello_helloint
,
470 { "Helloint", "glbp.hello.helloint", FT_UINT32
, BASE_DEC
, NULL
,
471 0x0, "Hello interval [msec]", HFILL
}},
473 { &hf_glbp_hello_holdint
,
474 { "Holdint", "glbp.hello.holdint", FT_UINT32
, BASE_DEC
, NULL
,
475 0x0, "Hold interval [msec]", HFILL
}},
477 { &hf_glbp_hello_redirect
,
478 { "Redirect", "glbp.hello.redirect", FT_UINT16
, BASE_DEC
, NULL
,
479 0x0, "Redirect interval [sec]", HFILL
}},
481 { &hf_glbp_hello_timeout
,
482 { "Timeout", "glbp.hello.timeout", FT_UINT16
, BASE_DEC
, NULL
,
483 0x0, "Forwarder timeout interval [sec]", HFILL
}},
485 { &hf_glbp_hello_unknown13
,
486 { "Unknown1-3", "glbp.hello.unknown13", FT_BYTES
, BASE_NONE
, NULL
,
489 { &hf_glbp_hello_addrtype
,
490 { "Address type", "glbp.hello.addrtype", FT_UINT8
, BASE_DEC
, VALS(glbp_addr_type_vals
),
493 { &hf_glbp_hello_addrlen
,
494 { "Address length", "glbp.hello.addrlen", FT_UINT8
, BASE_DEC
, NULL
,
497 { &hf_glbp_hello_virtualipv4
,
498 { "Virtual IPv4", "glbp.hello.virtualipv4", FT_IPv4
, BASE_NONE
, NULL
,
501 { &hf_glbp_hello_virtualipv6
,
502 { "Virtual IPv6", "glbp.hello.virtualipv6", FT_IPv6
, BASE_NONE
, NULL
,
505 { &hf_glbp_hello_virtualunk
,
506 { "Virtual Unknown", "glbp.hello.virtualunk", FT_BYTES
, BASE_NONE
, NULL
,
509 /* type = 2 - request/response??? */
510 { &hf_glbp_reqresp_forwarder
,
511 { "Forwarder?", "glbp.reqresp.forwarder", FT_UINT8
, BASE_DEC
, NULL
,
514 { &hf_glbp_reqresp_vfstate
,
515 { "VF state?", "glbp.reqresp.vfstate", FT_UINT8
, BASE_DEC
, VALS(glbp_vfstate_vals
),
518 { &hf_glbp_reqresp_unknown21
,
519 { "Unknown2-1", "glbp.reqresp.unknown21", FT_BYTES
, BASE_NONE
, NULL
,
522 { &hf_glbp_reqresp_priority
,
523 { "Priority", "glbp.reqresp.priority", FT_UINT8
, BASE_DEC
, NULL
,
526 { &hf_glbp_reqresp_weight
,
527 { "Weight", "glbp.reqresp.weight", FT_UINT8
, BASE_DEC
, NULL
,
530 { &hf_glbp_reqresp_unknown22
,
531 { "Unknown2-2", "glbp.reqresp.unknown22", FT_BYTES
, BASE_NONE
, NULL
,
534 { &hf_glbp_reqresp_virtualmac
,
535 { "Virtualmac", "glbp.reqresp.virtualmac", FT_ETHER
, BASE_NONE
, NULL
,
538 /* type = 3 - auth */
539 { &hf_glbp_auth_authtype
,
540 { "Authtype", "glbp.auth.authtype", FT_UINT8
, BASE_DEC
, VALS(glbp_auth_type_vals
),
543 { &hf_glbp_auth_authlength
,
544 { "Authlength", "glbp.auth.authlength", FT_UINT8
, BASE_DEC
, NULL
,
547 { &hf_glbp_auth_plainpass
,
548 { "Plain pass", "glbp.auth.plainpass", FT_STRING
, BASE_NONE
, NULL
,
551 { &hf_glbp_auth_md5hash
,
552 { "MD5-string hash", "glbp.auth.md5hash", FT_BYTES
, BASE_NONE
, NULL
,
555 { &hf_glbp_auth_md5chainindex
,
556 { "MD5-chain index", "glbp.auth.md5chainindex", FT_UINT32
, BASE_DEC
, NULL
,
559 { &hf_glbp_auth_md5chainhash
,
560 { "MD5-chain hash", "glbp.auth.md5chainhash", FT_BYTES
, BASE_NONE
, NULL
,
563 { &hf_glbp_auth_authunknown
,
564 { "Unknown auth value", "glbp.auth.authunknown", FT_BYTES
, BASE_NONE
, NULL
,
568 { &hf_glbp_unknown_data
,
569 { "Unknown TLV data", "glbp.unknown.data", FT_BYTES
, BASE_NONE
, NULL
,
573 static gint
*ett
[] = {
578 static ei_register_info ei
[] = {
579 { &ei_glbp_ipv4_wrong_length
,
580 { "glbp.ipv4_wrong_length", PI_MALFORMED
, PI_ERROR
,
581 "Wrong IPv4 address length: %u",
583 { &ei_glbp_ipv6_wrong_length
,
584 { "glbp.ipv6_wrong_length", PI_MALFORMED
, PI_ERROR
,
585 "Wrong IPv6 address length: %u",
587 { &ei_glbp_tlv_length_too_small
,
588 { "glbp.tlv_length_too_small", PI_MALFORMED
, PI_ERROR
,
589 "Length %u too small",
591 { &ei_glbp_tlv_invalid_bytes_used
,
592 { "glbp.tlv_invalid_bytes_used", PI_MALFORMED
, PI_ERROR
,
593 "Zero or negative length",
597 expert_module_t
* expert_glbp
;
599 proto_glbp
= proto_register_protocol(
600 "Gateway Load Balancing Protocol", "GLBP", "glbp");
601 proto_register_field_array(proto_glbp
, hf
, array_length(hf
));
602 proto_register_subtree_array(ett
, array_length(ett
));
603 expert_glbp
= expert_register_protocol(proto_glbp
);
604 expert_register_field_array(expert_glbp
, ei
, array_length(ei
));
608 proto_reg_handoff_glbp(void)
610 dissector_handle_t glbp_handle
;
612 glbp_handle
= new_create_dissector_handle(dissect_glbp_static
, proto_glbp
);
613 dissector_add_uint("udp.port", 3222, glbp_handle
);