2013-06-14 14:35:34 +00:00
|
|
|
/* packet-carp.c
|
|
|
|
* Routines for the Common Address Redundancy Protocol (CARP)
|
|
|
|
* Copyright 2013, Uli Heilmeier <uh@heilmeier.eu>
|
|
|
|
* Based on packet-vrrp.c by Heikki Vatiainen <hessu@cs.tut.fi>
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-12 11:23:27 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2013-06-14 14:35:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <epan/packet.h>
|
|
|
|
#include <epan/ipproto.h>
|
2016-07-21 14:21:25 +00:00
|
|
|
#include <epan/expert.h>
|
2013-06-14 14:35:34 +00:00
|
|
|
#include <epan/in_cksum.h>
|
|
|
|
|
2013-12-15 23:44:12 +00:00
|
|
|
void proto_register_carp(void);
|
|
|
|
void proto_reg_handoff_carp(void);
|
|
|
|
|
2013-06-14 14:35:34 +00:00
|
|
|
static gint proto_carp = -1;
|
|
|
|
static gint ett_carp = -1;
|
|
|
|
static gint ett_carp_ver_type = -1;
|
|
|
|
|
|
|
|
static gint hf_carp_ver_type = -1;
|
|
|
|
static gint hf_carp_version = -1;
|
|
|
|
static gint hf_carp_type = -1;
|
|
|
|
static gint hf_carp_vhid = -1;
|
|
|
|
static gint hf_carp_advskew = -1;
|
|
|
|
static gint hf_carp_authlen = -1;
|
|
|
|
static gint hf_carp_demotion = -1;
|
|
|
|
static gint hf_carp_advbase = -1;
|
|
|
|
static gint hf_carp_counter = -1;
|
|
|
|
static gint hf_carp_hmac = -1;
|
2014-08-01 14:08:57 +00:00
|
|
|
static gint hf_carp_checksum = -1;
|
2016-07-21 14:21:25 +00:00
|
|
|
static gint hf_carp_checksum_status = -1;
|
|
|
|
|
|
|
|
static expert_field ei_carp_checksum = EI_INIT;
|
2013-06-14 14:35:34 +00:00
|
|
|
|
|
|
|
#define CARP_VERSION_MASK 0xf0
|
|
|
|
#define CARP_TYPE_MASK 0x0f
|
|
|
|
|
|
|
|
#define CARP_TYPE_ADVERTISEMENT 1
|
|
|
|
static const value_string carp_type_vals[] = {
|
|
|
|
{CARP_TYPE_ADVERTISEMENT, "Advertisement"},
|
|
|
|
{0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean
|
2013-06-14 14:56:00 +00:00
|
|
|
test_carp_packet(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_)
|
2013-06-14 14:35:34 +00:00
|
|
|
{
|
|
|
|
guint8 ver_type, version, auth_length;
|
|
|
|
|
2013-10-13 19:56:52 +00:00
|
|
|
/* First some simple check if the data is
|
2013-06-14 14:35:34 +00:00
|
|
|
really CARP */
|
2015-04-16 11:31:57 +00:00
|
|
|
if (tvb_captured_length(tvb) < 36)
|
2013-06-14 14:35:34 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Version must be 1 or 2, type must be in carp_type_vals */
|
|
|
|
ver_type = tvb_get_guint8(tvb, 0);
|
|
|
|
version = hi_nibble(ver_type);
|
|
|
|
if ((version == 0) || (version > 2) ||
|
|
|
|
(try_val_to_str(lo_nibble(ver_type), carp_type_vals) == NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
auth_length = tvb_get_guint8(tvb, 3);
|
|
|
|
if ( auth_length != 7 )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-12-10 03:11:34 +00:00
|
|
|
dissect_carp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
2013-06-14 14:35:34 +00:00
|
|
|
{
|
|
|
|
int offset = 0;
|
Clean up Internet checksum handling.
Add macros to set entries of a vec_t, one for use when you have a
pointer to private data, and one for use when you have data in a tvbuff.
The latter wraps the use of tvb_get_ptr(), so that you're not directly
calling it in a dissector.
Move ip_checksum() to epan/in_cksum.c, and add an ip_checksum_tvb() that
wraps the use of tvb_get_ptr().
In the CARP dissector, give the length variable an unsigned type -
there's no benefit to it being signed, and that requires some casts to
be thrown around.
In the DCCP dissector, check only against the coverage length to see if
we have enough data, combine the "should we check the checksum?" check
with the "*can* we check the checksum?" check in a single if, and throw
a dissector assertion if the source network address type isn't IPv4 or
IPv6.
Get rid of inclues of <epan/in_cksum.h> in dissectors that don't use any
of the Internet checksum routines.
In the HIP dissector, make sure we have the data to calculate the
checksum before doing so.
Change-Id: I2f9674775dbb54c533d33082632809f7d32ec8ae
Reviewed-on: https://code.wireshark.org/review/3517
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-08-09 01:09:00 +00:00
|
|
|
guint carp_len;
|
2013-06-14 14:35:34 +00:00
|
|
|
guint8 vhid;
|
|
|
|
vec_t cksum_vec[4];
|
|
|
|
proto_item *ti, *tv;
|
|
|
|
proto_tree *carp_tree, *ver_type_tree;
|
|
|
|
guint8 ver_type;
|
|
|
|
|
|
|
|
/* Make sure it's a CARP packet */
|
|
|
|
if (!test_carp_packet(tvb, pinfo, tree, data))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CARP");
|
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
|
|
|
|
|
|
vhid = tvb_get_guint8(tvb, 1);
|
|
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "%s (Virtual Host ID: %u)",
|
|
|
|
"Announcement", vhid);
|
|
|
|
|
|
|
|
ti = proto_tree_add_item(tree, proto_carp, tvb, 0, -1, ENC_NA);
|
|
|
|
carp_tree = proto_item_add_subtree(ti, ett_carp);
|
|
|
|
|
|
|
|
ver_type = tvb_get_guint8(tvb, 0);
|
|
|
|
tv = proto_tree_add_uint_format(carp_tree, hf_carp_ver_type,
|
|
|
|
tvb, offset, 1, ver_type,
|
|
|
|
"Version %u, Packet type %u (%s)",
|
|
|
|
hi_nibble(ver_type), lo_nibble(ver_type),
|
|
|
|
val_to_str_const(lo_nibble(ver_type), carp_type_vals, "Unknown"));
|
|
|
|
ver_type_tree = proto_item_add_subtree(tv, ett_carp_ver_type);
|
|
|
|
proto_tree_add_uint(ver_type_tree, hf_carp_version, tvb, offset, 1, ver_type);
|
|
|
|
proto_tree_add_uint(ver_type_tree, hf_carp_type, tvb, offset, 1, ver_type);
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_vhid, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_advskew, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_authlen, tvb,
|
2014-12-13 17:52:20 +00:00
|
|
|
offset, 1, ENC_BIG_ENDIAN);
|
2013-06-14 14:35:34 +00:00
|
|
|
offset++;
|
|
|
|
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_demotion, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_advbase, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
offset++;
|
|
|
|
|
Clean up Internet checksum handling.
Add macros to set entries of a vec_t, one for use when you have a
pointer to private data, and one for use when you have data in a tvbuff.
The latter wraps the use of tvb_get_ptr(), so that you're not directly
calling it in a dissector.
Move ip_checksum() to epan/in_cksum.c, and add an ip_checksum_tvb() that
wraps the use of tvb_get_ptr().
In the CARP dissector, give the length variable an unsigned type -
there's no benefit to it being signed, and that requires some casts to
be thrown around.
In the DCCP dissector, check only against the coverage length to see if
we have enough data, combine the "should we check the checksum?" check
with the "*can* we check the checksum?" check in a single if, and throw
a dissector assertion if the source network address type isn't IPv4 or
IPv6.
Get rid of inclues of <epan/in_cksum.h> in dissectors that don't use any
of the Internet checksum routines.
In the HIP dissector, make sure we have the data to calculate the
checksum before doing so.
Change-Id: I2f9674775dbb54c533d33082632809f7d32ec8ae
Reviewed-on: https://code.wireshark.org/review/3517
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-08-09 01:09:00 +00:00
|
|
|
carp_len = tvb_reported_length(tvb);
|
2015-04-16 11:31:57 +00:00
|
|
|
if (!pinfo->fragmented && tvb_captured_length(tvb) >= carp_len) {
|
2013-06-14 14:35:34 +00:00
|
|
|
/* The packet isn't part of a fragmented datagram
|
|
|
|
and isn't truncated, so we can checksum it. */
|
Clean up Internet checksum handling.
Add macros to set entries of a vec_t, one for use when you have a
pointer to private data, and one for use when you have data in a tvbuff.
The latter wraps the use of tvb_get_ptr(), so that you're not directly
calling it in a dissector.
Move ip_checksum() to epan/in_cksum.c, and add an ip_checksum_tvb() that
wraps the use of tvb_get_ptr().
In the CARP dissector, give the length variable an unsigned type -
there's no benefit to it being signed, and that requires some casts to
be thrown around.
In the DCCP dissector, check only against the coverage length to see if
we have enough data, combine the "should we check the checksum?" check
with the "*can* we check the checksum?" check in a single if, and throw
a dissector assertion if the source network address type isn't IPv4 or
IPv6.
Get rid of inclues of <epan/in_cksum.h> in dissectors that don't use any
of the Internet checksum routines.
In the HIP dissector, make sure we have the data to calculate the
checksum before doing so.
Change-Id: I2f9674775dbb54c533d33082632809f7d32ec8ae
Reviewed-on: https://code.wireshark.org/review/3517
Reviewed-by: Guy Harris <guy@alum.mit.edu>
2014-08-09 01:09:00 +00:00
|
|
|
SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, carp_len);
|
2016-07-21 14:21:25 +00:00
|
|
|
proto_tree_add_checksum(carp_tree, tvb, offset, hf_carp_checksum, hf_carp_checksum_status, &ei_carp_checksum, pinfo, in_cksum(&cksum_vec[0], 1),
|
2016-07-11 03:47:28 +00:00
|
|
|
ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
|
|
|
|
} else {
|
2016-07-21 14:21:25 +00:00
|
|
|
proto_tree_add_checksum(carp_tree, tvb, offset, hf_carp_checksum, hf_carp_checksum_status, &ei_carp_checksum, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
|
2013-06-14 14:35:34 +00:00
|
|
|
}
|
2014-08-01 14:08:57 +00:00
|
|
|
|
2013-06-14 14:35:34 +00:00
|
|
|
offset+=2;
|
|
|
|
|
|
|
|
/* Counter */
|
|
|
|
proto_tree_add_item(carp_tree, hf_carp_counter, tvb, offset, 8, ENC_BIG_ENDIAN);
|
|
|
|
offset+=8;
|
|
|
|
|
2014-09-19 01:18:34 +00:00
|
|
|
proto_tree_add_item(carp_tree, hf_carp_hmac, tvb, offset, 20, ENC_NA);
|
2013-06-14 14:35:34 +00:00
|
|
|
offset+=20;
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* heuristic dissector */
|
|
|
|
static gboolean
|
|
|
|
dissect_carp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
2013-06-14 15:08:10 +00:00
|
|
|
{
|
2013-06-14 14:35:34 +00:00
|
|
|
if (!test_carp_packet(tvb, pinfo, tree, data))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
dissect_carp(tvb, pinfo, tree, data);
|
2013-06-14 15:08:10 +00:00
|
|
|
return TRUE;
|
2013-06-14 14:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void proto_register_carp(void)
|
|
|
|
{
|
|
|
|
static hf_register_info hf[] = {
|
|
|
|
{ &hf_carp_ver_type,
|
|
|
|
{"CARP message version and type", "carp.typever",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"CARP version and type", HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_version,
|
|
|
|
{"CARP protocol version", "carp.version",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, CARP_VERSION_MASK,
|
|
|
|
"CARP version", HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_type,
|
|
|
|
{"CARP packet type", "carp.type",
|
|
|
|
FT_UINT8, BASE_DEC, VALS(carp_type_vals), CARP_TYPE_MASK,
|
|
|
|
"CARP type", HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_vhid,
|
|
|
|
{"Virtual Host ID", "carp.vhid",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
NULL, HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_advskew,
|
2016-10-27 16:15:04 +00:00
|
|
|
{"Advertisement Skew", "carp.advskew",
|
2013-06-14 14:35:34 +00:00
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
NULL, HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_authlen,
|
|
|
|
{"Auth Len", "carp.authlen",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"Size of counter+hash in 32bit chunks", HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_demotion,
|
|
|
|
{"Demotion indicator", "carp.demotion",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
NULL, HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_advbase,
|
|
|
|
{"Adver Int", "carp.adver_int",
|
|
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
|
|
"Time interval (in seconds) between ADVERTISEMENTS", HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_counter, {"Counter", "carp.counter",
|
|
|
|
FT_UINT64, BASE_DEC, NULL, 0x0,
|
|
|
|
NULL, HFILL }},
|
|
|
|
|
|
|
|
{ &hf_carp_hmac,
|
|
|
|
{"HMAC", "carp.hmac",
|
|
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
|
|
"SHA-1 HMAC", HFILL }},
|
2014-08-01 14:08:57 +00:00
|
|
|
|
|
|
|
{ &hf_carp_checksum,
|
|
|
|
{"Checksum", "carp.checksum",
|
|
|
|
FT_UINT16, BASE_HEX, NULL, 0x0,
|
|
|
|
NULL, HFILL }},
|
2016-07-21 14:21:25 +00:00
|
|
|
|
|
|
|
{ &hf_carp_checksum_status,
|
|
|
|
{"Checksum Status", "carp.checksum.status",
|
|
|
|
FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
|
|
|
|
NULL, HFILL }},
|
2013-06-14 14:35:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static gint *ett[] = {
|
|
|
|
&ett_carp,
|
|
|
|
&ett_carp_ver_type
|
|
|
|
};
|
|
|
|
|
2016-07-21 14:21:25 +00:00
|
|
|
static ei_register_info ei[] = {
|
|
|
|
{ &ei_carp_checksum, { "carp.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
|
|
|
|
};
|
|
|
|
|
|
|
|
expert_module_t* expert_carp;
|
|
|
|
|
|
|
|
proto_carp = proto_register_protocol("Common Address Redundancy Protocol", "CARP", "carp");
|
2013-06-14 14:35:34 +00:00
|
|
|
proto_register_field_array(proto_carp, hf, array_length(hf));
|
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
2016-07-21 14:21:25 +00:00
|
|
|
expert_carp = expert_register_protocol(proto_carp);
|
|
|
|
expert_register_field_array(expert_carp, ei, array_length(ei));
|
2013-06-14 14:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
proto_reg_handoff_carp(void)
|
|
|
|
{
|
|
|
|
dissector_handle_t carp_handle;
|
|
|
|
|
2015-12-09 03:49:44 +00:00
|
|
|
carp_handle = create_dissector_handle(dissect_carp, proto_carp);
|
2013-06-14 14:35:34 +00:00
|
|
|
dissector_add_uint("ip.proto", IP_PROTO_VRRP, carp_handle);
|
2015-07-13 00:40:31 +00:00
|
|
|
heur_dissector_add( "ip", dissect_carp_heur, "CARP over IP", "carp_ip", proto_carp, HEURISTIC_ENABLE);
|
2013-06-14 14:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-07-26 18:43:17 +00:00
|
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
2013-06-14 14:35:34 +00:00
|
|
|
*
|
|
|
|
* Local variables:
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 8
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* End:
|
|
|
|
*
|
|
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
|
|
*/
|