2 * Routines for the Virtual Router Redundancy Protocol (VRRP)
4 * VRRPv2: RFC3768 (superseeding RFC2338)
7 * Heikki Vatiainen <hessu@cs.tut.fi>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <epan/packet.h>
34 #include <epan/ipproto.h>
35 #include <epan/in_cksum.h>
36 #include <epan/expert.h>
38 static gint proto_vrrp
= -1;
39 static gint ett_vrrp
= -1;
40 static gint ett_vrrp_ver_type
= -1;
42 static gint hf_vrrp_ver_type
= -1;
43 static gint hf_vrrp_version
= -1;
44 static gint hf_vrrp_type
= -1;
45 static gint hf_vrrp_virt_rtr_id
= -1;
46 static gint hf_vrrp_prio
= -1;
47 static gint hf_vrrp_addr_count
= -1;
48 static gint hf_vrrp_checksum
= -1;
49 static gint hf_vrrp_checksum_bad
= -1;
50 static gint hf_vrrp_auth_type
= -1;
51 static gint hf_vrrp_adver_int
= -1;
52 static gint hf_vrrp_reserved_mbz
= -1;
53 static gint hf_vrrp_short_adver_int
= -1;
54 static gint hf_vrrp_ip
= -1;
55 static gint hf_vrrp_ip6
= -1;
56 static gint hf_vrrp_auth_string
= -1;
58 static expert_field ei_vrrp_checksum
= EI_INIT
;
60 #define VRRP_VERSION_MASK 0xf0
61 #define VRRP_TYPE_MASK 0x0f
62 #define VRRP_AUTH_DATA_LEN 8
64 #define VRRP_TYPE_ADVERTISEMENT 1
65 static const value_string vrrp_type_vals
[] = {
66 {VRRP_TYPE_ADVERTISEMENT
, "Advertisement"},
70 #define VRRP_AUTH_TYPE_NONE 0
71 #define VRRP_AUTH_TYPE_SIMPLE_TEXT 1
72 #define VRRP_AUTH_TYPE_IP_AUTH_HDR 2
73 static const value_string vrrp_auth_vals
[] = {
74 {VRRP_AUTH_TYPE_NONE
, "No Authentication"},
75 {VRRP_AUTH_TYPE_SIMPLE_TEXT
, "Simple Text Authentication [RFC 2338] / Reserved [RFC 3768]"},
76 {VRRP_AUTH_TYPE_IP_AUTH_HDR
, "IP Authentication Header [RFC 2338] / Reserved [RFC 3768]"},
80 #define VRRP_PRIORITY_MASTER_STOPPING 0
81 /* Values between 1 and 254 inclusive are for backup VRRP routers */
82 #define VRRP_PRIORITY_DEFAULT 100
83 #define VRRP_PRIORITY_OWNER 255
84 static const value_string vrrp_prio_vals
[] = {
85 {VRRP_PRIORITY_MASTER_STOPPING
, "Current Master has stopped participating in VRRP"},
86 {VRRP_PRIORITY_DEFAULT
, "Default priority for a backup VRRP router"},
87 {VRRP_PRIORITY_OWNER
, "This VRRP router owns the virtual router's IP address(es)"},
93 dissect_vrrp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
101 proto_item
*ti
, *tv
, *hidden_item
, *checksum_item
;
102 proto_tree
*vrrp_tree
, *ver_type_tree
;
103 guint8 priority
, addr_count
= 0, auth_type
= VRRP_AUTH_TYPE_NONE
;
104 guint16 cksum
, computed_cksum
;
106 is_ipv6
= (pinfo
->src
.type
== AT_IPv6
);
108 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "VRRP");
109 col_clear(pinfo
->cinfo
, COL_INFO
);
111 ver_type
= tvb_get_guint8(tvb
, 0);
112 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Announcement (v%u)",
113 hi_nibble(ver_type
));
115 ti
= proto_tree_add_item(tree
, proto_vrrp
, tvb
, 0, -1, ENC_NA
);
116 vrrp_tree
= proto_item_add_subtree(ti
, ett_vrrp
);
118 priority
= tvb_get_guint8(tvb
, 2);
119 addr_count
= tvb_get_guint8(tvb
, 3);
121 tv
= proto_tree_add_uint_format(vrrp_tree
, hf_vrrp_ver_type
,
122 tvb
, offset
, 1, ver_type
,
123 "Version %u, Packet type %u (%s)",
124 hi_nibble(ver_type
), lo_nibble(ver_type
),
125 val_to_str_const(lo_nibble(ver_type
), vrrp_type_vals
, "Unknown"));
126 ver_type_tree
= proto_item_add_subtree(tv
, ett_vrrp_ver_type
);
129 proto_tree_add_uint(ver_type_tree
, hf_vrrp_version
, tvb
,
130 offset
, 1, ver_type
);
131 proto_tree_add_uint(ver_type_tree
, hf_vrrp_type
, tvb
, offset
, 1, ver_type
);
134 proto_tree_add_item(vrrp_tree
, hf_vrrp_virt_rtr_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
137 proto_tree_add_uint_format(vrrp_tree
, hf_vrrp_prio
, tvb
, offset
, 1, priority
, "Priority: %u (%s)",
139 val_to_str_const(priority
, vrrp_prio_vals
, "Non-default backup priority"));
142 proto_tree_add_uint(vrrp_tree
, hf_vrrp_addr_count
, tvb
,
143 offset
, 1, addr_count
);
146 switch(hi_nibble(ver_type
)) {
148 /* 4 bits reserved (mbz) + 12 bits interval */
149 proto_tree_add_item(vrrp_tree
, hf_vrrp_reserved_mbz
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
150 proto_tree_add_item(vrrp_tree
, hf_vrrp_short_adver_int
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
155 /* 1 byte auth type + 1 byte interval */
156 auth_type
= tvb_get_guint8(tvb
, offset
);
157 proto_tree_add_item(vrrp_tree
, hf_vrrp_auth_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
160 proto_tree_add_item(vrrp_tree
, hf_vrrp_adver_int
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
169 checksum_item
= proto_tree_add_item(vrrp_tree
, hf_vrrp_checksum
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
171 cksum
= tvb_get_ntohs(tvb
, offset
);
172 vrrp_len
= (gint
)tvb_reported_length(tvb
);
173 if (!pinfo
->fragmented
&& (gint
)tvb_length(tvb
) >= vrrp_len
) {
174 /* The packet isn't part of a fragmented datagram
175 and isn't truncated, so we can checksum it. */
176 switch(hi_nibble(ver_type
)) {
178 /* Set up the fields of the pseudo-header. */
179 cksum_vec
[0].ptr
= (guint8
*)pinfo
->src
.data
;
180 cksum_vec
[0].len
= pinfo
->src
.len
;
181 cksum_vec
[1].ptr
= (guint8
*)pinfo
->dst
.data
;
182 cksum_vec
[1].len
= pinfo
->dst
.len
;
183 cksum_vec
[2].ptr
= (const guint8
*)&phdr
;
184 phdr
[0] = g_htonl(vrrp_len
);
185 phdr
[1] = g_htonl(IP_PROTO_VRRP
);
186 cksum_vec
[2].len
= 8;
187 cksum_vec
[3].ptr
= tvb_get_ptr(tvb
, 0, vrrp_len
);
188 cksum_vec
[3].len
= vrrp_len
;
189 computed_cksum
= in_cksum(cksum_vec
, 4);
193 cksum_vec
[0].ptr
= tvb_get_ptr(tvb
, 0, vrrp_len
);
194 cksum_vec
[0].len
= vrrp_len
;
195 computed_cksum
= in_cksum(&cksum_vec
[0], 1);
199 if (computed_cksum
== 0) {
200 hidden_item
= proto_tree_add_boolean(vrrp_tree
, hf_vrrp_checksum_bad
, tvb
, offset
, 2, FALSE
);
201 PROTO_ITEM_SET_HIDDEN(hidden_item
);
202 proto_item_append_text(checksum_item
, " [correct]");
204 hidden_item
= proto_tree_add_boolean(vrrp_tree
, hf_vrrp_checksum_bad
, tvb
, offset
, 2, TRUE
);
205 PROTO_ITEM_SET_HIDDEN(hidden_item
);
206 proto_item_append_text(checksum_item
, " [incorrect, should be 0x%04x]", in_cksum_shouldbe(cksum
, computed_cksum
));
207 expert_add_info_format(pinfo
, checksum_item
, &ei_vrrp_checksum
,
208 "VRRP Checksum Incorrect, should be 0x%04x", in_cksum_shouldbe(cksum
, computed_cksum
));
214 while (addr_count
> 0) {
216 proto_tree_add_item(vrrp_tree
, hf_vrrp_ip6
, tvb
, offset
, 16, ENC_NA
);
219 proto_tree_add_item(vrrp_tree
, hf_vrrp_ip
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
225 if (auth_type
== VRRP_AUTH_TYPE_SIMPLE_TEXT
) {
226 proto_tree_add_item(vrrp_tree
, hf_vrrp_auth_string
, tvb
, offset
, VRRP_AUTH_DATA_LEN
, ENC_ASCII
|ENC_NA
);
227 offset
+= VRRP_AUTH_DATA_LEN
;
234 void proto_register_vrrp(void)
236 static hf_register_info hf
[] = {
238 {"VRRP message version and type", "vrrp.typever",
239 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
240 "VRRP version and type", HFILL
}},
243 {"VRRP protocol version", "vrrp.version",
244 FT_UINT8
, BASE_DEC
, NULL
, VRRP_VERSION_MASK
,
245 "VRRP version", HFILL
}},
248 {"VRRP packet type", "vrrp.type",
249 FT_UINT8
, BASE_DEC
, VALS(vrrp_type_vals
), VRRP_TYPE_MASK
,
250 "VRRP type", HFILL
}},
252 { &hf_vrrp_virt_rtr_id
,
253 {"Virtual Rtr ID", "vrrp.virt_rtr_id",
254 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
255 "Virtual router this packet is reporting status for", HFILL
}},
258 {"Priority", "vrrp.prio",
259 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
260 "Sending VRRP router's priority for the virtual router", HFILL
}},
262 { &hf_vrrp_addr_count
,
263 {"Addr Count", "vrrp.addr_count",
264 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
265 "The number of addresses contained in this VRRP advertisement", HFILL
}},
268 { "Checksum", "vrrp.checksum",
269 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
270 "Used to detect data corruption in the VRRP message", HFILL
}},
272 { &hf_vrrp_checksum_bad
,
273 { "Bad Checksum", "vrrp.checksum_bad",
274 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
277 { &hf_vrrp_auth_type
,
278 {"Auth Type", "vrrp.auth_type",
279 FT_UINT8
, BASE_DEC
, VALS(vrrp_auth_vals
), 0x0,
280 "The authentication method being utilized", HFILL
}},
282 { &hf_vrrp_adver_int
,
283 {"Adver Int", "vrrp.adver_int",
284 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
285 "Time interval (in seconds) between ADVERTISEMENTS", HFILL
}},
287 { &hf_vrrp_reserved_mbz
,
288 {"Reserved", "vrrp.reserved_mbz",
289 FT_UINT8
, BASE_DEC
, NULL
, 0xF0,
290 "Must be zero", HFILL
}},
292 { &hf_vrrp_short_adver_int
,
293 {"Adver Int", "vrrp.short_adver_int",
294 FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF,
295 "Time interval (in centiseconds) between ADVERTISEMENTS", HFILL
}},
298 {"IP Address", "vrrp.ip_addr",
299 FT_IPv4
, BASE_NONE
, NULL
, 0x0,
300 "IP address associated with the virtual router", HFILL
}},
303 {"IPv6 Address", "vrrp.ipv6_addr",
304 FT_IPv6
, BASE_NONE
, NULL
, 0x0,
305 "IPv6 address associated with the virtual router", HFILL
}},
307 { &hf_vrrp_auth_string
,
308 {"Authentification String", "vrrp.auth_string",
309 FT_STRING
, BASE_NONE
, NULL
, 0x0,
313 static gint
*ett
[] = {
318 static ei_register_info ei
[] = {
319 { &ei_vrrp_checksum
, { "vrrp.checksum_bad.expert", PI_CHECKSUM
, PI_WARN
, "Bad checksum", EXPFILL
}},
322 expert_module_t
* expert_vrrp
;
325 proto_vrrp
= proto_register_protocol("Virtual Router Redundancy Protocol",
327 proto_register_field_array(proto_vrrp
, hf
, array_length(hf
));
328 proto_register_subtree_array(ett
, array_length(ett
));
330 expert_vrrp
= expert_register_protocol(proto_vrrp
);
331 expert_register_field_array(expert_vrrp
, ei
, array_length(ei
));
336 proto_reg_handoff_vrrp(void)
338 dissector_handle_t vrrp_handle
;
340 vrrp_handle
= new_create_dissector_handle(dissect_vrrp
, proto_vrrp
);
341 dissector_add_uint("ip.proto", IP_PROTO_VRRP
, vrrp_handle
);
345 * Editor modelines - http://www.wireshark.org/tools/modelines.html
350 * indent-tabs-mode: nil
353 * vi: set shiftwidth=4 tabstop=8 expandtab:
354 * :indentSize=4:tabSize=8:noTabs=true: