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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
46 #include <epan/packet.h>
47 #include <epan/expert.h>
49 static int proto_glbp = -1;
51 static gint hf_glbp_version = -1;
52 static gint hf_glbp_unknown1 = -1;
53 static gint hf_glbp_group = -1;
54 static gint hf_glbp_unknown2 = -1;
55 static gint hf_glbp_ownerid = -1;
56 static gint hf_glbp_tlv = -1;
57 static gint hf_glbp_type = -1;
58 static gint hf_glbp_length = -1;
59 /* glbp type = 1 - hello */
60 static gint hf_glbp_hello_unknown10 = -1;
61 static gint hf_glbp_hello_vgstate = -1;
62 static gint hf_glbp_hello_unknown11 = -1;
63 static gint hf_glbp_hello_priority = -1;
64 static gint hf_glbp_hello_unknown12 = -1;
65 static gint hf_glbp_hello_helloint = -1;
66 static gint hf_glbp_hello_holdint = -1;
67 static gint hf_glbp_hello_redirect = -1;
68 static gint hf_glbp_hello_timeout = -1;
69 static gint hf_glbp_hello_unknown13 = -1;
70 static gint hf_glbp_hello_addrtype = -1;
71 static gint hf_glbp_hello_addrlen = -1;
72 static gint hf_glbp_hello_virtualipv4 = -1;
73 static gint hf_glbp_hello_virtualipv6 = -1;
74 static gint hf_glbp_hello_virtualunk = -1;
75 /* glbp type = 2 - Request/Response??? */
76 static gint hf_glbp_reqresp_forwarder = -1;
77 static gint hf_glbp_reqresp_vfstate = -1;
78 static gint hf_glbp_reqresp_unknown21 = -1;
79 static gint hf_glbp_reqresp_priority = -1;
80 static gint hf_glbp_reqresp_weight = -1;
81 static gint hf_glbp_reqresp_unknown22 = -1;
82 static gint hf_glbp_reqresp_virtualmac = -1;
83 /* glbp type = 3 - Auth */
84 static gint hf_glbp_auth_authtype = -1;
85 static gint hf_glbp_auth_authlength = -1;
86 static gint hf_glbp_auth_plainpass = -1;
87 static gint hf_glbp_auth_md5hash = -1;
88 static gint hf_glbp_auth_md5chainindex = -1;
89 static gint hf_glbp_auth_md5chainhash = -1;
90 static gint hf_glbp_auth_authunknown = -1;
92 static gint hf_glbp_unknown_data = -1;
94 static gint ett_glbp = -1;
95 static gint ett_glbp_tlv = -1;
97 static const value_string glbp_type_vals[] = {
99 { 2, "Request/Response?" },
106 static const value_string glbp_reqresp_forwarder_vals[] = {
114 static const value_string glbp_addr_type_vals[] = {
121 static const value_string glbp_auth_type_vals[] = {
131 static const value_string glbp_loadbalancing_vals[] = {
132 { x, "None (AVG only)" },
134 { x, "Host dependent" },
135 { x, "Round robin" },
141 static const value_string glbp_vgstate_vals[] = {
154 static const value_string glbp_vfstate_vals[] = {
166 dissect_glbp_hello(tvbuff_t *tvb, int offset,
167 packet_info *pinfo, proto_tree *tlv_tree)
172 proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown10, tvb, offset, 1, FALSE);
174 proto_tree_add_item(tlv_tree, hf_glbp_hello_vgstate, tvb, offset, 1, FALSE);
176 proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown11, tvb, offset, 1, FALSE);
178 proto_tree_add_item(tlv_tree, hf_glbp_hello_priority, tvb, offset, 1, FALSE);
180 proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown12, tvb, offset, 2, FALSE);
182 proto_tree_add_item(tlv_tree, hf_glbp_hello_helloint, tvb, offset, 4, FALSE);
184 proto_tree_add_item(tlv_tree, hf_glbp_hello_holdint, tvb, offset, 4, FALSE);
186 proto_tree_add_item(tlv_tree, hf_glbp_hello_redirect, tvb, offset, 2, FALSE);
188 proto_tree_add_item(tlv_tree, hf_glbp_hello_timeout, tvb, offset, 2, FALSE);
190 proto_tree_add_item(tlv_tree, hf_glbp_hello_unknown13, tvb, offset, 2, FALSE);
192 proto_tree_add_item(tlv_tree, hf_glbp_hello_addrtype, tvb, offset, 1, FALSE);
193 addrtype = tvb_get_guint8(tvb, offset);
195 proto_tree_add_item(tlv_tree, hf_glbp_hello_addrlen, tvb, offset, 1, FALSE);
196 addrlen = tvb_get_guint8(tvb, offset);
201 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Wrong IPv4 address length: %u", addrlen);
202 return offset + addrlen;
204 proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualipv4, tvb, offset, addrlen, FALSE);
208 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Wrong IPv6 address length: %u", addrlen);
209 return offset + addrlen;
211 proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualipv6, tvb, offset, addrlen, FALSE);
214 proto_tree_add_item(tlv_tree, hf_glbp_hello_virtualunk, tvb, offset, addrlen, FALSE);
219 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
220 val_to_str(addrtype, glbp_addr_type_vals, "%d"));
227 dissect_glbp_reqresp(tvbuff_t *tvb, int offset,
228 packet_info *pinfo _U_, proto_tree *tlv_tree)
230 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_forwarder, tvb, offset, 1, FALSE);
232 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_vfstate, tvb, offset, 1, FALSE);
234 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_unknown21, tvb, offset, 1, FALSE);
236 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_priority, tvb, offset, 1, FALSE);
238 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_weight, tvb, offset, 1, FALSE);
240 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_unknown22, tvb, offset, 7, FALSE);
242 proto_tree_add_item(tlv_tree, hf_glbp_reqresp_virtualmac, tvb, offset, 6, FALSE);
249 dissect_glbp_auth(tvbuff_t *tvb, int offset,
250 packet_info *pinfo _U_, proto_tree *tlv_tree)
255 proto_tree_add_item(tlv_tree, hf_glbp_auth_authtype, tvb, offset, 1, FALSE);
256 authtype = tvb_get_guint8(tvb, offset);
258 proto_tree_add_item(tlv_tree, hf_glbp_auth_authlength, tvb, offset, 1, FALSE);
259 authlength = tvb_get_guint8(tvb, offset);
263 proto_tree_add_item(tlv_tree, hf_glbp_auth_plainpass, tvb, offset, authlength, FALSE);
264 offset += authlength;
267 proto_tree_add_item(tlv_tree, hf_glbp_auth_md5hash, tvb, offset, authlength, FALSE);
268 offset += authlength;
271 proto_tree_add_item(tlv_tree, hf_glbp_auth_md5chainindex, tvb, offset, 4, FALSE);
272 proto_tree_add_item(tlv_tree, hf_glbp_auth_md5chainhash, tvb, offset+4, authlength-4, FALSE);
273 offset += authlength;
276 proto_tree_add_item(tlv_tree, hf_glbp_auth_authunknown, tvb, offset, authlength, FALSE);
277 offset += authlength;
285 dissect_glbp_unknown(tvbuff_t *tvb, int offset, guint32 length,
286 packet_info *pinfo _U_, proto_tree *tlv_tree)
288 proto_tree_add_item(tlv_tree, hf_glbp_unknown_data, tvb, offset, length, FALSE);
295 dissect_glbp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
297 proto_tree *glbp_tree = NULL;
298 proto_tree *tlv_tree = NULL;
299 proto_item *ti = NULL;
306 group = tvb_get_ntohs(tvb, 2);
308 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GLBP");
309 col_add_fstr(pinfo->cinfo, COL_INFO, "G: %d", group);
312 ti = proto_tree_add_item(tree, proto_glbp, tvb, 0, -1, FALSE);
313 glbp_tree = proto_item_add_subtree(ti, ett_glbp);
316 proto_tree_add_item(glbp_tree, hf_glbp_version, tvb, offset, 1, FALSE);
318 proto_tree_add_item(glbp_tree, hf_glbp_unknown1, tvb, offset, 1, FALSE);
320 proto_tree_add_item(glbp_tree, hf_glbp_group, tvb, offset, 2, FALSE);
322 proto_tree_add_item(glbp_tree, hf_glbp_unknown2, tvb, offset, 2, FALSE);
324 proto_tree_add_item(glbp_tree, hf_glbp_ownerid, tvb, offset, 6, FALSE);
326 while (tvb_length_remaining(tvb, offset) > 0) {
328 type = tvb_get_guint8(tvb, offset);
329 length = tvb_get_guint8(tvb, offset+1);
331 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Length %u too small", length);
336 ti = proto_tree_add_item(glbp_tree, hf_glbp_tlv, tvb, offset, length+2, FALSE);
337 tlv_tree = proto_item_add_subtree(ti, ett_glbp_tlv);
338 proto_item_append_text(ti, " l=%d, t=%s", length+2,
339 val_to_str(type, glbp_type_vals, "%d"));
341 proto_tree_add_item(tlv_tree, hf_glbp_type, tvb, offset, 1, FALSE);
343 proto_tree_add_item(tlv_tree, hf_glbp_length, tvb, offset, 1, FALSE);
345 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
346 val_to_str(type, glbp_type_vals, "%d"));
351 offset = dissect_glbp_hello(tvb, offset, pinfo, tlv_tree);
353 case 2: /* Request/Response */
354 offset = dissect_glbp_reqresp(tvb, offset, pinfo, tlv_tree);
356 case 3: /* Plaintext auth */
357 offset = dissect_glbp_auth(tvb, offset, pinfo, tlv_tree);
360 offset = dissect_glbp_unknown(tvb, offset, length, pinfo, tlv_tree);
363 if (lastoffset >= offset) {
364 expert_add_info_format(pinfo, NULL, PI_MALFORMED, PI_ERROR, "Zero or negative length");
367 /* Skip over trailing bytes before starting with the next element */
368 if (lastoffset + length > offset)
369 offset = lastoffset + length;
376 test_glbp(tvbuff_t *tvb, packet_info *pinfo)
379 if ( tvb_length(tvb) < 2)
381 unknown1 = tvb_get_guint8(tvb, 1);
382 if (tvb_get_guint8(tvb, 0) != 1 /* version? */
384 || pinfo->srcport != pinfo->destport
386 || unknown1 == 0 && pinfo->net_dst != ipv4:224.0.0.102
387 && pinfo->net_dst != ipv6:...
388 || unknown1 == 0 && pinfo->dl_src != ether:c2-00-7c-b8-00-00
397 dissect_glbp_static(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
399 if ( !test_glbp(tvb, pinfo) ) {
402 return dissect_glbp(tvb, pinfo, tree);
407 proto_register_glbp(void)
409 static hf_register_info hf[] = {
412 { "Version?", "glbp.version", FT_UINT8, BASE_DEC, NULL,
416 { "Unknown1", "glbp.unknown1", FT_UINT8, BASE_DEC, NULL,
420 { "Group", "glbp.group", FT_UINT16, BASE_DEC, NULL,
424 { "Unknown2", "glbp.unknown2", FT_BYTES, BASE_NONE, NULL,
428 { "Owner ID", "glbp.ownerid", FT_ETHER, BASE_NONE, NULL,
432 { "TLV", "glbp.tlv", FT_PROTOCOL, BASE_NONE, NULL,
436 { "Type", "glbp.type", FT_UINT8, BASE_DEC, VALS(glbp_type_vals),
440 { "Length", "glbp.length", FT_UINT8, BASE_DEC, NULL,
443 /* type = 1 - hello */
444 { &hf_glbp_hello_unknown10,
445 { "Unknown1-0", "glbp.hello.unknown10", FT_BYTES, BASE_NONE, NULL,
448 { &hf_glbp_hello_vgstate,
449 { "VG state?", "glbp.hello.vgstate", FT_UINT8, BASE_DEC, VALS(glbp_vgstate_vals),
452 { &hf_glbp_hello_unknown11,
453 { "Unknown1-1", "glbp.hello.unknown11", FT_BYTES, BASE_NONE, NULL,
456 { &hf_glbp_hello_priority,
457 { "Priority", "glbp.hello.priority", FT_UINT8, BASE_DEC, NULL,
460 { &hf_glbp_hello_unknown12,
461 { "Unknown1-2", "glbp.hello.unknown12", FT_BYTES, BASE_NONE, NULL,
464 { &hf_glbp_hello_helloint,
465 { "Helloint", "glbp.hello.helloint", FT_UINT32, BASE_DEC, NULL,
466 0x0, "Hello interval [msec]", HFILL }},
468 { &hf_glbp_hello_holdint,
469 { "Holdint", "glbp.hello.holdint", FT_UINT32, BASE_DEC, NULL,
470 0x0, "Hold interval [msec]", HFILL }},
472 { &hf_glbp_hello_redirect,
473 { "Redirect", "glbp.hello.redirect", FT_UINT16, BASE_DEC, NULL,
474 0x0, "Redirect interval [sec]", HFILL }},
476 { &hf_glbp_hello_timeout,
477 { "Timeout", "glbp.hello.timeout", FT_UINT16, BASE_DEC, NULL,
478 0x0, "Forwarder timeout interval [sec]", HFILL }},
480 { &hf_glbp_hello_unknown13,
481 { "Unknown1-3", "glbp.hello.unknown13", FT_BYTES, BASE_NONE, NULL,
484 { &hf_glbp_hello_addrtype,
485 { "Address type", "glbp.hello.addrtype", FT_UINT8, BASE_DEC, VALS(glbp_addr_type_vals),
488 { &hf_glbp_hello_addrlen,
489 { "Address length", "glbp.hello.addrlen", FT_UINT8, BASE_DEC, NULL,
492 { &hf_glbp_hello_virtualipv4,
493 { "Virtual IPv4", "glbp.hello.virtualipv4", FT_IPv4, BASE_NONE, NULL,
496 { &hf_glbp_hello_virtualipv6,
497 { "Virtual IPv6", "glbp.hello.virtualipv6", FT_IPv6, BASE_NONE, NULL,
500 { &hf_glbp_hello_virtualunk,
501 { "Virtual Unknown", "glbp.hello.virtualunk", FT_BYTES, BASE_NONE, NULL,
504 /* type = 2 - request/response??? */
505 { &hf_glbp_reqresp_forwarder,
506 { "Forwarder?", "glbp.reqresp.forwarder", FT_UINT8, BASE_DEC, NULL,
509 { &hf_glbp_reqresp_vfstate,
510 { "VF state?", "glbp.reqresp.vfstate", FT_UINT8, BASE_DEC, VALS(glbp_vfstate_vals),
513 { &hf_glbp_reqresp_unknown21,
514 { "Unknown2-1", "glbp.reqresp.unknown21", FT_BYTES, BASE_NONE, NULL,
517 { &hf_glbp_reqresp_priority,
518 { "Priority", "glbp.reqresp.priority", FT_UINT8, BASE_DEC, NULL,
521 { &hf_glbp_reqresp_weight,
522 { "Weight", "glbp.reqresp.weight", FT_UINT8, BASE_DEC, NULL,
525 { &hf_glbp_reqresp_unknown22,
526 { "Unknown2-2", "glbp.reqresp.unknown22", FT_BYTES, BASE_NONE, NULL,
529 { &hf_glbp_reqresp_virtualmac,
530 { "Virtualmac", "glbp.reqresp.virtualmac", FT_ETHER, BASE_NONE, NULL,
533 /* type = 3 - auth */
534 { &hf_glbp_auth_authtype,
535 { "Authtype", "glbp.auth.authtype", FT_UINT8, BASE_DEC, VALS(glbp_auth_type_vals),
538 { &hf_glbp_auth_authlength,
539 { "Authlength", "glbp.auth.authlength", FT_UINT8, BASE_DEC, NULL,
542 { &hf_glbp_auth_plainpass,
543 { "Plain pass", "glbp.auth.plainpass", FT_STRING, BASE_NONE, NULL,
546 { &hf_glbp_auth_md5hash,
547 { "MD5-string hash", "glbp.auth.md5hash", FT_BYTES, BASE_NONE, NULL,
550 { &hf_glbp_auth_md5chainindex,
551 { "MD5-chain index", "glbp.auth.md5chainindex", FT_UINT32, BASE_DEC, NULL,
554 { &hf_glbp_auth_md5chainhash,
555 { "MD5-chain hash", "glbp.auth.md5chainhash", FT_BYTES, BASE_NONE, NULL,
558 { &hf_glbp_auth_authunknown,
559 { "Unknown auth value", "glbp.auth.authunknown", FT_BYTES, BASE_NONE, NULL,
563 { &hf_glbp_unknown_data,
564 { "Unknown TLV data", "glbp.unknown.data", FT_BYTES, BASE_NONE, NULL,
568 static gint *ett[] = {
573 proto_glbp = proto_register_protocol(
574 "Gateway Load Balancing Protocol", "GLBP", "glbp");
575 proto_register_field_array(proto_glbp, hf, array_length(hf));
576 proto_register_subtree_array(ett, array_length(ett));
580 proto_reg_handoff_glbp(void)
582 dissector_handle_t glbp_handle;
584 glbp_handle = new_create_dissector_handle(dissect_glbp_static, proto_glbp);
585 dissector_add("udp.port", 3222, glbp_handle);