From: Guy Harris Date: Tue, 26 Dec 2017 09:13:19 +0000 (-0800) Subject: Handle DLT_ENC files *not* written on the same OS and byte-order host. X-Git-Tag: tcpdump-4.99-bp~1579 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/1fdde1543ecb9c70ad051add9917fb49bd4d14bf Handle DLT_ENC files *not* written on the same OS and byte-order host. Some fields in the header are in the byte order of the host that wrote them; one of them is a 32-bit AF_ value, and those are not likely ever to be > 65535, so they should never have any of the upper 16 bits set, and are also unlikely ever to be AF_UNSPEC, i.e. 0, so they should have at least one of the lower 16 bits set. This means that they will have at least one of the upper 16 bits set iff the host that wrote the file has the opposite byte order of the host that's reading the file; use that to determine whether to byte-swap the address-family or flags fields. (The SPI field is in *network* byte order.) Use the BSD_AFNUM values to check for IPv4 vs. IPv6 traffic, so we don't have to have the same AF_ values as the host that wrote the file. --- diff --git a/print-enc.c b/print-enc.c index c3fcf10c..d8f0a9e6 100644 --- a/print-enc.c +++ b/print-enc.c @@ -31,6 +31,7 @@ #include "netdissect.h" #include "extract.h" +#include "af.h" /* From $OpenBSD: if_enc.h,v 1.8 2001/06/25 05:14:00 angelos Exp $ */ /* @@ -85,13 +86,21 @@ struct enchdr { (wh) &= ~(xf); \ } +/* + * Byte-swap a 32-bit number. + * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on + * big-endian platforms.) + */ +#define SWAPLONG(y) \ +((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) + u_int enc_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; - int flags; + u_int af, flags; const struct enchdr *hdr; if (caplen < ENC_HDRLEN) { @@ -100,7 +109,31 @@ enc_if_print(netdissect_options *ndo, } hdr = (const struct enchdr *)p; - flags = hdr->flags; + /* + * The address family and flags fields are in the byte order + * of the host that originally captured the traffic. + * + * To determine that, look at the address family. It's 32-bit, + * it is not likely ever to be > 65535 (I doubt there will + * ever be > 65535 address families and, so far, AF_ values have + * not been allocated very sparsely) so it should not have the + * upper 16 bits set, and it is not likely ever to be AF_UNSPEC, + * i.e. it's not likely ever to be 0, so if it's byte-swapped, + * it should have at least one of the upper 16 bits set. + * + * So if any of the upper 16 bits are set, we assume it, and + * the flags field, are byte-swapped. + * + * The SPI field is always in network byte order, i.e. big- + * endian. + */ + UNALIGNED_MEMCPY(&af, &hdr->af, sizeof af); + UNALIGNED_MEMCPY(&flags, &hdr->flags, sizeof flags); + if ((af & 0xFFFF0000) != 0) { + af = SWAPLONG(af); + flags = SWAPLONG(hdr->flags); + } + if (flags == 0) ND_PRINT((ndo, "(unprotected): ")); else @@ -114,15 +147,15 @@ enc_if_print(netdissect_options *ndo, caplen -= ENC_HDRLEN; p += ENC_HDRLEN; - switch (hdr->af) { - case AF_INET: + switch (af) { + case BSD_AFNUM_INET: ip_print(ndo, p, length); break; -#ifdef AF_INET6 - case AF_INET6: + case BSD_AFNUM_INET6_BSD: + case BSD_AFNUM_INET6_FREEBSD: + case BSD_AFNUM_INET6_DARWIN: ip6_print(ndo, p, length); break; -#endif } out: