2 * Routines for the Common Address Redundancy Protocol (CARP)
3 * Copyright 2013, Uli Heilmeier <uh@heilmeier.eu>
4 * Based on packet-vrrp.c by Heikki Vatiainen <hessu@cs.tut.fi>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
31 #include <epan/ipproto.h>
32 #include <epan/in_cksum.h>
34 static gint proto_carp
= -1;
35 static gint ett_carp
= -1;
36 static gint ett_carp_ver_type
= -1;
38 static gint hf_carp_ver_type
= -1;
39 static gint hf_carp_version
= -1;
40 static gint hf_carp_type
= -1;
41 static gint hf_carp_vhid
= -1;
42 static gint hf_carp_advskew
= -1;
43 static gint hf_carp_authlen
= -1;
44 static gint hf_carp_demotion
= -1;
45 static gint hf_carp_advbase
= -1;
46 static gint hf_carp_counter
= -1;
47 static gint hf_carp_hmac
= -1;
49 #define CARP_VERSION_MASK 0xf0
50 #define CARP_TYPE_MASK 0x0f
52 #define CARP_TYPE_ADVERTISEMENT 1
53 static const value_string carp_type_vals
[] = {
54 {CARP_TYPE_ADVERTISEMENT
, "Advertisement"},
59 test_carp_packet(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
, void *data _U_
)
61 guint8 ver_type
, version
, auth_length
;
63 /* First some simple check if the data is
65 if (tvb_length(tvb
) < 36)
68 /* Version must be 1 or 2, type must be in carp_type_vals */
69 ver_type
= tvb_get_guint8(tvb
, 0);
70 version
= hi_nibble(ver_type
);
71 if ((version
== 0) || (version
> 2) ||
72 (try_val_to_str(lo_nibble(ver_type
), carp_type_vals
) == NULL
))
75 auth_length
= tvb_get_guint8(tvb
, 3);
76 if ( auth_length
!= 7 )
83 dissect_carp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
90 proto_tree
*carp_tree
, *ver_type_tree
;
92 guint16 cksum
, computed_cksum
;
94 /* Make sure it's a CARP packet */
95 if (!test_carp_packet(tvb
, pinfo
, tree
, data
))
98 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CARP");
99 col_clear(pinfo
->cinfo
, COL_INFO
);
101 vhid
= tvb_get_guint8(tvb
, 1);
102 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s (Virtual Host ID: %u)",
103 "Announcement", vhid
);
105 ti
= proto_tree_add_item(tree
, proto_carp
, tvb
, 0, -1, ENC_NA
);
106 carp_tree
= proto_item_add_subtree(ti
, ett_carp
);
108 ver_type
= tvb_get_guint8(tvb
, 0);
109 tv
= proto_tree_add_uint_format(carp_tree
, hf_carp_ver_type
,
110 tvb
, offset
, 1, ver_type
,
111 "Version %u, Packet type %u (%s)",
112 hi_nibble(ver_type
), lo_nibble(ver_type
),
113 val_to_str_const(lo_nibble(ver_type
), carp_type_vals
, "Unknown"));
114 ver_type_tree
= proto_item_add_subtree(tv
, ett_carp_ver_type
);
115 proto_tree_add_uint(ver_type_tree
, hf_carp_version
, tvb
, offset
, 1, ver_type
);
116 proto_tree_add_uint(ver_type_tree
, hf_carp_type
, tvb
, offset
, 1, ver_type
);
119 proto_tree_add_item(carp_tree
, hf_carp_vhid
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
122 proto_tree_add_item(carp_tree
, hf_carp_advskew
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
125 proto_tree_add_item(carp_tree
, hf_carp_authlen
, tvb
,
129 proto_tree_add_item(carp_tree
, hf_carp_demotion
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
132 proto_tree_add_item(carp_tree
, hf_carp_advbase
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
135 cksum
= tvb_get_ntohs(tvb
, offset
);
136 carp_len
= (gint
)tvb_reported_length(tvb
);
137 if (!pinfo
->fragmented
&& (gint
)tvb_length(tvb
) >= carp_len
) {
138 /* The packet isn't part of a fragmented datagram
139 and isn't truncated, so we can checksum it. */
140 cksum_vec
[0].ptr
= tvb_get_ptr(tvb
, 0, carp_len
);
141 cksum_vec
[0].len
= carp_len
;
142 computed_cksum
= in_cksum(&cksum_vec
[0], 1);
143 if (computed_cksum
== 0) {
144 proto_tree_add_text(carp_tree
, tvb
, offset
, 2,
145 "Checksum: 0x%04x [correct]",
148 proto_tree_add_text(carp_tree
, tvb
, offset
, 2,
149 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
151 in_cksum_shouldbe(cksum
, computed_cksum
));
154 proto_tree_add_text(carp_tree
, tvb
, offset
, 2,
155 "Checksum: 0x%04x", cksum
);
160 proto_tree_add_item(carp_tree
, hf_carp_counter
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
163 proto_tree_add_item(carp_tree
, hf_carp_hmac
, tvb
, offset
, 20, ENC_ASCII
|ENC_NA
);
169 /* heuristic dissector */
171 dissect_carp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
173 if (!test_carp_packet(tvb
, pinfo
, tree
, data
))
176 dissect_carp(tvb
, pinfo
, tree
, data
);
180 void proto_register_carp(void)
182 static hf_register_info hf
[] = {
184 {"CARP message version and type", "carp.typever",
185 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
186 "CARP version and type", HFILL
}},
189 {"CARP protocol version", "carp.version",
190 FT_UINT8
, BASE_DEC
, NULL
, CARP_VERSION_MASK
,
191 "CARP version", HFILL
}},
194 {"CARP packet type", "carp.type",
195 FT_UINT8
, BASE_DEC
, VALS(carp_type_vals
), CARP_TYPE_MASK
,
196 "CARP type", HFILL
}},
199 {"Virtual Host ID", "carp.vhid",
200 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
204 {"Advertisment Skew", "carp.advskew",
205 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
209 {"Auth Len", "carp.authlen",
210 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
211 "Size of counter+hash in 32bit chunks", HFILL
}},
214 {"Demotion indicator", "carp.demotion",
215 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
219 {"Adver Int", "carp.adver_int",
220 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
221 "Time interval (in seconds) between ADVERTISEMENTS", HFILL
}},
223 { &hf_carp_counter
, {"Counter", "carp.counter",
224 FT_UINT64
, BASE_DEC
, NULL
, 0x0,
228 {"HMAC", "carp.hmac",
229 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
230 "SHA-1 HMAC", HFILL
}},
233 static gint
*ett
[] = {
238 proto_carp
= proto_register_protocol("Common Address Redundancy Protocol",
240 proto_register_field_array(proto_carp
, hf
, array_length(hf
));
241 proto_register_subtree_array(ett
, array_length(ett
));
245 proto_reg_handoff_carp(void)
247 dissector_handle_t carp_handle
;
249 carp_handle
= new_create_dissector_handle(dissect_carp
, proto_carp
);
250 dissector_add_uint("ip.proto", IP_PROTO_VRRP
, carp_handle
);
251 heur_dissector_add( "ip", dissect_carp_heur
, proto_carp
);
255 * Editor modelines - http://www.wireshark.org/tools/modelines.html
260 * indent-tabs-mode: nil
263 * vi: set shiftwidth=4 tabstop=8 expandtab:
264 * :indentSize=4:tabSize=8:noTabs=true: