aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <gharris@sonic.net>2021-07-22 16:36:36 -0700
committerGuy Harris <gharris@sonic.net>2021-07-22 16:36:36 -0700
commitb5a442a9798e7d680255cb2043c0291fd58a1113 (patch)
tree34c3ca9b5daa95fd5c4fb7b5d57f0b34dc6bb2fb
parent05e7c6ac596bdbb17b7048d3052fa9e8bd8ee3a2 (diff)
rpcap: add support for IPv6 addresses in findalldevs replies.
Also add support for various old-server-code address family values, and toss in a big comment explaining the whole findalldevs reply address mess.
-rw-r--r--epan/dissectors/packet-rpcap.c169
1 files changed, 155 insertions, 14 deletions
diff --git a/epan/dissectors/packet-rpcap.c b/epan/dissectors/packet-rpcap.c
index da76d3c873..2e63a36be0 100644
--- a/epan/dissectors/packet-rpcap.c
+++ b/epan/dissectors/packet-rpcap.c
@@ -174,7 +174,10 @@ static int hf_if_broadaddr = -1;
static int hf_if_dstaddr = -1;
static int hf_if_af = -1;
static int hf_if_port = -1;
-static int hf_if_ip = -1;
+static int hf_if_ipv4 = -1;
+static int hf_if_flowinfo = -1;
+static int hf_if_ipv6 = -1;
+static int hf_if_scopeid = -1;
static int hf_if_padding = -1;
static int hf_if_unknown = -1;
@@ -277,12 +280,6 @@ static const value_string auth_type[] = {
{ 0, NULL }
};
-static const value_string address_family[] = {
- { COMMON_AF_UNSPEC, "AF_UNSPEC" },
- { COMMON_AF_INET, "AF_INET" },
- { 0, NULL }
-};
-
static const value_string bpf_class[] = {
{ 0x00, "ld" },
{ 0x01, "ldx" },
@@ -379,6 +376,102 @@ dissect_rpcap_error (tvbuff_t *tvb, packet_info *pinfo,
"Error: %s", tvb_format_text_wsp (pinfo->pool, tvb, offset, len));
}
+/*
+ * There's some painful history with this part of a findalldevs reply.
+ *
+ * Older RPCAPDs sent the addresses over the wire in the OS's native
+ * structure format. For most OSes, this looks like the over-the-wire
+ * format, but might have a different value for AF_INET6 than the value
+ * on the machine receiving the reply. For OSes with the newer BSD-style
+ * sockaddr structures, this has, instead of a 2-byte address family,
+ * a 1-byte structure length followed by a 1-byte address family. The
+ * RPCAPD code would put the address family in network byte order before
+ * sending it; that would set it to 0 on a little-endian machine, as
+ * htons() of any value between 1 and 255 would result in a value > 255,
+ * with its lower 8 bits zero, so putting that back into a 1-byte field
+ * would set it to 0.
+ *
+ * Therefore, for older RPCAPDs running on an OS with newer BSD-style
+ * sockaddr structures, the family field, if treated as a big-endian
+ * (network byte order) 16-bit field, would be:
+ *
+ * (length << 8) | family if sent by a big-endian machine
+ * (length << 8) if sent by a little-endian machine
+ *
+ * For current RPCAPDs, and for older RPCAPDs running on an OS with
+ * older BSD-style sockaddr structures, the family field, if treated
+ * as a big-endian 16-bit field, would just contain the family.
+ *
+ * (An additional bit of pain was that the structure was sent over the
+ * wire as a network-byte-order struct sockaddr_storage, which does
+ * *not* have the same size on all platforms. On most platforms, the
+ * structure is 128 bytes long; on Solaris, however, it's 256 bytes
+ * long. Neither the rpcap client code in libpcap, nor we, try to
+ * detect Solaris addresses and deal with them.)
+ *
+ * The current rpcapd serializes the socket addresses as 128-byte
+ * structures, containing:
+ *
+ * a 2-octet address family value, in network byte order;
+ *
+ * a 4-octet IPv4 address, if the address family value is 2
+ * (the AF_INET value on all supported platforms);
+ *
+ * a 16-octet IPv6 address, if the address family value is
+ * 23 (the Windows AF_INET6 value, chosen because Windows
+ * was, before rpcap was changed to standardize the format,
+ * the only platform for which precompiled binaries for
+ * rpcapd were generally available);
+ *
+ * padding up to 128 bytes.
+ *
+ * The rpcap client code, and we, check for those address family values,
+ * as well as other values that might have been produced by the old
+ * code on various platforms.
+ */
+
+/*
+ * Possible IPv4 family values other than the designated over-the-wire value,
+ * which is 2 (because everybody uses 2 for AF_INET4).
+ */
+#define SOCKADDR_IN_LEN 16 /* length of struct sockaddr_in */
+#define NEW_BSD_AF_INET_BE ((SOCKADDR_IN_LEN << 8) | BSD_AF_INET)
+#define NEW_BSD_AF_INET_LE (SOCKADDR_IN_LEN << 8)
+
+/*
+ * Possible IPv6 family values other than the designated over-the-wire value,
+ * which is 23 (because that's what Windows uses, and most RPCAP servers
+ * out there are probably running Windows, as WinPcap includes the server
+ * but few if any UN*Xes build and ship it). Some are defined in
+ * <epan/aftypes.h>.
+ *
+ * The new BSD sockaddr structure format was in place before 4.4-Lite, so
+ * all the free-software BSDs use it.
+ */
+#define SOCKADDR_IN6_LEN 28 /* length of struct sockaddr_in6 */
+#define NEW_BSD_AF_INET6_BSD_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_BSD) /* NetBSD, OpenBSD, BSD/OS */
+#define NEW_BSD_AF_INET6_FREEBSD_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_FREEBSD) /* FreeBSD, DragonFly BSD */
+#define NEW_BSD_AF_INET6_DARWIN_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_DARWIN) /* macOS, iOS, anything else Darwin-based */
+#define NEW_BSD_AF_INET6_LE (SOCKADDR_IN6_LEN << 8)
+#define HPUX_AF_INET6 22
+#define AIX_AF_INET6 24
+
+static const value_string address_family[] = {
+ { COMMON_AF_UNSPEC, "AF_UNSPEC" },
+ { COMMON_AF_INET, "AF_INET" },
+ { NEW_BSD_AF_INET_BE, "AF_INET (old server code on big-endian 4.4-Lite-based OS)" },
+ { NEW_BSD_AF_INET_LE, "AF_INET (old server code on little-endian 4.4-Lite-based OS)" },
+ { WINSOCK_AF_INET6, "AF_INET6" },
+ { NEW_BSD_AF_INET6_BSD_BE, "AF_INET6 (old server code on big-endian NetBSD, OpenBSD, BSD/OS)" },
+ { NEW_BSD_AF_INET6_FREEBSD_BE, "AF_INET6 (old server code on big-endian FreeBSD)" },
+ { NEW_BSD_AF_INET6_DARWIN_BE, "AF_INET6 (old server code on big-endian Mac OS X)" },
+ { NEW_BSD_AF_INET6_LE, "AF_INET6 (old server code on little-endian 4.4-Lite-based OS)" },
+ { LINUX_AF_INET6, "AF_INET6 (old server code on Linux)" },
+ { HPUX_AF_INET6, "AF_INET6 (old server code on HP-UX)" },
+ { AIX_AF_INET6, "AF_INET6 (old server code on AIX)" },
+ { SOLARIS_AF_INET6, "AF_INET6 (old server code on Solaris)" },
+ { 0, NULL }
+};
static gint
dissect_rpcap_ifaddr (tvbuff_t *tvb, packet_info *pinfo,
@@ -387,9 +480,10 @@ dissect_rpcap_ifaddr (tvbuff_t *tvb, packet_info *pinfo,
{
proto_tree *tree;
proto_item *ti;
- gchar ipaddr[MAX_ADDR_STR_LEN];
- guint32 ipv4;
guint16 af;
+ guint32 ipv4;
+ ws_in6_addr ipv6;
+ gchar ipaddr[MAX_ADDR_STR_LEN];
ti = proto_tree_add_item (parent_tree, hf_id, tvb, offset, 128, ENC_BIG_ENDIAN);
tree = proto_item_add_subtree (ti, ett_ifaddr);
@@ -398,7 +492,11 @@ dissect_rpcap_ifaddr (tvbuff_t *tvb, packet_info *pinfo,
proto_tree_add_item (tree, hf_if_af, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
- if (af == COMMON_AF_INET) {
+ switch (af) {
+
+ case COMMON_AF_INET:
+ case NEW_BSD_AF_INET_BE:
+ case NEW_BSD_AF_INET_LE:
proto_tree_add_item (tree, hf_if_port, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
@@ -408,18 +506,52 @@ dissect_rpcap_ifaddr (tvbuff_t *tvb, packet_info *pinfo,
if (parent_item) {
proto_item_append_text (parent_item, ": %s", ipaddr);
}
- proto_tree_add_item (tree, hf_if_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item (tree, hf_if_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item (tree, hf_if_padding, tvb, offset, 120, ENC_NA);
offset += 120;
- } else {
+ break;
+
+ case WINSOCK_AF_INET6:
+ case NEW_BSD_AF_INET6_BSD_BE:
+ case NEW_BSD_AF_INET6_FREEBSD_BE:
+ case NEW_BSD_AF_INET6_DARWIN_BE:
+ case NEW_BSD_AF_INET6_LE:
+ case LINUX_AF_INET6:
+ case HPUX_AF_INET6:
+ case AIX_AF_INET6:
+ case SOLARIS_AF_INET6:
+ proto_tree_add_item (tree, hf_if_port, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item (tree, hf_if_flowinfo, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ tvb_get_ipv6 (tvb, offset, &ipv6);
+ ip6_to_str_buf(&ipv6, ipaddr, MAX_ADDR_STR_LEN);
+ proto_item_append_text (ti, ": %s", ipaddr);
+ if (parent_item) {
+ proto_item_append_text (parent_item, ": %s", ipaddr);
+ }
+ proto_tree_add_item (tree, hf_if_ipv6, tvb, offset, 16, ENC_NA);
+ offset += 16;
+
+ proto_tree_add_item (tree, hf_if_scopeid, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ proto_tree_add_item (tree, hf_if_padding, tvb, offset, 108, ENC_NA);
+ offset += 100;
+ break;
+
+ default:
ti = proto_tree_add_item (tree, hf_if_unknown, tvb, offset, 126, ENC_NA);
if (af != COMMON_AF_UNSPEC) {
expert_add_info_format(pinfo, ti, &ei_if_unknown,
"Unknown address family: %d", af);
}
offset += 126;
+ break;
}
return offset;
@@ -1433,8 +1565,17 @@ proto_register_rpcap (void)
{ &hf_if_port,
{ "Port", "rpcap.if.port", FT_UINT16, BASE_DEC,
NULL, 0x0, "Port number", HFILL } },
- { &hf_if_ip,
- { "IP address", "rpcap.if.ip", FT_IPv4, BASE_NONE,
+ { &hf_if_ipv4,
+ { "IPv4 address", "rpcap.if.ipv4", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL } },
+ { &hf_if_flowinfo,
+ { "Flow information", "rpcap.if.flowinfo", FT_UINT32, BASE_HEX,
+ NULL, 0x0, NULL, HFILL } },
+ { &hf_if_ipv6,
+ { "IPv6 address", "rpcap.if.ipv6", FT_IPv6, BASE_NONE,
+ NULL, 0x0, NULL, HFILL } },
+ { &hf_if_scopeid,
+ { "Scope ID", "rpcap.if.scopeid", FT_UINT32, BASE_HEX,
NULL, 0x0, NULL, HFILL } },
{ &hf_if_padding,
{ "Padding", "rpcap.if.padding", FT_BYTES, BASE_NONE,