wireshark/epan/dissectors/packet-zebra.c
Michael Mann 268841f3e0 Combine Decode As and port preferences for tcp.port dissector table.
This patch introduces new APIs to allow dissectors to have a preference for
a (TCP) port, but the underlying data is actually part of Decode As functionality.
For now the APIs are intentionally separate from the regular APIs that register a
dissector within a dissector table.  It may be possible to eventually combine the
two so that all dissectors that register with a dissector table have an opportunity
to "automatically" have a preference to adjust the "table value" through the
preferences dialog.

The tcp.port dissector table was used as the guinea pig.  This will eventually be
expanded to other dissector tables as well (most notably UDP ports).  Some
dissectors that "shared" a TCP/UDP port preference were also converted. It also
removed the need for some preference callback functions (mostly when the callback
function was the proto_reg_handoff function) so there is cleanup around that.

Dissectors that has a port preference whose default was 0 were switched to using
the dissector_add_for_decode_as_with_preference API rather than dissector_add_uint_with_preference

Also added comments for TCP ports used that aren't IANA registered.

Change-Id: I99604f95d426ad345f4b494598d94178b886eb67
Reviewed-on: https://code.wireshark.org/review/17724
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-08 02:44:53 +00:00

897 lines
28 KiB
C

/* packet-zebra.c
* Routines for zebra packet disassembly
*
* Jochen Friedrich <jochen@scram.de>
*
* 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.
*/
/*
* The Zebra Protocol is the protocol used between the Zebra routing daemon and other
* protocol daemons (ones for BGP, OSPF, etc.) within the Zebra and Quagga open-source
* routing suites. Zebra itself (https://www.gnu.org/software/zebra) is discontinued,
* and its successor is Quagga (http://www.nongnu.org/quagga).
*
* Both Zebra and Quagga use a "Zebra Protocol", but starting with Quagga v0.99 the
* Zebra Protocol has changed, with a different header format and more commands/types.
* Quagga 0.99.0 was version 1, and 0.99.20 or so changed it to version 2.
*
* See http://www.nongnu.org/quagga/docs/docs-info.html#Zebra-Protocol for some details.
*/
#include "config.h"
#include <epan/packet.h>
/* Function declarations */
void proto_reg_handoff_zebra(void);
void proto_register_zebra(void);
static int proto_zebra = -1;
static int hf_zebra_len = -1;
static int hf_zebra_command = -1;
static int hf_zebra_request = -1;
static int hf_zebra_interface = -1;
static int hf_zebra_index = -1;
static int hf_zebra_indexnum = -1;
static int hf_zebra_type_v0 = -1;
static int hf_zebra_type_v1 = -1;
static int hf_zebra_intflags = -1;
static int hf_zebra_rtflags = -1;
static int hf_zebra_distance = -1;
static int hf_zebra_metric = -1;
static int hf_zebra_mtu = -1;
static int hf_zebra_mtu6 = -1;
static int hf_zebra_bandwidth = -1;
static int hf_zebra_family = -1;
static int hf_zebra_flags = -1;
static int hf_zebra_message = -1;
static int hf_zebra_route_safi = -1;
static int hf_zebra_msg_nexthop = -1;
static int hf_zebra_msg_index = -1;
static int hf_zebra_msg_distance = -1;
static int hf_zebra_msg_metric = -1;
static int hf_zebra_nexthopnum = -1;
static int hf_zebra_nexthop4 = -1;
static int hf_zebra_nexthop6 = -1;
static int hf_zebra_dest4 = -1;
static int hf_zebra_dest6 = -1;
static int hf_zebra_prefixlen = -1;
static int hf_zebra_prefix4 = -1;
static int hf_zebra_prefix6 = -1;
static int hf_zebra_version = -1;
static int hf_zebra_marker = -1;
static int hf_zebra_intstatus = -1;
static int hf_zebra_routeridaddress = -1;
static int hf_zebra_routeridmask = -1;
static int hf_zebra_mac = -1;
static int hf_zebra_redist_default = -1;
static gint ett_zebra = -1;
static gint ett_zebra_request = -1;
static gint ett_message = -1;
#define TCP_PORT_ZEBRA 2600 /* Not IANA registered */
/* Zebra message types. */
#define ZEBRA_INTERFACE_ADD 1
#define ZEBRA_INTERFACE_DELETE 2
#define ZEBRA_INTERFACE_ADDRESS_ADD 3
#define ZEBRA_INTERFACE_ADDRESS_DELETE 4
#define ZEBRA_INTERFACE_UP 5
#define ZEBRA_INTERFACE_DOWN 6
#define ZEBRA_IPV4_ROUTE_ADD 7
#define ZEBRA_IPV4_ROUTE_DELETE 8
#define ZEBRA_IPV6_ROUTE_ADD 9
#define ZEBRA_IPV6_ROUTE_DELETE 10
#define ZEBRA_REDISTRIBUTE_ADD 11
#define ZEBRA_REDISTRIBUTE_DELETE 12
#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13
#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15
#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16
#define ZEBRA_IPV4_IMPORT_LOOKUP 17
#define ZEBRA_IPV6_IMPORT_LOOKUP 18
#define ZEBRA_INTERFACE_RENAME 19
#define ZEBRA_ROUTER_ID_ADD 20
#define ZEBRA_ROUTER_ID_DELETE 21
#define ZEBRA_ROUTER_ID_UPDATE 22
#define ZEBRA_HELLO 23
static const value_string messages[] = {
{ ZEBRA_INTERFACE_ADD, "Add Interface" },
{ ZEBRA_INTERFACE_DELETE, "Delete Interface" },
{ ZEBRA_INTERFACE_ADDRESS_ADD, "Add Interface Address" },
{ ZEBRA_INTERFACE_ADDRESS_DELETE, "Delete Interface Address" },
{ ZEBRA_INTERFACE_UP, "Interface Up" },
{ ZEBRA_INTERFACE_DOWN, "Interface Down" },
{ ZEBRA_IPV4_ROUTE_ADD, "Add IPv4 Route" },
{ ZEBRA_IPV4_ROUTE_DELETE, "Delete IPv4 Route" },
{ ZEBRA_IPV6_ROUTE_ADD, "Add IPv6 Route" },
{ ZEBRA_IPV6_ROUTE_DELETE, "Delete IPv6 Route" },
{ ZEBRA_REDISTRIBUTE_ADD, "Add Redistribute" },
{ ZEBRA_REDISTRIBUTE_DELETE, "Delete Redistribute" },
{ ZEBRA_REDISTRIBUTE_DEFAULT_ADD, "Add Default Redistribute" },
{ ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, "Delete Default Redistribute" },
{ ZEBRA_IPV4_NEXTHOP_LOOKUP, "IPv4 Nexthop Lookup" },
{ ZEBRA_IPV6_NEXTHOP_LOOKUP, "IPv6 Nexthop Lookup" },
{ ZEBRA_IPV4_IMPORT_LOOKUP, "IPv4 Import Lookup" },
{ ZEBRA_IPV6_IMPORT_LOOKUP, "IPv6 Import Lookup" },
{ ZEBRA_INTERFACE_RENAME, "Rename Interface" },
{ ZEBRA_ROUTER_ID_ADD, "Router ID Add" },
{ ZEBRA_ROUTER_ID_DELETE, "Router ID Delete" },
{ ZEBRA_ROUTER_ID_UPDATE, "Router ID Update" },
{ ZEBRA_HELLO, "Hello" },
{ 0, NULL },
};
/* Zebra route's types. */
#define ZEBRA_ROUTE_SYSTEM 0
#define ZEBRA_ROUTE_KERNEL 1
#define ZEBRA_ROUTE_CONNECT 2
#define ZEBRA_ROUTE_STATIC 3
#define ZEBRA_ROUTE_RIP 4
#define ZEBRA_ROUTE_RIPNG 5
#define ZEBRA_ROUTE_OSPF 6
#define ZEBRA_ROUTE_OSPF6 7
#define ZEBRA_ROUTE_BGP 8
static const value_string routes_v0[] = {
{ ZEBRA_ROUTE_SYSTEM, "System Route" },
{ ZEBRA_ROUTE_KERNEL, "Kernel Route" },
{ ZEBRA_ROUTE_CONNECT, "Connected Route" },
{ ZEBRA_ROUTE_STATIC, "Static Route" },
{ ZEBRA_ROUTE_RIP, "RIP Route" },
{ ZEBRA_ROUTE_RIPNG, "RIPnG Route" },
{ ZEBRA_ROUTE_OSPF, "OSPF Route" },
{ ZEBRA_ROUTE_OSPF6, "OSPF6 Route" },
{ ZEBRA_ROUTE_BGP, "BGP Route" },
{ 0, NULL },
};
/*
* In Quagga, ISIS is type 8 and BGP is type 9, but Zebra didn't have ISIS...
* so for Zebra BGP is type 8. So we dup the value_string table for quagga.
*/
#define QUAGGA_ROUTE_ISIS 8
#define QUAGGA_ROUTE_BGP 9
#define QUAGGA_ROUTE_HSLS 10
#define QUAGGA_ROUTE_OLSR 11
#define QUAGGA_ROUTE_BABEL 12
static const value_string routes_v1[] = {
{ ZEBRA_ROUTE_SYSTEM, "System Route" },
{ ZEBRA_ROUTE_KERNEL, "Kernel Route" },
{ ZEBRA_ROUTE_CONNECT, "Connected Route" },
{ ZEBRA_ROUTE_STATIC, "Static Route" },
{ ZEBRA_ROUTE_RIP, "RIP Route" },
{ ZEBRA_ROUTE_RIPNG, "RIPnG Route" },
{ ZEBRA_ROUTE_OSPF, "OSPF Route" },
{ ZEBRA_ROUTE_OSPF6, "OSPF6 Route" },
{ QUAGGA_ROUTE_ISIS, "ISIS Route" },
{ QUAGGA_ROUTE_BGP, "BGP Route" },
{ QUAGGA_ROUTE_HSLS, "HSLS Route" },
{ QUAGGA_ROUTE_OLSR, "OLSR Route" },
{ QUAGGA_ROUTE_BABEL, "BABEL Route" },
{ 0, NULL },
};
/* Zebra's family types. */
#define ZEBRA_FAMILY_IPV4 2
#define ZEBRA_FAMILY_IPV6 10
static const value_string families[] = {
{ ZEBRA_FAMILY_IPV4, "IPv4" },
{ ZEBRA_FAMILY_IPV6, "IPv6" },
{ 0, NULL },
};
/* Zebra message flags */
#define ZEBRA_FLAG_INTERNAL 0x01
#define ZEBRA_FLAG_SELFROUTE 0x02
#define ZEBRA_FLAG_BLACKHOLE 0x04
/* Zebra API message flag. */
#define ZEBRA_ZAPI_MESSAGE_NEXTHOP 0x01
#define ZEBRA_ZAPI_MESSAGE_IFINDEX 0x02
#define ZEBRA_ZAPI_MESSAGE_DISTANCE 0x04
#define ZEBRA_ZAPI_MESSAGE_METRIC 0x08
/* Zebra NextHop Types */
#define ZEBRA_NEXTHOP_TYPE_IFINDEX 0x01
#define ZEBRA_NEXTHOP_TYPE_IFNAME 0x02
#define ZEBRA_NEXTHOP_TYPE_IPV4 0x03
#define ZEBRA_NEXTHOP_TYPE_IPV4_IFINDEX 0x04
#define ZEBRA_NEXTHOP_TYPE_IPV4_IFNAME 0x05
#define ZEBRA_NEXTHOP_TYPE_IPV6 0x06
#define ZEBRA_NEXTHOP_TYPE_IPV6_IFINDEX 0x07
#define ZEBRA_NEXTHOP_TYPE_IPV6_IFNAME 0x08
/* Subsequent Address Family Identifier. */
#define ZEBRA_SAFI_UNICAST 1
#define ZEBRA_SAFI_MULTICAST 2
#define ZEBRA_SAFI_RESERVED_3 3
#define ZEBRA_SAFI_MPLS_VPN 4
static const value_string safi[] = {
{ ZEBRA_SAFI_UNICAST, "Unicast" },
{ ZEBRA_SAFI_MULTICAST, "Multicast" },
{ ZEBRA_SAFI_RESERVED_3, "Reserved" },
{ ZEBRA_SAFI_MPLS_VPN, "MPLS VPN" },
{ 0, NULL },
};
#define INTERFACE_NAMSIZ 20
#define PSIZE(a) (((a) + 7) / (8))
static int
zebra_route_nexthop(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 len)
{
guint8 nexthoptype, nexthopcount, interfacenamelength;
nexthopcount = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_zebra_nexthopnum,
tvb, offset, 1, nexthopcount);
offset += 1;
if (nexthopcount > len)
return offset; /* Sanity */
while (nexthopcount--) {
nexthoptype = tvb_get_guint8(tvb, offset);
offset += 1;
if (nexthoptype == ZEBRA_NEXTHOP_TYPE_IFINDEX ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV4_IFINDEX ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV6_IFINDEX){
proto_tree_add_item(tree,hf_zebra_index, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
if (nexthoptype == ZEBRA_NEXTHOP_TYPE_IFNAME ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV4_IFNAME ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV6_IFNAME) {
interfacenamelength = tvb_get_guint8(tvb, offset);
offset += 1;
proto_tree_add_item(tree, hf_zebra_interface,
tvb, offset, interfacenamelength,
ENC_ASCII|ENC_NA);
offset += interfacenamelength;
}
if (nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV6 ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV6_IFINDEX ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV6_IFNAME) {
proto_tree_add_item(tree, hf_zebra_nexthop6,
tvb, offset, 16, ENC_NA);
offset += 16;
}
if (nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV4 ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV4_IFINDEX ||
nexthoptype == ZEBRA_NEXTHOP_TYPE_IPV4_IFNAME) {
proto_tree_add_item(tree, hf_zebra_nexthop4,
tvb, offset, 4, ENC_NA);
offset += 4;
}
}
return offset;
}
static int
zebra_route_ifindex(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 len)
{
guint16 indexcount = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_zebra_indexnum,
tvb, offset, 1, indexcount);
offset += 1;
if (indexcount > len)
return offset; /* Sanity */
while (indexcount--) {
proto_tree_add_item(tree, hf_zebra_index, tvb, offset, 4,
ENC_BIG_ENDIAN);
offset += 4;
}
return offset;
}
static guint8
zebra_route_message(proto_tree *tree, tvbuff_t *tvb, int offset)
{
static const int * flags[] = {
&hf_zebra_msg_nexthop,
&hf_zebra_msg_index,
&hf_zebra_msg_distance,
&hf_zebra_msg_metric,
NULL
};
proto_tree_add_bitmask(tree, tvb, offset, hf_zebra_message, ett_message, flags, ENC_NA);
offset += 1;
return offset;
}
static int
zebra_route(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 len,
guint8 family, guint8 version)
{
guint32 prefix4;
guint8 message, prefixlen, buffer6[16];
if (version == 0) {
proto_tree_add_item(tree, hf_zebra_type_v0, tvb,
offset, 1, ENC_BIG_ENDIAN);
} else {
proto_tree_add_item(tree, hf_zebra_type_v1, tvb,
offset, 1, ENC_BIG_ENDIAN);
}
offset += 1;
proto_tree_add_item(tree, hf_zebra_rtflags, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
message = tvb_get_guint8(tvb, offset);
offset = zebra_route_message(tree, tvb, offset);
if (version > 1) {
/* version 2 added safi */
proto_tree_add_item(tree, hf_zebra_route_safi, tvb,
offset, 2, ENC_BIG_ENDIAN);
offset += 2;
}
prefixlen = tvb_get_guint8(tvb, offset);
proto_tree_add_uint(tree, hf_zebra_prefixlen, tvb,
offset, 1, prefixlen);
offset += 1;
if (family == ZEBRA_FAMILY_IPV6) {
memset(buffer6, '\0', sizeof buffer6);
tvb_memcpy(tvb, buffer6, offset,
MIN((unsigned) PSIZE(prefixlen), sizeof buffer6));
proto_tree_add_ipv6(tree, hf_zebra_prefix6,
tvb, offset, PSIZE(prefixlen), (struct e_in6_addr *)buffer6);
}else {
prefix4 = 0;
tvb_memcpy(tvb, (guint8 *)&prefix4, offset,
MIN((unsigned) PSIZE(prefixlen), sizeof prefix4));
proto_tree_add_ipv4(tree, hf_zebra_prefix4,
tvb, offset, PSIZE(prefixlen), prefix4);
}
offset += PSIZE(prefixlen);
if (message & ZEBRA_ZAPI_MESSAGE_NEXTHOP) {
offset = zebra_route_nexthop(tree, tvb, offset, len);
}
if (message & ZEBRA_ZAPI_MESSAGE_IFINDEX) {
offset = zebra_route_ifindex(tree, tvb, offset, len);
}
if (message & ZEBRA_ZAPI_MESSAGE_DISTANCE) {
proto_tree_add_item(tree, hf_zebra_distance,
tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
}
if (message & ZEBRA_ZAPI_MESSAGE_METRIC) {
proto_tree_add_item(tree, hf_zebra_metric,
tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
return offset;
}
static int
zebra_interface_address(proto_tree *tree, tvbuff_t *tvb, int offset)
{
guint8 family;
proto_tree_add_item(tree, hf_zebra_index, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_zebra_flags, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
proto_tree_add_item(tree, hf_zebra_family, tvb,
offset, 1, ENC_BIG_ENDIAN);
family = tvb_get_guint8(tvb, offset);
offset += 1;
if (family == ZEBRA_FAMILY_IPV4) {
proto_tree_add_item(tree, hf_zebra_prefix4,
tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
else if (family == ZEBRA_FAMILY_IPV6) {
proto_tree_add_item(tree, hf_zebra_prefix6,
tvb, offset, 16, ENC_NA);
offset += 16;
}
else
return offset;
proto_tree_add_item(tree, hf_zebra_prefixlen, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
if (family == ZEBRA_FAMILY_IPV4) {
proto_tree_add_item(tree, hf_zebra_dest4,
tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
else if (family == ZEBRA_FAMILY_IPV6) {
proto_tree_add_item(tree, hf_zebra_dest6,
tvb, offset, 16, ENC_NA);
offset += 16;
}
return offset;
}
static int
zebra_interface_del(proto_tree *tree, tvbuff_t *tvb, int offset)
{
proto_tree_add_item(tree, hf_zebra_interface,
tvb, offset, INTERFACE_NAMSIZ, ENC_ASCII|ENC_NA);
offset += INTERFACE_NAMSIZ;
proto_tree_add_item(tree, hf_zebra_index, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
return offset;
}
static int
zebra_interface(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 version)
{
gint maclen;
proto_tree_add_item(tree, hf_zebra_interface,
tvb, offset, INTERFACE_NAMSIZ, ENC_ASCII|ENC_NA);
offset += INTERFACE_NAMSIZ;
proto_tree_add_item(tree, hf_zebra_index, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_zebra_intstatus, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
if (version != 0) {
proto_tree_add_item(tree, hf_zebra_intflags, tvb,
offset, 8, ENC_BIG_ENDIAN);
offset += 8;
} else {
proto_tree_add_item(tree, hf_zebra_intflags, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
proto_tree_add_item(tree, hf_zebra_metric, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_zebra_mtu, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
if (version != 0) {
proto_tree_add_item(tree, hf_zebra_mtu6, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
}
proto_tree_add_item(tree, hf_zebra_bandwidth, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
if (version != 0) {
maclen = (gint)tvb_get_ntohl(tvb, offset);
offset += 4;
if (maclen > 0)
proto_tree_add_item(tree, hf_zebra_mac, tvb,
offset, maclen, ENC_NA);
offset += maclen;
}
return offset;
}
static int
zebra_nexthop_lookup(proto_tree *tree, tvbuff_t *tvb, int offset, guint16 len,
guint8 family)
{
if (family == ZEBRA_FAMILY_IPV6) {
proto_tree_add_item(tree, hf_zebra_dest6, tvb, offset, 16,
ENC_NA);
offset += 16;
}else {
proto_tree_add_item(tree, hf_zebra_dest4, tvb, offset, 4,
ENC_BIG_ENDIAN);
offset += 4;
}
proto_tree_add_item(tree, hf_zebra_metric,tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
offset = zebra_route_nexthop(tree, tvb, offset, len);
return offset;
}
static int
zerba_router_update(proto_tree *tree, tvbuff_t *tvb, int offset)
{
offset += 1;
proto_tree_add_item(tree, hf_zebra_routeridaddress, tvb,
offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_zebra_routeridmask, tvb,
offset, 1, ENC_BIG_ENDIAN);
offset += 1;
return offset;
}
static int
dissect_zebra_request(proto_tree *tree, gboolean request, tvbuff_t *tvb,
int offset, guint16 len, guint16 command, guint8 version)
{
proto_tree_add_uint(tree, hf_zebra_len, tvb, offset, 2, len);
offset += 2;
if (version != 0) {
proto_tree_add_item(tree, hf_zebra_marker, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_uint(tree, hf_zebra_version, tvb, offset, 1,
version);
offset += 1;
proto_tree_add_uint(tree, hf_zebra_command, tvb, offset, 2,
command);
offset += 2;
} else {
proto_tree_add_uint(tree, hf_zebra_command, tvb, offset, 1,
command);
offset += 1;
}
switch(command) {
case ZEBRA_INTERFACE_ADD:
case ZEBRA_INTERFACE_UP:
case ZEBRA_INTERFACE_DOWN:
if (request)
break; /* Request just subscribes to messages */
offset = zebra_interface(tree, tvb, offset, version);
break;
case ZEBRA_INTERFACE_DELETE:
offset = zebra_interface_del(tree, tvb, offset);
break;
case ZEBRA_INTERFACE_ADDRESS_ADD:
case ZEBRA_INTERFACE_ADDRESS_DELETE:
offset = zebra_interface_address(tree, tvb, offset);
break;
case ZEBRA_IPV4_ROUTE_ADD:
case ZEBRA_IPV4_ROUTE_DELETE:
offset = zebra_route(tree, tvb, offset, len,
ZEBRA_FAMILY_IPV4, version);
break;
case ZEBRA_IPV6_ROUTE_ADD:
case ZEBRA_IPV6_ROUTE_DELETE:
offset = zebra_route(tree, tvb, offset, len,
ZEBRA_FAMILY_IPV6, version);
break;
case ZEBRA_REDISTRIBUTE_ADD:
case ZEBRA_REDISTRIBUTE_DEFAULT_ADD:
if (version == 0) {
proto_tree_add_item(tree, hf_zebra_type_v0, tvb,
offset, 1, ENC_BIG_ENDIAN);
} else {
proto_tree_add_item(tree, hf_zebra_type_v1, tvb,
offset, 1, ENC_BIG_ENDIAN);
}
offset = 1;
break;
case ZEBRA_IPV4_IMPORT_LOOKUP:
case ZEBRA_IPV4_NEXTHOP_LOOKUP:
offset = zebra_nexthop_lookup(tree, tvb, offset, len,
ZEBRA_FAMILY_IPV4);
break;
case ZEBRA_IPV6_IMPORT_LOOKUP:
case ZEBRA_IPV6_NEXTHOP_LOOKUP:
offset = zebra_nexthop_lookup(tree, tvb, offset, len,
ZEBRA_FAMILY_IPV6);
break;
case ZEBRA_ROUTER_ID_UPDATE:
offset = zerba_router_update(tree, tvb, offset);
break;
case ZEBRA_ROUTER_ID_ADD:
case ZEBRA_ROUTER_ID_DELETE:
case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE:
/* nothing to do */
break;
case ZEBRA_REDISTRIBUTE_DELETE:
/* in version 1+, there's a route type field */
if (version > 0) {
proto_tree_add_item(tree, hf_zebra_type_v1, tvb,
offset, 1, ENC_BIG_ENDIAN);
}
break;
case ZEBRA_HELLO:
proto_tree_add_item(tree, hf_zebra_redist_default, tvb,
offset, 1, ENC_BIG_ENDIAN);
break;
}
return offset;
}
/*
Zebra Protocol header version 0:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------------------------------+---------------+
| Length (2) | Command (1) |
+-------------------------------+---------------+
Zebra Protocol header version 1:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-------------------------------+---------------+-------------+
| Length (2) | Marker (1) | Version (1) |
+-------------------------------+---------------+-------------+
| Command (2) |
+-------------------------------+
The Marker is 0xFF to distinguish it from a version 0 header.
*/
static int
dissect_zebra(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *ti;
proto_tree *zebra_tree;
gboolean request;
int left, offset;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZEBRA");
request = (pinfo->destport == pinfo->match_uint);
left = tvb_reported_length(tvb);
offset = 0;
col_set_str(pinfo->cinfo, COL_INFO,
request? "Zebra Request" : "Zebra Reply");
/* if (tree) */ {
ti = proto_tree_add_item(tree, proto_zebra, tvb, offset, -1,
ENC_NA);
zebra_tree = proto_item_add_subtree(ti, ett_zebra);
ti = proto_tree_add_boolean(zebra_tree, hf_zebra_request,
tvb, offset, 0, request);
PROTO_ITEM_SET_HIDDEN(ti);
for (;;) {
guint8 headermarker, version;
guint16 command, len;
proto_tree *zebra_request_tree;
if (left < 3)
break;
len = tvb_get_ntohs(tvb, offset);
if (len < 3)
break;
headermarker = tvb_get_guint8(tvb,offset+2);
if (headermarker != 0xFF) {
command = headermarker;
version = 0;
} else {
version = tvb_get_guint8(tvb, offset+3);
command = tvb_get_ntohs(tvb, offset+4);
}
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(command, messages, "Command Type 0x%02d"));
ti = proto_tree_add_uint(zebra_tree,
hf_zebra_command, tvb,
offset, len, command);
zebra_request_tree = proto_item_add_subtree(ti,
ett_zebra_request);
dissect_zebra_request(zebra_request_tree, request, tvb,
offset, len, command, version);
offset += len;
left -= len;
}
}
return tvb_captured_length(tvb);
}
void
proto_register_zebra(void)
{
static hf_register_info hf[] = {
{ &hf_zebra_len,
{ "Length", "zebra.len",
FT_UINT16, BASE_DEC, NULL, 0x0,
"Length of Zebra request", HFILL }},
{ &hf_zebra_version,
{ "Version", "zebra.version",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Zerbra srv version", HFILL }},
{ &hf_zebra_marker,
{ "Marker", "zebra.marker",
FT_UINT8, BASE_HEX, NULL, 0x0,
"Zerbra srv marker", HFILL }},
{ &hf_zebra_request,
{ "Request", "zebra.request",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"TRUE if Zebra request", HFILL }},
{ &hf_zebra_command,
{ "Command", "zebra.command",
FT_UINT8, BASE_DEC, VALS(messages), 0x0,
"Zebra command", HFILL }},
{ &hf_zebra_interface,
{ "Interface", "zebra.interface",
FT_STRING, BASE_NONE, NULL, 0x0,
"Interface name of Zebra request", HFILL }},
{ &hf_zebra_index,
{ "Index", "zebra.index",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Index of interface", HFILL }},
{ &hf_zebra_intstatus,
{ "Status", "zebra.intstatus",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Status of interface", HFILL}},
{ &hf_zebra_indexnum,
{ "Index Number", "zebra.indexnum",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of indices for route", HFILL }},
{ &hf_zebra_intflags,
{ "Flags", "zebra.intflags",
FT_UINT64, BASE_DEC, NULL, 0x0,
"Flags of interface", HFILL }},
{ &hf_zebra_rtflags,
{ "Flags", "zebra.rtflags",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Flags of route", HFILL }},
{ &hf_zebra_message,
{ "Message", "zebra.message",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Message type of route", HFILL }},
{ &hf_zebra_route_safi,
{ "SAFI", "zebra.safi",
FT_UINT16, BASE_DEC, VALS(safi), 0x0,
"Subsequent Address Family Identifier", HFILL }},
{ &hf_zebra_msg_nexthop,
{ "Message Nexthop", "zebra.message.nexthop",
FT_BOOLEAN, 8, NULL, ZEBRA_ZAPI_MESSAGE_NEXTHOP,
"Message contains nexthop", HFILL }},
{ &hf_zebra_msg_index,
{ "Message Index", "zebra.message.index",
FT_BOOLEAN, 8, NULL, ZEBRA_ZAPI_MESSAGE_IFINDEX,
"Message contains index", HFILL }},
{ &hf_zebra_msg_distance,
{ "Message Distance", "zebra.message.distance",
FT_BOOLEAN, 8, NULL, ZEBRA_ZAPI_MESSAGE_DISTANCE,
"Message contains distance", HFILL }},
{ &hf_zebra_msg_metric,
{ "Message Metric", "zebra.message.metric",
FT_BOOLEAN, 8, NULL, ZEBRA_ZAPI_MESSAGE_METRIC,
"Message contains metric", HFILL }},
{ &hf_zebra_type_v0,
{ "Type", "zebra.type",
FT_UINT8, BASE_DEC, VALS(routes_v0), 0x0,
"Type of route", HFILL }},
{ &hf_zebra_type_v1,
{ "Type", "zebra.type",
FT_UINT8, BASE_DEC, VALS(routes_v1), 0x0,
"Type of route", HFILL }},
{ &hf_zebra_distance,
{ "Distance", "zebra.distance",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Distance of route", HFILL }},
{ &hf_zebra_metric,
{ "Metric", "zebra.metric",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Metric of interface or route", HFILL }},
{ &hf_zebra_mtu,
{ "MTU", "zebra.mtu",
FT_UINT32, BASE_DEC, NULL, 0x0,
"MTU of interface", HFILL }},
{ &hf_zebra_mtu6,
{ "MTUv6", "zebra.mtu6",
FT_UINT32, BASE_DEC, NULL, 0x0,
"MTUv6 of interface", HFILL }},
{ &hf_zebra_bandwidth,
{ "Bandwidth", "zebra.bandwidth",
FT_UINT32, BASE_DEC, NULL, 0x0,
"Bandwidth of interface", HFILL }},
{ &hf_zebra_family,
{ "Family", "zebra.family",
FT_UINT8, BASE_DEC, VALS(families), 0x0,
"Family of IP address", HFILL }},
{ &hf_zebra_flags,
{ "Flags", "zebra.flags",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Flags of Address Info", HFILL }},
{ &hf_zebra_dest4,
{ "Destination", "zebra.dest4",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Destination IPv4 field", HFILL }},
{ &hf_zebra_dest6,
{ "Destination", "zebra.dest6",
FT_IPv6, BASE_NONE, NULL, 0x0,
"Destination IPv6 field", HFILL }},
{ &hf_zebra_nexthopnum,
{ "Nexthop Number", "zebra.nexthopnum",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Number of nexthops in route", HFILL }},
{ &hf_zebra_nexthop4,
{ "Nexthop", "zebra.nexthop4",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Nethop IPv4 field of route", HFILL }},
{ &hf_zebra_nexthop6,
{ "Nexthop", "zebra.nexthop6",
FT_IPv6, BASE_NONE, NULL, 0x0,
"Nethop IPv6 field of route", HFILL }},
{ &hf_zebra_prefixlen,
{ "Prefix length", "zebra.prefixlen",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_zebra_prefix4,
{ "Prefix", "zebra.prefix4",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Prefix IPv4", HFILL }},
{ &hf_zebra_prefix6,
{ "Prefix", "zebra.prefix6",
FT_IPv6, BASE_NONE, NULL, 0x0,
"Prefix IPv6", HFILL }},
{ &hf_zebra_routeridaddress,
{ "Router ID address", "zebra.routerIDAddress",
FT_IPv4, BASE_NONE, NULL, 0x0,
"Router ID", HFILL }},
{ &hf_zebra_routeridmask,
{ "Router ID mask", "zebra.routerIDMask",
FT_UINT8, BASE_DEC, NULL, 0x0,
"netmask of Router ID", HFILL }},
{ &hf_zebra_mac,
{ "MAC address", "zebra.macaddress",
FT_ETHER, BASE_NONE, NULL, 0x0,
"MAC address of interface", HFILL }},
{ &hf_zebra_redist_default,
{ "Redistribute default", "zebra.redist_default",
FT_BOOLEAN, BASE_NONE, NULL, 0x0,
"TRUE if redistribute default", HFILL }}
};
static gint *ett[] = {
&ett_zebra,
&ett_zebra_request,
&ett_message,
};
proto_zebra = proto_register_protocol("Zebra Protocol", "ZEBRA", "zebra");
proto_register_field_array(proto_zebra, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_zebra(void)
{
dissector_handle_t zebra_handle;
zebra_handle = create_dissector_handle(dissect_zebra, proto_zebra);
dissector_add_uint_with_preference("tcp.port", TCP_PORT_ZEBRA, zebra_handle);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/