diff options
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 2 | ||||
-rw-r--r-- | epan/arptypes.h | 1 | ||||
-rw-r--r-- | epan/dissectors/Makefile.common | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink-route.c | 782 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink.c | 255 | ||||
-rw-r--r-- | epan/dissectors/packet-netlink.h | 62 |
6 files changed, 1104 insertions, 0 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 6dbec41b87..ad61b13b5d 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -967,6 +967,8 @@ set(DISSECTOR_SRC dissectors/packet-netbios.c dissectors/packet-netdump.c dissectors/packet-netflow.c + dissectors/packet-netlink.c + dissectors/packet-netlink-route.c dissectors/packet-netperfmeter.c dissectors/packet-netrom.c dissectors/packet-netsync.c diff --git a/epan/arptypes.h b/epan/arptypes.h index d72fa2b90e..6b73352694 100644 --- a/epan/arptypes.h +++ b/epan/arptypes.h @@ -78,6 +78,7 @@ extern "C" { /* Virtual ARP types for non ARP hardware used in Linux cooked mode. */ #define ARPHRD_IPGRE 778 /* GRE over IP */ +#define ARPHRD_NETLINK 824 /* netlink */ #ifdef __cplusplus } diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 2932c8aae2..dc3063ffc8 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -889,6 +889,8 @@ DISSECTOR_SRC = \ packet-netbios.c \ packet-netdump.c \ packet-netflow.c \ + packet-netlink.c \ + packet-netlink-route.c \ packet-netperfmeter.c \ packet-netrom.c \ packet-netsync.c \ diff --git a/epan/dissectors/packet-netlink-route.c b/epan/dissectors/packet-netlink-route.c new file mode 100644 index 0000000000..4a91a35644 --- /dev/null +++ b/epan/dissectors/packet-netlink-route.c @@ -0,0 +1,782 @@ +/* packet-netlin-route.c + * + * $Id$ + * + * 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. + */ + +/* man 7 rtnetlink */ + +#define NEW_PROTO_TREE_API + +#include "config.h" + +#include <glib.h> + +#include <epan/packet.h> + +#include "packet-arp.h" +#include "packet-netlink.h" + +struct netlink_route_info { + packet_info *pinfo; + struct packet_netlink_data *data; + + int encoding; /* copy of data->encoding */ +}; + +enum { +/* rtnetlink values for nlmsghdr.nlmsg_type from <linux/rtnetlink.h> */ + WS_RTM_NEWLINK = 16, + WS_RTM_DELLINK = 17, + WS_RTM_GETLINK = 18, + WS_RTM_SETLINK = 19, + WS_RTM_NEWADDR = 20, + WS_RTM_DELADDR = 21, + WS_RTM_GETADDR = 22, + WS_RTM_NEWROUTE = 24, + WS_RTM_DELROUTE = 25, + WS_RTM_GETROUTE = 26, + WS_RTM_NEWNEIGH = 28, + WS_RTM_DELNEIGH = 29, + WS_RTM_GETNEIGH = 30, + WS_RTM_NEWRULE = 32, + WS_RTM_DELRULE = 33, + WS_RTM_GETRULE = 34, + WS_RTM_NEWQDISC = 36, + WS_RTM_DELQDISC = 37, + WS_RTM_GETQDISC = 38, + WS_RTM_NEWTCLASS = 40, + WS_RTM_DELTCLASS = 41, + WS_RTM_GETTCLASS = 42, + WS_RTM_NEWTFILTER = 44, + WS_RTM_DELTFILTER = 45, + WS_RTM_GETTFILTER = 46, + WS_RTM_NEWACTION = 48, + WS_RTM_DELACTION = 49, + WS_RTM_GETACTION = 50, + WS_RTM_NEWPREFIX = 52, + WS_RTM_GETMULTICAST = 58, + WS_RTM_GETANYCAST = 62, + WS_RTM_NEWNEIGHTBL = 64, + WS_RTM_GETNEIGHTBL = 66, + WS_RTM_SETNEIGHTBL = 67, + WS_RTM_NEWNDUSEROPT = 68, + WS_RTM_NEWADDRLABEL = 72, + WS_RTM_DELADDRLABEL = 73, + WS_RTM_GETADDRLABEL = 74, + WS_RTM_GETDCB = 78, + WS_RTM_SETDCB = 79, + WS_RTM_NEWNETCONF = 80, + WS_RTM_GETNETCONF = 82, + WS_RTM_NEWMDB = 84, + WS_RTM_DELMDB = 85, + WS_RTM_GETMDB = 86, +}; + +/* values for rta_type (network interface) from <linux/if_link.h> */ +enum ws_ifla_attr_type { + WS_IFLA_UNSPEC = 0, + WS_IFLA_ADDRESS = 1, + WS_IFLA_BROADCAST = 2, + WS_IFLA_IFNAME = 3, + WS_IFLA_MTU = 4, + WS_IFLA_LINK = 5, + WS_IFLA_QDISC = 6, + WS_IFLA_STATS = 7, + WS_IFLA_COST = 8, + WS_IFLA_PRIORITY = 9, + WS_IFLA_MASTER = 10, + WS_IFLA_WIRELESS = 11, + WS_IFLA_PROTINFO = 12, + WS_IFLA_TXQLEN = 13, + WS_IFLA_MAP = 14, + WS_IFLA_WEIGHT = 15, + WS_IFLA_OPERSTATE = 16, + WS_IFLA_LINKMODE = 17, + WS_IFLA_LINKINFO = 18, + WS_IFLA_NET_NS_PID= 19, + WS_IFLA_IFALIAS = 20, + WS_IFLA_NUM_VF = 21, + WS_IFLA_VFINFO_LIST=22, + WS_IFLA_STATS64 = 23, + WS_IFLA_VF_PORTS = 24, + WS_IFLA_PORT_SELF = 25, + WS_IFLA_AF_SPEC = 26, + WS_IFLA_GROUP = 27, + WS_IFLA_NET_NS_FD = 28, + WS_IFLA_EXT_MASK = 29, + WS_IFLA_PROMISCUITY=30, + WS_IFLA_NUM_TX_QUEUES=31, + WS_IFLA_NUM_RX_QUEUES=32, + WS_IFLA_CARRIER = 33 +}; + +/* values for rta_type (route) from <linux/rtnetlink.h> */ +enum ws_rta_attr_type { + WS_RTA_UNSPEC = 0, + WS_RTA_DST = 1, + WS_RTA_SRC = 2, + WS_RTA_IIF = 3, + WS_RTA_OIF = 4, + WS_RTA_GATEWAY = 5, + WS_RTA_PRIORITY = 6, + WS_RTA_PREFSRC = 7, + WS_RTA_METRICS = 8, + WS_RTA_MULTIPATH = 9, + WS_RTA_PROTOINFO = 10, + WS_RTA_FLOW = 11, + WS_RTA_CACHEINFO = 12, + WS_RTA_SESSION = 13, + WS_RTA_MP_ALGO = 14, + WS_RTA_TABLE = 15, + WS_RTA_MARK = 16, + WS_RTA_MFC_STATS = 17 +}; + + +/* values for rtmsg.rtm_protocol from <linux/rtnetlink.h> */ +enum { +/* kernel */ + WS_RTPROT_UNSPEC = 0, + WS_RTPROT_REDIRECT = 1, + WS_RTPROT_KERNEL = 2, + WS_RTPROT_BOOT = 3, + WS_RTPROT_STATIC = 4, +/* user */ + WS_RTPROT_GATED = 8, + WS_RTPROT_RA = 9, + WS_RTPROT_MRT = 10, + WS_RTPROT_ZEBRA = 11, + WS_RTPROT_BIRD = 12, + WS_RTPROT_DNROUTED = 13, + WS_RTPROT_XORP = 14, + WS_RTPROT_NTK = 15, + WS_RTPROT_DHCP = 16, + WS_RTPROT_MROUTED = 17 +}; + +/* values for rtmsg.rtm_scope from <linux/rtnetlink.h> */ +enum { + WS_RT_SCOPE_UNIVERSE = 0, +/* user defined */ + WS_RT_SCOPE_SITE = 200, + WS_RT_SCOPE_LINK = 253, + WS_RT_SCOPE_HOST = 254, + WS_RT_SCOPE_NOWHERE = 255 +}; + +/* values for rtmsg.rtm_type from <linux/rtnetlink.h> */ +enum { + WS_RTN_UNSPEC = 0, + WS_RTN_UNICAST = 1, + WS_RTN_LOCAL = 2, + WS_RTN_BROADCAST = 3, + WS_RTN_ANYCAST = 4, + WS_RTN_MULTICAST = 5, + WS_RTN_BLACKHOLE = 6, + WS_RTN_UNREACHABLE = 7, + WS_RTN_PROHIBIT = 8, + WS_RTN_THROW = 9, + WS_RTN_NAT = 10, + WS_RTN_XRESOLVE = 11 +}; + +/* values for ifinfomsg.ifi_flags <linux/if.h> */ +enum { + WS_IFF_UP = 0x1, + WS_IFF_BROADCAST = 0x2, + WS_IFF_DEBUG = 0x4, + WS_IFF_LOOPBACK = 0x8, + WS_IFF_POINTOPOINT = 0x10, + WS_IFF_NOTRAILERS = 0x20, + WS_IFF_RUNNING = 0x40, + WS_IFF_NOARP = 0x80, + WS_IFF_PROMISC = 0x100, + WS_IFF_ALLMULTI = 0x200, + WS_IFF_MASTER = 0x400, + WS_IFF_SLAVE = 0x800, + WS_IFF_MULTICAST = 0x1000, + WS_IFF_PORTSEL = 0x2000, + WS_IFF_AUTOMEDIA = 0x4000, + WS_IFF_DYNAMIC = 0x8000, + WS_IFF_LOWER_UP = 0x10000, + WS_IFF_DORMANT = 0x20000, + WS_IFF_ECHO = 0x40000, +}; + +static dissector_handle_t netlink_route_handle; + +static header_field_info *hfi_netlink_route = NULL; + +#define NETLINK_ROUTE_HFI_INIT HFI_INIT(proto_netlink_route) + +static const value_string netlink_route_type_vals[] = { + { WS_RTM_NEWLINK, "Create network interface" }, + { WS_RTM_DELLINK, "Remove network interface" }, + { WS_RTM_GETLINK, "Get network interface" }, + /* WS_RTM_SETLINK */ + + { WS_RTM_NEWADDR, "Add IP address" }, + { WS_RTM_DELADDR, "Delete IP address" }, + { WS_RTM_GETADDR, "Get IP address" }, + + { WS_RTM_NEWROUTE, "Add network route" }, + { WS_RTM_DELROUTE, "Delete network route" }, + { WS_RTM_GETROUTE, "Get network route" }, + + { WS_RTM_NEWNEIGH, "Add neighbor table entry" }, + { WS_RTM_DELNEIGH, "Delete neighbor table entry" }, + { WS_RTM_GETNEIGH, "Get neighbor table entry" }, + + { WS_RTM_NEWRULE, "Add routing rule" }, + { WS_RTM_DELRULE, "Delete routing rule" }, + { WS_RTM_GETRULE, "Get routing rule" }, + + { WS_RTM_NEWQDISC, "Add queueing discipline" }, + { WS_RTM_DELQDISC, "Delete queueing discipline" }, + { WS_RTM_GETQDISC, "Get queueing discipline" }, + + { WS_RTM_NEWTCLASS, "Add traffic class" }, + { WS_RTM_DELTCLASS, "Delete traffic class" }, + { WS_RTM_GETTCLASS, "Get traffic class" }, + + { WS_RTM_NEWTFILTER, "Add traffic class" }, + { WS_RTM_DELTFILTER, "Delete traffic class" }, + { WS_RTM_GETTFILTER, "Get traffic class" }, +/* XXX from WS_RTM_NEWACTION */ + { 0, NULL } +}; + +static header_field_info hfi_netlink_route_type NETLINK_ROUTE_HFI_INIT = + { "Message type", "netlink-route.type", FT_UINT16, BASE_DEC, + VALS(netlink_route_type_vals), 0x00, NULL, HFILL }; + +static gint ett_netlink_route = -1; +static gint ett_netlink_route_attr = -1; +static gint ett_netlink_route_if_flags = -1; + +typedef int netlink_route_attributes_cb_t(tvbuff_t *, struct netlink_route_info *, proto_tree *, int rta_type, int offset, int len); + +static int +dissect_netlink_route_attributes(tvbuff_t *tvb, header_field_info *hfi_type, struct netlink_route_info *info, proto_tree *tree, int offset, netlink_route_attributes_cb_t cb) +{ + /* align to 4 */ + offset = (offset + 3) & ~3; + + while (tvb_length_remaining(tvb, offset) >= 4) { + guint16 rta_len, rta_type; + int end_offset; + + proto_item *ti; + proto_tree *attr_tree; + + rta_len = tvb_get_letohs(tvb, offset); + end_offset = (offset + rta_len + 3) & ~3; + + ti = proto_tree_add_text(tree, tvb, offset, end_offset - offset, "rtnetlink attribute"); + attr_tree = proto_item_add_subtree(ti, ett_netlink_route_attr); + + proto_tree_add_text(attr_tree, tvb, offset, 2, "Len: %d", rta_len); + offset += 2; + + rta_type = tvb_get_letohs(tvb, offset); + proto_tree_add_item(attr_tree, hfi_type, tvb, offset, 2, info->encoding); + offset += 2; + + if (hfi_type->strings) { + /* XXX, export hf_try_val_to_str */ + const char *rta_str = try_val_to_str(rta_type, (const value_string *) hfi_type->strings); + + if (rta_str) + proto_item_append_text(ti, ": %s", rta_str); + } + + + if (!cb(tvb, info, attr_tree, rta_type, offset, end_offset - offset)) { + /* not handled */ + } + + if (end_offset <= offset) + break; + + offset = end_offset; + } + + return offset; +} + +/* Interface */ +static header_field_info hfi_netlink_route_ifi_family NETLINK_ROUTE_HFI_INIT = + { "Interface family", "netlink-route.ifi_family", FT_UINT8, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifi_type NETLINK_ROUTE_HFI_INIT = + { "Device type", "netlink-route.ifi_type", FT_UINT16, BASE_DEC, + VALS(arp_hrd_vals), 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifi_index NETLINK_ROUTE_HFI_INIT = + { "Interface index", "netlink-route.ifi_index", FT_INT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifi_flags NETLINK_ROUTE_HFI_INIT = + { "Device flags", "netlink-route.ifi_flags", FT_UINT32, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static const true_false_string hfi_netlink_route_ifi_flags_iff_up_tfs = { "Up", "Down" }; + +static header_field_info hfi_netlink_route_ifi_flags_iff_up NETLINK_ROUTE_HFI_INIT = + { "Interface", "netlink-route.ifi_flags.iff_up", FT_BOOLEAN, 32, + &hfi_netlink_route_ifi_flags_iff_up_tfs, WS_IFF_UP, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifi_flags_iff_broadcast NETLINK_ROUTE_HFI_INIT = + { "Broadcast", "netlink-route.ifi_flags.iff_broadcast", FT_BOOLEAN, 32, + &tfs_valid_invalid, WS_IFF_BROADCAST, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifi_change NETLINK_ROUTE_HFI_INIT = + { "Device change flags", "netlink-route.ifi_change", FT_UINT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static int +dissect_netlink_route_ifinfomsg(tvbuff_t *tvb, struct netlink_route_info *info, proto_tree *tree, int offset) +{ + proto_item *ti; + proto_tree *if_flags_tree; + + proto_tree_add_item(tree, &hfi_netlink_route_ifi_family, tvb, offset, 1, info->encoding); + offset += 1; + + /* XXX padding, check if 0 */ + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_ifi_type, tvb, offset, 2, info->encoding); + offset += 2; + + proto_tree_add_item(tree, &hfi_netlink_route_ifi_index, tvb, offset, 4, info->encoding); + offset += 4; + + ti = proto_tree_add_item(tree, &hfi_netlink_route_ifi_flags, tvb, offset, 4, info->encoding); + if_flags_tree = proto_item_add_subtree(ti, ett_netlink_route_if_flags); + + if (if_flags_tree) { + guint32 if_flags = tvb_get_letohl(tvb, offset); + + if (if_flags & WS_IFF_UP) + proto_item_append_text(ti, " UP"); + if (if_flags & WS_IFF_BROADCAST) + proto_item_append_text(ti, " BROADCAST"); + if (if_flags & WS_IFF_DEBUG) + proto_item_append_text(ti, " DEBUG"); + if (if_flags & WS_IFF_LOOPBACK) + proto_item_append_text(ti, " LOOPBACK"); + if (if_flags & WS_IFF_POINTOPOINT) + proto_item_append_text(ti, " POINTOPOINT"); + if (if_flags & WS_IFF_NOTRAILERS) + proto_item_append_text(ti, " NOTRAILERS"); + if (if_flags & WS_IFF_RUNNING) + proto_item_append_text(ti, " RUNNING"); + if (if_flags & WS_IFF_NOARP) + proto_item_append_text(ti, " NOARP"); + if (if_flags & WS_IFF_PROMISC) + proto_item_append_text(ti, " PROMISC"); + if (if_flags & WS_IFF_ALLMULTI) + proto_item_append_text(ti, " ALLMULTI"); + if (if_flags & WS_IFF_MASTER) + proto_item_append_text(ti, " MASTER"); + if (if_flags & WS_IFF_SLAVE) + proto_item_append_text(ti, " SLAVE"); + if (if_flags & WS_IFF_MULTICAST) + proto_item_append_text(ti, " MULTICAST"); + if (if_flags & WS_IFF_PORTSEL) + proto_item_append_text(ti, " PORTSEL"); + if (if_flags & WS_IFF_AUTOMEDIA) + proto_item_append_text(ti, " AUTOMEDIA"); + if (if_flags & WS_IFF_DYNAMIC) + proto_item_append_text(ti, " DYNAMIC"); + if (if_flags & WS_IFF_LOWER_UP) + proto_item_append_text(ti, " LOWER_UP"); + if (if_flags & WS_IFF_DORMANT) + proto_item_append_text(ti, " DORMANT"); + if (if_flags & WS_IFF_ECHO) + proto_item_append_text(ti, " ECHO"); + + proto_tree_add_item(if_flags_tree, &hfi_netlink_route_ifi_flags_iff_up, tvb, offset, 4, info->encoding); + proto_tree_add_item(if_flags_tree, &hfi_netlink_route_ifi_flags_iff_broadcast, tvb, offset, 4, info->encoding); + /* XXX */ + } + offset += 4; + + proto_tree_add_item(tree, &hfi_netlink_route_ifi_change, tvb, offset, 4, info->encoding); + offset += 4; + + return offset; +} + +/* Interface Attributes */ + +static const value_string netlink_route_ifla_attr_vals[] = { + { WS_IFLA_UNSPEC, "Unspecified" }, + { WS_IFLA_ADDRESS, "Address" }, + { WS_IFLA_BROADCAST, "Broadcast" }, + { WS_IFLA_IFNAME, "Device name" }, + { WS_IFLA_MTU, "MTU" }, + { WS_IFLA_LINK, "Link type" }, + { WS_IFLA_QDISC, "Queueing discipline" }, + { WS_IFLA_STATS, "Interface Statistics" }, + { WS_IFLA_COST, "Cost" }, + { WS_IFLA_PRIORITY, "Priority" }, +/* XXX from WS_IFLA_MASTER */ + { 0, NULL } +}; + +static header_field_info hfi_netlink_route_ifla_attr_type NETLINK_ROUTE_HFI_INIT = + { "Attribute type", "netlink-route.ifla_attr_type", FT_UINT16, BASE_DEC, + VALS(netlink_route_ifla_attr_vals), 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifla_ifname NETLINK_ROUTE_HFI_INIT = + { "Device name", "netlink-route.ifla_ifname", FT_STRINGZ, STR_ASCII, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_ifla_mtu NETLINK_ROUTE_HFI_INIT = + { "MTU of device", "netlink-route.ifla_mtu", FT_UINT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static int +dissect_netlink_route_if_attrs(tvbuff_t *tvb, struct netlink_route_info *info, proto_tree *tree, int rta_type, int offset, int len) +{ + enum ws_ifla_attr_type type = (enum ws_ifla_attr_type) rta_type; + + switch (type) { + case WS_IFLA_IFNAME: + proto_tree_add_item(tree, &hfi_netlink_route_ifla_ifname, tvb, offset, len, ENC_ASCII | ENC_NA); + return 1; + + case WS_IFLA_MTU: + if (len == 4) { + proto_tree_add_item(tree, &hfi_netlink_route_ifla_mtu, tvb, offset, len, info->encoding); + return 1; + } + return 0; + + default: + return 0; + } +} + +/* IP address */ +static header_field_info hfi_netlink_route_ifa_family NETLINK_ROUTE_HFI_INIT = + { "Address type", "netlink-route.ifa_family", FT_UINT8, BASE_DEC, + /* XXX .strings = _linux_family_vals (nflog) */ + NULL, 0x00, NULL, HFILL }; + +static int +dissect_netlink_route_ifaddrmsg(tvbuff_t *tvb, struct netlink_route_info *info _U_, proto_tree *tree, int offset) +{ + proto_tree_add_item(tree, &hfi_netlink_route_ifa_family, tvb, offset, 1, ENC_NA); + offset += 1; + + return offset; +} + +/* Route */ +static header_field_info hfi_netlink_route_rt_family NETLINK_ROUTE_HFI_INIT = + { "Address family", "netlink-route.rt_family", FT_UINT8, BASE_DEC, + /* XXX .strings = _linux_family_vals (nflog) */ + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rt_dst_len NETLINK_ROUTE_HFI_INIT = + { "Length of destination", "netlink-route.rt_dst_len", FT_UINT8, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rt_src_len NETLINK_ROUTE_HFI_INIT = + { "Length of source", "netlink-route.rt_src_len", FT_UINT8, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rt_tos NETLINK_ROUTE_HFI_INIT = + { "TOS filter", "netlink-route.rt_tos", FT_UINT8, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rt_table NETLINK_ROUTE_HFI_INIT = + { "Routing table ID", "netlink-route.rt_table", FT_UINT8, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static const value_string hfi_netlink_route_rt_protocol_vals[] = { + { WS_RTPROT_UNSPEC, "unknown" }, + { WS_RTPROT_REDIRECT, "ICMP redirects" }, + { WS_RTPROT_KERNEL, "kernel" }, + { WS_RTPROT_BOOT, "boot" }, + { WS_RTPROT_STATIC, "static" }, + { WS_RTPROT_GATED, "GateD" }, + { WS_RTPROT_RA, "RDISC/ND router advertisements" }, + { WS_RTPROT_MRT, "Merit MRT" }, + { WS_RTPROT_ZEBRA, "Zebra" }, + { WS_RTPROT_BIRD, "BIRD" }, + { WS_RTPROT_DNROUTED, "DECnet routing daemon" }, + { WS_RTPROT_XORP, "XORP" }, + { WS_RTPROT_NTK, "Netsukuku" }, + { WS_RTPROT_DHCP, "DHCP client" }, + { WS_RTPROT_MROUTED, "Multicast daemon" }, + { 0x00, NULL } +}; + +static header_field_info hfi_netlink_route_rt_protocol NETLINK_ROUTE_HFI_INIT = + { "Routing protocol", "netlink-route.rt_protocol", FT_UINT8, BASE_HEX, + VALS(hfi_netlink_route_rt_protocol_vals), 0x00, NULL, HFILL }; + +static const value_string netlink_route_rt_scope_vals[] = { + { WS_RT_SCOPE_UNIVERSE, "global route" }, + { WS_RT_SCOPE_SITE, "interior route in the local autonomous system" }, + { WS_RT_SCOPE_LINK, "route on this link" }, + { WS_RT_SCOPE_HOST, "route on the local host" }, + { WS_RT_SCOPE_NOWHERE, "destination doesn't exist" }, + { 0x00, NULL } +}; + +static header_field_info hfi_netlink_route_rt_scope NETLINK_ROUTE_HFI_INIT = + { "Route origin", "netlink-route.rt_scope", FT_UINT8, BASE_HEX, + VALS(netlink_route_rt_scope_vals), 0x00, NULL, HFILL }; + +static const value_string netlink_route_rt_type_vals[] = { + { WS_RTN_UNSPEC, "Unknown route" }, + { WS_RTN_UNICAST, "Gateway or direct route" }, + { WS_RTN_LOCAL, "Local interface route" }, + { WS_RTN_BROADCAST, "Local broadcast route (send as broadcast)" }, + { WS_RTN_ANYCAST, "Local broadcast route (send as unicast)" }, + { WS_RTN_MULTICAST, "Multicast route" }, + { WS_RTN_BLACKHOLE, "Drop" }, + { WS_RTN_UNREACHABLE, "Unreachable destination" }, + { WS_RTN_PROHIBIT, "Administratively prohibited" }, + { WS_RTN_THROW, "Routing lookup in another table" }, + { WS_RTN_NAT, "Netwrk address translation rule" }, + { WS_RTN_XRESOLVE, "Use external resolver" }, + { 0x00, NULL } +}; + +static header_field_info hfi_netlink_route_rt_type NETLINK_ROUTE_HFI_INIT = + { "Route type", "netlink-route.rt_type", FT_UINT8, BASE_HEX, + VALS(netlink_route_rt_type_vals), 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rt_flags NETLINK_ROUTE_HFI_INIT = + { "Route flags", "netlink-route.rt_flags", FT_UINT32, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static int +dissect_netlink_route_rtmsg(tvbuff_t *tvb, struct netlink_route_info *info, proto_tree *tree, int offset) +{ + proto_tree_add_item(tree, &hfi_netlink_route_rt_family, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_dst_len, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_src_len, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_tos, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_table, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_protocol, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_scope, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_type, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(tree, &hfi_netlink_route_rt_flags, tvb, offset, 4, info->encoding); + offset += 4; + + return offset; +} + +/* Route Attributes */ + +static const value_string netlink_route_rta_attr_vals[] = { + { WS_RTA_UNSPEC, "Unspecified" }, + { WS_RTA_DST, "Route destination address" }, + { WS_RTA_SRC, "Route source address" }, + { WS_RTA_IIF, "Input interface index" }, + { WS_RTA_OIF, "Output interface index" }, + { WS_RTA_GATEWAY,"Gateway of the route" }, +/* XXX, from WS_RTA_PRIORITY */ + { 0, NULL } +}; + +static header_field_info hfi_netlink_route_rta_attr_type NETLINK_ROUTE_HFI_INIT = + { "Attribute type", "netlink-route.rta_attr_type", FT_UINT16, BASE_DEC, + VALS(netlink_route_rta_attr_vals), 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rta_iif NETLINK_ROUTE_HFI_INIT = + { "Input interface index", "netlink-route.rta_iif", FT_UINT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_route_rta_oif NETLINK_ROUTE_HFI_INIT = + { "Output interface index", "netlink-route.rta_oif", FT_UINT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static int +dissect_netlink_route_route_attrs(tvbuff_t *tvb, struct netlink_route_info *info, proto_tree *tree, int rta_type, int offset, int len) +{ + enum ws_rta_attr_type type = (enum ws_rta_attr_type) rta_type; + + switch (type) { + case WS_RTA_IIF: + if (len == 4) { + proto_tree_add_item(tree, &hfi_netlink_route_rta_iif, tvb, offset, 4, info->encoding); + return 1; + } + return 0; + + case WS_RTA_OIF: + if (len == 4) { + proto_tree_add_item(tree, &hfi_netlink_route_rta_oif, tvb, offset, 4, info->encoding); + return 1; + } + return 0; + + default: + return 0; + } +} + +static int +dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data) +{ + int offset; + + struct netlink_route_info info; + struct packet_netlink_data *data = NULL; + + if (_data) { + if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC) + data = _data; + } + + DISSECTOR_ASSERT(data); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink route"); + col_clear(pinfo->cinfo, COL_INFO); + + offset = 0; + + if (tree) { + proto_item_set_text(tree, "Linux rtnetlink (route netlink) message"); + + /* XXX, from header tvb */ + proto_tree_add_uint(tree, &hfi_netlink_route_type, NULL, 0, 0, data->type); + } + + info.encoding = data->encoding; + + info.pinfo = pinfo; + info.data = data; + + switch (data->type) { + case WS_RTM_NEWLINK: + case WS_RTM_DELLINK: + case WS_RTM_GETLINK: + offset = dissect_netlink_route_ifinfomsg(tvb, &info, tree, offset); + /* Optional attributes */ + offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifla_attr_type, &info, tree, offset, dissect_netlink_route_if_attrs); + break; + + case WS_RTM_NEWADDR: + case WS_RTM_DELADDR: + case WS_RTM_GETADDR: + offset = dissect_netlink_route_ifaddrmsg(tvb, &info, tree, offset); + break; + + case WS_RTM_NEWROUTE: + case WS_RTM_DELROUTE: + case WS_RTM_GETROUTE: + offset = dissect_netlink_route_rtmsg(tvb, &info, tree, offset); + /* Optional attributes */ + offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_rta_attr_type, &info, tree, offset, dissect_netlink_route_route_attrs); + break; + } + + return offset; +} + +void +proto_register_netlink_route(void) +{ +#ifndef HAVE_HFI_SECTION_INIT + static header_field_info *hfi[] = { + &hfi_netlink_route_type, + + /* Interface */ + &hfi_netlink_route_ifi_family, + &hfi_netlink_route_ifi_type, + &hfi_netlink_route_ifi_index, + &hfi_netlink_route_ifi_flags, + &hfi_netlink_route_ifi_flags_iff_up, + &hfi_netlink_route_ifi_flags_iff_broadcast, + &hfi_netlink_route_ifi_change, + /* Interface Attributes */ + &hfi_netlink_route_ifla_attr_type, + &hfi_netlink_route_ifla_ifname, + &hfi_netlink_route_ifla_mtu, + + /* IP address */ + &hfi_netlink_route_ifa_family, + + /* Network Route */ + &hfi_netlink_route_rt_family, + &hfi_netlink_route_rt_dst_len, + &hfi_netlink_route_rt_src_len, + &hfi_netlink_route_rt_tos, + &hfi_netlink_route_rt_table, + &hfi_netlink_route_rt_protocol, + &hfi_netlink_route_rt_scope, + &hfi_netlink_route_rt_type, + &hfi_netlink_route_rt_flags, + /* Network route Attributes */ + &hfi_netlink_route_rta_attr_type, + &hfi_netlink_route_rta_iif, + &hfi_netlink_route_rta_oif, + }; +#endif + + static gint *ett[] = { + &ett_netlink_route, + &ett_netlink_route_attr, + &ett_netlink_route_if_flags + }; + + int proto_netlink_route; + + proto_netlink_route = proto_register_protocol("Linux rtnetlink (route netlink) protocol", "rtnetlink", "netlink-route" ); + hfi_netlink_route = proto_registrar_get_nth(proto_netlink_route); + + proto_register_fields(proto_netlink_route, hfi, array_length(hfi)); + proto_register_subtree_array(ett, array_length(ett)); + + netlink_route_handle = new_create_dissector_handle(dissect_netlink_route, proto_netlink_route); +} + +void +proto_reg_handoff_netlink_route(void) +{ + dissector_add_uint("netlink.protocol", WS_NETLINK_ROUTE, netlink_route_handle); +} diff --git a/epan/dissectors/packet-netlink.c b/epan/dissectors/packet-netlink.c new file mode 100644 index 0000000000..51fe73cf67 --- /dev/null +++ b/epan/dissectors/packet-netlink.c @@ -0,0 +1,255 @@ +/* packet-netlink.c + * + * $Id$ + * + * 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. + */ + +/* http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html */ + +#define NEW_PROTO_TREE_API + +#include "config.h" + +#include <glib.h> + +#include <epan/arptypes.h> +#include <epan/packet.h> +#include <wiretap/wtap.h> + +#include "packet-netlink.h" + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HEADER_SIZE 16 /* total header length */ + +static const value_string ltype_vals[] = { + { WS_NETLINK_ROUTE, "Route" }, + { WS_NETLINK_UNUSED, "Unused" }, + { WS_NETLINK_USERSOCK, "user-mode" }, + { WS_NETLINK_FIREWALL, "Unused (formerly: ip_queue)" }, + { WS_NETLINK_SOCK_DIAG, "socket monitoring" }, + { WS_NETLINK_NFLOG, "Netfilter ULOG" }, + { WS_NETLINK_XFRM, "IPsec" }, + { WS_NETLINK_SELINUX, "SELinux events" }, + { WS_NETLINK_ISCSI, "Open-iSCSI" }, + { WS_NETLINK_AUDIT, "Auditing" }, + { WS_NETLINK_FIB_LOOKUP, "FIB lookup" }, + { WS_NETLINK_CONNECTOR, "Kernel connector" }, + { WS_NETLINK_NETFILTER, "Netfilter" }, + { WS_NETLINK_IP6_FW, "Unused (formerly: ip6_queue)" }, + { WS_NETLINK_DNRTMSG, "DECnet routing messages" }, + { WS_NETLINK_KOBJECT_UEVENT, "Kernel messages" }, + { WS_NETLINK_GENERIC, "Generic" }, + { WS_NETLINK_SCSITRANSPORT, "SCSI Transports" }, + { WS_NETLINK_ECRYPTFS, "ecryptfs" }, + { WS_NETLINK_RDMA, "RDMA" }, + { WS_NETLINK_CRYPTO, "Crypto layer" }, + { 0, NULL } +}; + + +static dissector_handle_t netlink_handle; + +static header_field_info *hfi_netlink = NULL; + +#define NETLINK_HFI_INIT HFI_INIT(proto_netlink) + +static header_field_info hfi_netlink_hatype NETLINK_HFI_INIT = + { "Link-layer address type", "netlink.hatype", FT_UINT16, BASE_DEC, + NULL, 0x0, NULL, HFILL }; + +/* Linux netlink protocol type */ +static header_field_info hfi_netlink_family NETLINK_HFI_INIT = + { "Family", "netlink.family", FT_UINT16, BASE_HEX, + VALS(ltype_vals), 0x00, NULL, HFILL }; + + +static header_field_info hfi_netlink_hdr_len NETLINK_HFI_INIT = + { "Length", "netlink.hdr_len", FT_UINT32, BASE_DEC, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_hdr_type NETLINK_HFI_INIT = + { "Type", "netlink.hdr_type", FT_UINT16, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_hdr_flags NETLINK_HFI_INIT = + { "Flags", "netlink.hdr_flags", FT_UINT16, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_hdr_seq NETLINK_HFI_INIT = + { "Sequence", "netlink.hdr_seq", FT_UINT32, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static header_field_info hfi_netlink_hdr_pid NETLINK_HFI_INIT = + { "Port ID", "netlink.hdr_pid", FT_UINT32, BASE_HEX, + NULL, 0x00, NULL, HFILL }; + +static gint ett_netlink_cooked = -1; +static gint ett_netlink_msghdr = -1; +static gint ett_netlink_msg = -1; + +static dissector_table_t netlink_dissector_table; +static dissector_handle_t data_handle; + +static int +dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data _U_) +{ + guint16 protocol, hatype; + proto_item *ti; + tvbuff_t *next_tvb; + proto_tree *fh_tree = NULL; + + int offset; + + hatype = tvb_get_ntohs(tvb, 2); + if (hatype != ARPHRD_NETLINK) + return 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink"); + col_clear(pinfo->cinfo, COL_INFO); + + if (tree) { + ti = proto_tree_add_protocol_format(tree, hfi_netlink->id, tvb, 0, + SLL_HEADER_SIZE, "Linux netlink (cooked header)"); + fh_tree = proto_item_add_subtree(ti, ett_netlink_cooked); + } + + /* Unused 2B */ + offset = 2; + + proto_tree_add_item(fh_tree, &hfi_netlink_hatype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Unused 10B */ + offset += 10; + + protocol = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(fh_tree, &hfi_netlink_family, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* DISSECTOR_ASSERT(offset == 16); */ + + while (tvb_reported_length_remaining(tvb, offset) >= 16) { + struct packet_netlink_data data; + + int pkt_end_offset; + guint32 pkt_len; + + proto_tree *fh_msg; + proto_tree *fh_hdr; + + int encoding = ENC_LITTLE_ENDIAN; /* XXX */ + + pkt_len = tvb_get_letohl(tvb, offset); + + pkt_end_offset = offset + pkt_len; + + ti = proto_tree_add_text(tree, tvb, offset, pkt_len, "Netlink message"); + fh_msg = proto_item_add_subtree(ti, ett_netlink_msg); + + ti = proto_tree_add_text(fh_msg, tvb, offset, 16, "Header"); + fh_hdr = proto_item_add_subtree(ti, ett_netlink_msghdr); + + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_len, tvb, offset, 4, encoding); + offset += 4; + + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_type, tvb, offset, 2, encoding); + data.type = tvb_get_letohs(tvb, offset); + offset += 2; + + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_flags, tvb, offset, 2, encoding); + offset += 2; + + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_seq, tvb, offset, 4, encoding); + offset += 4; + + proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_pid, tvb, offset, 4, encoding); + offset += 4; + + if (pkt_len > 16) { + data.magic = PACKET_NETLINK_MAGIC; + data.encoding = encoding; + + next_tvb = tvb_new_subset_length(tvb, offset, pkt_len-16); + + if (!dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, fh_msg, TRUE, &data)) + call_dissector(data_handle, next_tvb, pinfo, fh_msg); + + } else if (pkt_len != 16) { + /* XXX, expert info */ + break; + } + + offset = pkt_end_offset; + } + + return offset; +} + +void +proto_register_netlink(void) +{ +#ifndef HAVE_HFI_SECTION_INIT + static header_field_info *hfi[] = { + /* Cooked header */ + &hfi_netlink_hatype, + &hfi_netlink_family, + + /* Netlink message header */ + &hfi_netlink_hdr_len, + &hfi_netlink_hdr_type, + &hfi_netlink_hdr_flags, + &hfi_netlink_hdr_seq, + &hfi_netlink_hdr_pid, + }; +#endif + + static gint *ett[] = { + &ett_netlink_cooked, + &ett_netlink_msghdr, + &ett_netlink_msg + }; + + int proto_netlink; + + proto_netlink = proto_register_protocol("Linux netlink protocol", "NETLINK", "netlink" ); + hfi_netlink = proto_registrar_get_nth(proto_netlink); + + proto_register_fields(proto_netlink, hfi, array_length(hfi)); + proto_register_subtree_array(ett, array_length(ett)); + + netlink_handle = new_create_dissector_handle(dissect_netlink, proto_netlink); + + netlink_dissector_table = register_dissector_table( + "netlink.protocol", + "Linux netlink protocol type", + FT_UINT16, + BASE_HEX + ); +} + +void +proto_reg_handoff_netlink(void) +{ + data_handle = find_dissector("data"); + + dissector_add_uint("wtap_encap", WTAP_ENCAP_NETLINK, netlink_handle); +} diff --git a/epan/dissectors/packet-netlink.h b/epan/dissectors/packet-netlink.h new file mode 100644 index 0000000000..2708462413 --- /dev/null +++ b/epan/dissectors/packet-netlink.h @@ -0,0 +1,62 @@ +/* packet-netlink.h + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 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. + */ + +#ifndef __PACKET_NETLINK_H__ +#define __PACKET_NETLINK_H__ + +/* from <linux/netlink.h> prefixed with WS_ */ +enum { + WS_NETLINK_ROUTE = 0, + WS_NETLINK_UNUSED = 1, + WS_NETLINK_USERSOCK = 2, + WS_NETLINK_FIREWALL = 3, + WS_NETLINK_SOCK_DIAG = 4, + WS_NETLINK_NFLOG = 5, + WS_NETLINK_XFRM = 6, + WS_NETLINK_SELINUX = 7, + WS_NETLINK_ISCSI = 8, + WS_NETLINK_AUDIT = 9, + WS_NETLINK_FIB_LOOKUP = 10, + WS_NETLINK_CONNECTOR = 11, + WS_NETLINK_NETFILTER = 12, + WS_NETLINK_IP6_FW = 13, + WS_NETLINK_DNRTMSG = 14, + WS_NETLINK_KOBJECT_UEVENT = 15, + WS_NETLINK_GENERIC = 16, + /* leave room for NETLINK_DM (DM Events) */ + WS_NETLINK_SCSITRANSPORT = 18, + WS_NETLINK_ECRYPTFS = 19, + WS_NETLINK_RDMA = 20, + WS_NETLINK_CRYPTO = 21 +}; + +#define PACKET_NETLINK_MAGIC 0x4A5ACCCE + +struct packet_netlink_data { + guint32 magic; /* PACKET_NETLINK_MAGIC */ + + int encoding; + guint16 type; +}; + +#endif /* __PACKET_NETLINK_H__ */ |