wireshark/epan/dissectors/packet-babel.c
Michael Mann 2eb7b05b8c Convert most UDP dissectors to use "auto" preferences.
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67,
convert dissectors that use "udp.port".

More cleanup done on dissectors that use both TCP and UDP dissector
tables, so that less preference callbacks exist.

Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3
Reviewed-on: https://code.wireshark.org/review/18120
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-13 02:51:18 +00:00

544 lines
20 KiB
C

/* packet-babel.c
* Routines for Babel dissection (RFC 6126)
* Copyright 2011 by Juliusz Chroboczek <jch@pps.jussieu.fr>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/to_str.h>
void proto_register_babel(void);
void proto_reg_handoff_babel(void);
static int proto_babel = -1;
static gint ett_babel = -1;
static int hf_babel_magic = -1;
static int hf_babel_version = -1;
static int hf_babel_bodylen = -1;
static int hf_babel_message = -1;
static gint ett_message = -1;
static int hf_babel_message_type = -1;
static int hf_babel_message_length = -1;
static int hf_babel_message_nonce = -1;
static int hf_babel_message_interval = -1;
static int hf_babel_message_seqno = -1;
static int hf_babel_message_ae = -1;
static int hf_babel_message_prefix = -1;
static int hf_babel_message_rxcost = -1;
static int hf_babel_message_routerid = -1;
static int hf_babel_message_flags = -1;
static int hf_babel_message_plen = -1;
static int hf_babel_message_omitted = -1;
static int hf_babel_message_metric = -1;
static int hf_babel_message_hopcount = -1;
static gint ett_subtree = -1;
#define UDP_PORT_RANGE_BABEL "6696-6697" /* 6697 Not IANA registered, 6696 is */
#define MESSAGE_PAD1 0
#define MESSAGE_PADN 1
#define MESSAGE_ACK_REQ 2
#define MESSAGE_ACK 3
#define MESSAGE_HELLO 4
#define MESSAGE_IHU 5
#define MESSAGE_ROUTER_ID 6
#define MESSAGE_NH 7
#define MESSAGE_UPDATE 8
#define MESSAGE_REQUEST 9
#define MESSAGE_MH_REQUEST 10
#define MESSAGE_TS_PC 11
#define MESSAGE_HMAC 12
#define MESSAGE_SRC_UPDATE 13
#define MESSAGE_SRC_REQUEST 14
#define MESSAGE_SRC_SEQNO 15
/** message string values listed in rfc7557 */
static const value_string messages[] = {
{ MESSAGE_PAD1, "pad1"},
{ MESSAGE_PADN, "padn"},
{ MESSAGE_ACK_REQ, "ack-req"},
{ MESSAGE_ACK, "ack"},
{ MESSAGE_HELLO, "hello"},
{ MESSAGE_IHU, "ihu"},
{ MESSAGE_ROUTER_ID, "router-id"},
{ MESSAGE_NH, "nh"},
{ MESSAGE_UPDATE, "update"},
{ MESSAGE_REQUEST, "request"},
{ MESSAGE_MH_REQUEST, "mh-request"},
{ MESSAGE_TS_PC, "ts/pc"},
{ MESSAGE_HMAC, "hmac" },
{ MESSAGE_SRC_UPDATE, "source-specific-update"},
{ MESSAGE_SRC_REQUEST,"source-specific-req"},
{ MESSAGE_SRC_SEQNO, "source-specific-seqno"},
{ 0, NULL}
};
static const value_string aes[] = {
{ 0, "Wildcard" },
{ 1, "IPv4" },
{ 2, "IPv6" },
{ 3, "Link-Local IPv6"},
{ 0, NULL }
};
/* The prefix for v6-mapped IPv4 addresses. Format_address below
returns IPv4 addresses in that format. */
static const unsigned char v4prefix[16] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
/* The following two functions return ephemeral or constant strings, no
need to call free. */
static const char *
format_address(const unsigned char *prefix)
{
address addr;
if (prefix == NULL)
return "corrupt";
else if (memcmp(prefix, v4prefix, 12) == 0)
{
addr.type = AT_IPv4;
addr.len = 4;
addr.data = prefix + 12;
return address_to_str(wmem_packet_scope(), &addr);
}
else
{
addr.type = AT_IPv6;
addr.len = 16;
addr.data = prefix;
return address_to_str(wmem_packet_scope(), &addr);
}
}
static const char *
format_prefix(const unsigned char *prefix, unsigned char plen)
{
return wmem_strdup_printf(wmem_packet_scope(), "%s/%u", format_address(prefix), plen);
}
static int
network_prefix(int ae, int plen, unsigned int omitted,
tvbuff_t *tvb, int offset, const unsigned char *dp,
unsigned int len, unsigned char *p_r)
{
guint pb;
unsigned char prefix[16];
if (plen >= 0)
pb = (plen + 7) / 8;
else if (ae == 1)
pb = 4;
else
pb = 16;
if (pb > 16)
return -1;
memset(prefix, 0, 16);
switch(ae) {
case 0: break;
case 1:
if (omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
return -1;
memcpy(prefix, v4prefix, 12);
if (omitted) {
if (dp == NULL) return -1;
memcpy(prefix, dp, 12 + omitted);
}
if (pb > omitted)
tvb_memcpy(tvb, prefix + 12 + omitted, offset, pb - omitted);
break;
case 2:
if (omitted > 16 || (pb > omitted && len < pb - omitted))
return -1;
if (omitted) {
if (dp == NULL) return -1;
memcpy(prefix, dp, omitted);
}
if (pb > omitted)
tvb_memcpy(tvb, prefix + omitted, offset, pb - omitted);
break;
case 3:
if (pb > 8 && len < pb - 8) return -1;
prefix[0] = 0xfe;
prefix[1] = 0x80;
if (pb > 8)
tvb_memcpy(tvb, prefix + 8, offset, pb - 8);
break;
default:
return -1;
}
memcpy(p_r, prefix, 16);
return 1;
}
static int
network_address(int ae, tvbuff_t *tvb, int offset, unsigned int len,
unsigned char *a_r)
{
return network_prefix(ae, -1, 0, tvb, offset, NULL, len, a_r);
}
static int
dissect_babel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
proto_item *ti;
unsigned char v4_prefix[16] = {0}, v6_prefix[16] = {0};
int i;
proto_tree *babel_tree = NULL;
guint8 version;
guint16 bodylen;
if (tvb_captured_length(tvb) < 4)
return 0;
if (tvb_get_guint8(tvb, 0) != 42)
return 0;
version = tvb_get_guint8(tvb, 1);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Babel");
col_set_str(pinfo->cinfo, COL_INFO, "Babel");
if (version != 2) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Version %u", version);
return 2;
}
if (tree) {
ti = proto_tree_add_item(tree, proto_babel, tvb, 0, -1, ENC_NA);
babel_tree = proto_item_add_subtree(ti, ett_babel);
proto_tree_add_item(babel_tree, hf_babel_magic, tvb, 0, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(babel_tree, hf_babel_version, tvb, 1, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(babel_tree, hf_babel_bodylen,
tvb, 2, 2, ENC_BIG_ENDIAN);
}
bodylen = tvb_get_ntohs(tvb, 2);
i = 0;
while (i < bodylen) {
guint8 type, len = 0, total_length;
proto_tree *message_tree = NULL;
int message = 4 + i;
type = tvb_get_guint8(tvb, message);
if (type == MESSAGE_PAD1)
total_length = 1;
else {
len = tvb_get_guint8(tvb, message + 1);
total_length = len + 2;
}
col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
val_to_str_const(type, messages, "unknown"));
ti = proto_tree_add_uint_format(babel_tree, hf_babel_message,
tvb, message, total_length, type,
"Message %s (%u)",
val_to_str_const(type, messages, "unknown"),
type);
if (tree) {
message_tree = proto_item_add_subtree(ti, ett_message);
proto_tree_add_item(message_tree, hf_babel_message_type,
tvb, message, 1, ENC_BIG_ENDIAN);
}
if (type == MESSAGE_PAD1) {
i++;
continue;
}
if (tree) {
proto_tree_add_item(message_tree, hf_babel_message_length,
tvb, message + 1, 1, ENC_BIG_ENDIAN);
if (type == MESSAGE_PADN) {
} else if (type == MESSAGE_ACK_REQ) {
proto_tree_add_item(message_tree, hf_babel_message_nonce,
tvb, message + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_interval,
tvb, message + 6, 2, ENC_BIG_ENDIAN);
} else if (type == MESSAGE_ACK) {
proto_tree_add_item(message_tree, hf_babel_message_nonce,
tvb, message + 2, 2, ENC_BIG_ENDIAN);
} else if (type == MESSAGE_HELLO) {
proto_tree_add_item(message_tree, hf_babel_message_seqno,
tvb, message + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_interval,
tvb, message + 6, 2, ENC_BIG_ENDIAN);
} else if (type == MESSAGE_IHU) {
proto_tree *subtree;
unsigned char addr_str[16];
int rc =
network_address(tvb_get_guint8(tvb, message + 2),
tvb, message + 8, len - 6, addr_str);
proto_tree_add_item(message_tree, hf_babel_message_rxcost,
tvb, message + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_interval,
tvb, message + 6, 2, ENC_BIG_ENDIAN);
subtree = proto_tree_add_subtree_format(message_tree,
tvb, message + 4, len - 2,
ett_subtree, NULL, "Address: %s",
format_address(rc < 0 ?
NULL : addr_str));
proto_tree_add_item(subtree, hf_babel_message_ae,
tvb, message + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_prefix,
tvb, message + 4, len - 2, ENC_NA);
} else if (type == MESSAGE_ROUTER_ID) {
proto_tree_add_item(message_tree, hf_babel_message_routerid,
tvb, message + 4, 8, ENC_NA);
} else if (type == MESSAGE_NH) {
proto_tree *subtree;
unsigned char nh[16];
int rc =
network_address(tvb_get_guint8(tvb, message + 2),
tvb, message + 4, len - 2, nh);
subtree = proto_tree_add_subtree_format(message_tree,
tvb, message + 4, len - 2,
ett_subtree, NULL,
"NH: %s",
format_address(rc < 0 ? NULL : nh));
proto_tree_add_item(subtree, hf_babel_message_ae,
tvb, message + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_prefix,
tvb, message + 4, len - 2, ENC_NA);
} else if (type == MESSAGE_UPDATE) {
proto_tree *subtree;
unsigned char p[16];
guint8 ae = tvb_get_guint8(tvb, message + 2);
guint8 flags = tvb_get_guint8(tvb, message + 3);
guint8 plen = tvb_get_guint8(tvb, message + 4);
int rc =
network_prefix(ae, plen,
tvb_get_guint8(tvb, message + 5),
tvb, message + 12,
ae == 1 ? v4_prefix : v6_prefix,
len - 10, p);
if (rc >= 0 && (flags & 0x80)) {
if (ae == 1)
memcpy(v4_prefix, p, 16);
else
memcpy(v6_prefix, p, 16);
}
proto_tree_add_item(message_tree, hf_babel_message_flags,
tvb, message + 3, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_interval,
tvb, message + 6, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_seqno,
tvb, message + 8, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_metric,
tvb, message + 10, 2, ENC_BIG_ENDIAN);
subtree = proto_tree_add_subtree_format(message_tree,
tvb, message + 12, len - 10,
ett_subtree, NULL,
"Prefix: %s",
format_prefix(rc < 0 ? NULL : p,
plen));
proto_tree_add_item(subtree, hf_babel_message_ae,
tvb, message + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_plen,
tvb, message + 4, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_omitted,
tvb, message + 5, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_prefix,
tvb, message + 12, len - 10, ENC_NA);
} else if (type == MESSAGE_REQUEST) {
proto_tree *subtree;
unsigned char p[16];
guint8 plen = tvb_get_guint8(tvb, message + 3);
int rc =
network_prefix(tvb_get_guint8(tvb, message + 2), plen,
0, tvb, message + 4, NULL,
len - 2, p);
subtree = proto_tree_add_subtree_format(message_tree,
tvb, message + 4, len - 2,
ett_subtree, NULL,
"Prefix: %s",
format_prefix(rc < 0 ? NULL : p,
plen));
proto_tree_add_item(subtree, hf_babel_message_ae,
tvb, message + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_plen,
tvb, message + 3, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_prefix,
tvb, message + 4, len - 2, ENC_NA);
} else if (type == MESSAGE_MH_REQUEST) {
proto_tree *subtree;
unsigned char p[16];
guint8 plen = tvb_get_guint8(tvb, message + 3);
int rc =
network_prefix(tvb_get_guint8(tvb, message + 2), plen,
0, tvb, message + 16, NULL,
len - 14, p);
proto_tree_add_item(message_tree, hf_babel_message_seqno,
tvb, message + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_hopcount,
tvb, message + 6, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(message_tree, hf_babel_message_routerid,
tvb, message + 8, 8, ENC_NA);
subtree = proto_tree_add_subtree_format(message_tree,
tvb, message + 16, len - 14,
ett_subtree, NULL,
"Prefix: %s",
format_prefix(rc < 0 ? NULL : p,
plen));
proto_tree_add_item(subtree, hf_babel_message_ae,
tvb, message + 2, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_plen,
tvb, message + 3, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(subtree, hf_babel_message_prefix,
tvb, message + 16, len - 14, ENC_NA);
}
}
i += len + 2;
}
return i;
}
void
proto_register_babel(void)
{
static hf_register_info hf[] = {
{ &hf_babel_magic,
{ "Magic", "babel.magic", FT_UINT8, BASE_DEC,
NULL, 0, "Magic value 42", HFILL }
},
{ &hf_babel_version,
{ "Version", "babel.version", FT_UINT8, BASE_DEC,
NULL, 0, "Version of the Babel protocol", HFILL }
},
{ &hf_babel_bodylen,
{ "Body Length", "babel.bodylen", FT_UINT16, BASE_DEC,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message,
{ "Message", "babel.message", FT_UINT8, BASE_DEC,
NULL, 0, "Babel Message", HFILL }
},
{ &hf_babel_message_type,
{ "Message Type", "babel.message.type", FT_UINT8, BASE_DEC,
VALS(messages), 0, NULL, HFILL }
},
{ &hf_babel_message_length,
{ "Message Length", "babel.message.length", FT_UINT8, BASE_DEC,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_nonce,
{ "Nonce", "babel.message.nonce", FT_UINT16, BASE_HEX,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_interval,
{ "Interval", "babel.message.interval", FT_UINT16, BASE_DEC,
NULL, 0, "Interval (in centiseconds)", HFILL }
},
{ &hf_babel_message_seqno,
{ "Seqno", "babel.message.seqno", FT_UINT16, BASE_HEX,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_ae,
{ "Address Encoding", "babel.message.ae", FT_UINT8, BASE_DEC,
VALS(aes), 0, NULL, HFILL }
},
{ &hf_babel_message_prefix,
{ "Raw Prefix", "babel.message.prefix", FT_BYTES, BASE_NONE,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_rxcost,
{ "Rxcost", "babel.message.rxcost", FT_UINT16, BASE_HEX,
NULL, 0, "Rxcost (from the point of vue of the sender)", HFILL }
},
{ &hf_babel_message_routerid,
{ "Router ID", "babel.message.routerid", FT_BYTES, BASE_NONE,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_flags,
{ "Flags", "babel.message.flags", FT_UINT8, BASE_HEX,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_plen,
{ "Prefix Length", "babel.message.plen", FT_UINT8, BASE_DEC,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_omitted,
{ "Omitted Bytes", "babel.message.omitted", FT_UINT8, BASE_DEC,
NULL, 0, "Number of bytes omitted from the prefix", HFILL }
},
{ &hf_babel_message_metric,
{ "Metric", "babel.message.metric", FT_UINT16, BASE_DEC,
NULL, 0, NULL, HFILL }
},
{ &hf_babel_message_hopcount,
{ "Hop Count", "babel.message.hopcount", FT_UINT8, BASE_DEC,
NULL, 0, NULL, HFILL }
},
};
static gint *ett[] = {
&ett_babel,
&ett_message,
&ett_subtree,
};
proto_babel =
proto_register_protocol("Babel Routing Protocol", "Babel", "babel");
proto_register_field_array(proto_babel, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_babel(void)
{
dissector_handle_t babel_handle;
babel_handle = create_dissector_handle(dissect_babel, proto_babel);
dissector_add_uint_range_with_preference("udp.port", UDP_PORT_RANGE_BABEL, babel_handle);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* 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:
*/