]> The Tcpdump Group git mirrors - libpcap/commitdiff
rpcap: have the server tell the client its byte order.
authorGuy Harris <[email protected]>
Sat, 6 Aug 2022 11:00:43 +0000 (04:00 -0700)
committerGuy Harris <[email protected]>
Sat, 6 Aug 2022 11:00:43 +0000 (04:00 -0700)
Stick a byte-order magic number, in the host byte order of the server,
into the authentication reply.

If the authentication reply is large enough to contain that magic
number, extract it and, from it, determine whether the server's byte
order is the opposite of the client's byte order; if it's not present,
assume the server has the same byte order.

If the two byte orders are differen, do the same byte-order fixing of
the packet contents that we do when reading a pcap file or pcapng
section with the opposite byte order, so that host-byte-order fields are
converted from the byte order of the host that sent or wrote them to the
byte order of the host that received or read them.

This change will allow a client to work with all servers, regardless of
whether they provide the byte order or not, although if the server
doesn't provide the byte order, and it happens to be the opposite of the
client's byte order, packets with a link-layer header type that contains
host-byte-order fields will not be able to be processed correctly.  It
also allows clients that don't handle the byte order magic number in the
authentication reply to work with all servers, as they will just discard
what they consider extra data at the end of the reply.

(Note: fixing the byte order in the server requires that the client send
a byte order indication to the server, so *either* fix works only
between an updated client and an updated server.  We already have
optional data in the authentication reply, to allow updated servers and
clients to negotiate a protocol version while still allowing updated
clients to work with older servers and older clients to work with
updated servers, so this just continues that mechanism.)

CMakeLists.txt
Makefile.in
pcap-common.c
pcap-common.h
pcap-rpcap.c
pcap-util.c [new file with mode: 0644]
pcap-util.h [new file with mode: 0644]
rpcap-protocol.h
rpcapd/daemon.c
sf-pcap.c
sf-pcapng.c

index 982a0d0a0ebb58b06f1b065ab823cbc8b92cc8b0..b8cdcb82d3375b8f5f3acbfdecf010df9ebe897e 100644 (file)
@@ -1195,6 +1195,7 @@ set(PROJECT_SOURCE_LIST_C
     pcap-common.c
     pcap-options.c
     pcap-usb-linux-common.c
+    pcap-util.c
     pcap.c
     savefile.c
     sf-pcapng.c
index 2b1875d7ae0ae7e1c70462eb1059a51b95088a25..b5de882d907294ca254e52317b08f8fe22e46398 100644 (file)
@@ -92,7 +92,7 @@ PLATFORM_CXX_SRC =    @PLATFORM_CXX_SRC@
 MODULE_C_SRC =         @MODULE_C_SRC@
 REMOTE_C_SRC =         @REMOTE_C_SRC@
 COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
-               fmtutils.c \
+               fmtutils.c pcap-util.c \
                savefile.c sf-pcap.c sf-pcapng.c pcap-common.c pcap-options.c \
                pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c
 GENERATED_C_SRC = scanner.c grammar.c
@@ -114,6 +114,7 @@ PUBHDR = \
        pcap.h \
        pcap-bpf.h \
        pcap-namedb.h \
+       pcap-util.h \
        pcap/bpf.h \
        pcap/bluetooth.h \
        pcap/can_socketcan.h \
index 80851cf7a65f5c809b142214b87cf663f405e49e..9738325b2e33a20335476ed846f86445fa97c50b 100644 (file)
 #include <pcap-types.h>
 
 #include "pcap-int.h"
-#include "extract.h"
-#include "pcap/sll.h"
-#include "pcap/usb.h"
-#include "pcap/nflog.h"
-#include "pcap/can_socketcan.h"
-
-#include "pflog.h"
-
-#include "pcap-usb-linux-common.h"
 
 #include "pcap-common.h"
 
@@ -1440,427 +1431,3 @@ max_snaplen_for_dlt(int dlt)
                return MAXIMUM_SNAPLEN;
        }
 }
-
-/*
- * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields
- * that are saved in host byte order.
- *
- * When reading a DLT_PFLOG packet, we need to convert those fields from
- * the byte order of the host that wrote the file to this host's byte
- * order.
- */
-static void
-swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
-{
-       u_int caplen = hdr->caplen;
-       u_int length = hdr->len;
-       u_int pfloghdr_length;
-       struct pfloghdr *pflhdr = (struct pfloghdr *)buf;
-
-       if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) ||
-           length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
-               /* Not enough data to have the uid field */
-               return;
-       }
-
-       pfloghdr_length = pflhdr->length;
-
-       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
-               /* Header doesn't include uid field */
-               return;
-       }
-       pflhdr->uid = SWAPLONG(pflhdr->uid);
-
-       if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) ||
-           length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
-               /* Not enough data to have the pid field */
-               return;
-       }
-       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
-               /* Header doesn't include pid field */
-               return;
-       }
-       pflhdr->pid = SWAPLONG(pflhdr->pid);
-
-       if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) ||
-           length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
-               /* Not enough data to have the rule_uid field */
-               return;
-       }
-       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
-               /* Header doesn't include rule_uid field */
-               return;
-       }
-       pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid);
-
-       if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) ||
-           length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
-               /* Not enough data to have the rule_pid field */
-               return;
-       }
-       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
-               /* Header doesn't include rule_pid field */
-               return;
-       }
-       pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid);
-}
-
-/*
- * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or
- * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload,
- * with the CAN ID being in host byte order.
- *
- * When reading a DLT_LINUX_SLL packet, we need to check for those
- * packets and convert the CAN ID from the byte order of the host that
- * wrote the file to this host's byte order.
- */
-static void
-swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
-{
-       u_int caplen = hdr->caplen;
-       u_int length = hdr->len;
-       struct sll_header *shdr = (struct sll_header *)buf;
-       uint16_t protocol;
-       pcap_can_socketcan_hdr *chdr;
-
-       if (caplen < (u_int) sizeof(struct sll_header) ||
-           length < (u_int) sizeof(struct sll_header)) {
-               /* Not enough data to have the protocol field */
-               return;
-       }
-
-       protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
-       if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
-               return;
-
-       /*
-        * SocketCAN packet; fix up the packet's header.
-        */
-       chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
-       if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
-           length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
-               /* Not enough data to have the CAN ID */
-               return;
-       }
-       chdr->can_id = SWAPLONG(chdr->can_id);
-}
-
-/*
- * The same applies for DLT_LINUX_SLL2.
- */
-static void
-swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf)
-{
-       u_int caplen = hdr->caplen;
-       u_int length = hdr->len;
-       struct sll2_header *shdr = (struct sll2_header *)buf;
-       uint16_t protocol;
-       pcap_can_socketcan_hdr *chdr;
-
-       if (caplen < (u_int) sizeof(struct sll2_header) ||
-           length < (u_int) sizeof(struct sll2_header)) {
-               /* Not enough data to have the protocol field */
-               return;
-       }
-
-       protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol);
-       if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
-               return;
-
-       /*
-        * SocketCAN packet; fix up the packet's header.
-        */
-       chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header));
-       if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) ||
-           length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) {
-               /* Not enough data to have the CAN ID */
-               return;
-       }
-       chdr->can_id = SWAPLONG(chdr->can_id);
-}
-
-/*
- * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
- * byte order when capturing (it's supplied directly from a
- * memory-mapped buffer shared by the kernel).
- *
- * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we
- * need to convert it from the byte order of the host that wrote the
- * file to this host's byte order.
- */
-static void
-swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
-    int header_len_64_bytes)
-{
-       pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
-       bpf_u_int32 offset = 0;
-
-       /*
-        * "offset" is the offset *past* the field we're swapping;
-        * we skip the field *before* checking to make sure
-        * the captured data length includes the entire field.
-        */
-
-       /*
-        * The URB id is a totally opaque value; do we really need to
-        * convert it to the reading host's byte order???
-        */
-       offset += 8;                    /* skip past id */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->id = SWAPLL(uhdr->id);
-
-       offset += 4;                    /* skip past various 1-byte fields */
-
-       offset += 2;                    /* skip past bus_id */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
-
-       offset += 2;                    /* skip past various 1-byte fields */
-
-       offset += 8;                    /* skip past ts_sec */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
-
-       offset += 4;                    /* skip past ts_usec */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
-
-       offset += 4;                    /* skip past status */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->status = SWAPLONG(uhdr->status);
-
-       offset += 4;                    /* skip past urb_len */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->urb_len = SWAPLONG(uhdr->urb_len);
-
-       offset += 4;                    /* skip past data_len */
-       if (hdr->caplen < offset)
-               return;
-       uhdr->data_len = SWAPLONG(uhdr->data_len);
-
-       if (uhdr->transfer_type == URB_ISOCHRONOUS) {
-               offset += 4;                    /* skip past s.iso.error_count */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
-
-               offset += 4;                    /* skip past s.iso.numdesc */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
-       } else
-               offset += 8;                    /* skip USB setup header */
-
-       /*
-        * With the old header, there are no isochronous descriptors
-        * after the header.
-        *
-        * With the new header, the actual number of descriptors in
-        * the header is not s.iso.numdesc, it's ndesc - only the
-        * first N descriptors, for some value of N, are put into
-        * the header, and ndesc is set to the actual number copied.
-        * In addition, if s.iso.numdesc is negative, no descriptors
-        * are captured, and ndesc is set to 0.
-        */
-       if (header_len_64_bytes) {
-               /*
-                * This is either the "version 1" header, with
-                * 16 bytes of additional fields at the end, or
-                * a "version 0" header from a memory-mapped
-                * capture, with 16 bytes of zeroed-out padding
-                * at the end.  Byte swap them as if this were
-                * a "version 1" header.
-                */
-               offset += 4;                    /* skip past interval */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->interval = SWAPLONG(uhdr->interval);
-
-               offset += 4;                    /* skip past start_frame */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->start_frame = SWAPLONG(uhdr->start_frame);
-
-               offset += 4;                    /* skip past xfer_flags */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
-
-               offset += 4;                    /* skip past ndesc */
-               if (hdr->caplen < offset)
-                       return;
-               uhdr->ndesc = SWAPLONG(uhdr->ndesc);
-
-               if (uhdr->transfer_type == URB_ISOCHRONOUS) {
-                       /* swap the values in struct linux_usb_isodesc */
-                       usb_isodesc *pisodesc;
-                       uint32_t i;
-
-                       pisodesc = (usb_isodesc *)(void *)(buf+offset);
-                       for (i = 0; i < uhdr->ndesc; i++) {
-                               offset += 4;            /* skip past status */
-                               if (hdr->caplen < offset)
-                                       return;
-                               pisodesc->status = SWAPLONG(pisodesc->status);
-
-                               offset += 4;            /* skip past offset */
-                               if (hdr->caplen < offset)
-                                       return;
-                               pisodesc->offset = SWAPLONG(pisodesc->offset);
-
-                               offset += 4;            /* skip past len */
-                               if (hdr->caplen < offset)
-                                       return;
-                               pisodesc->len = SWAPLONG(pisodesc->len);
-
-                               offset += 4;            /* skip past padding */
-
-                               pisodesc++;
-                       }
-               }
-       }
-}
-
-/*
- * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order
- * data.  They begin with a fixed-length header with big-endian fields,
- * followed by a set of TLVs, where the type and length are in host
- * byte order but the values are either big-endian or are a raw byte
- * sequence that's the same regardless of the host's byte order.
- *
- * When reading a DLT_NFLOG packet, we need to convert the type and
- * length values from the byte order of the host that wrote the file
- * to the byte order of this host.
- */
-static void
-swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
-{
-       u_char *p = buf;
-       nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
-       nflog_tlv_t *tlv;
-       u_int caplen = hdr->caplen;
-       u_int length = hdr->len;
-       uint16_t size;
-
-       if (caplen < (u_int) sizeof(nflog_hdr_t) ||
-           length < (u_int) sizeof(nflog_hdr_t)) {
-               /* Not enough data to have any TLVs. */
-               return;
-       }
-
-       if (nfhdr->nflog_version != 0) {
-               /* Unknown NFLOG version */
-               return;
-       }
-
-       length -= sizeof(nflog_hdr_t);
-       caplen -= sizeof(nflog_hdr_t);
-       p += sizeof(nflog_hdr_t);
-
-       while (caplen >= sizeof(nflog_tlv_t)) {
-               tlv = (nflog_tlv_t *) p;
-
-               /* Swap the type and length. */
-               tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
-               tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
-
-               /* Get the length of the TLV. */
-               size = tlv->tlv_length;
-               if (size % 4 != 0)
-                       size += 4 - size % 4;
-
-               /* Is the TLV's length less than the minimum? */
-               if (size < sizeof(nflog_tlv_t)) {
-                       /* Yes. Give up now. */
-                       return;
-               }
-
-               /* Do we have enough data for the full TLV? */
-               if (caplen < size || length < size) {
-                       /* No. */
-                       return;
-               }
-
-               /* Skip over the TLV. */
-               length -= size;
-               caplen -= size;
-               p += size;
-       }
-}
-
-void
-swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
-{
-       /*
-        * Convert pseudo-headers from the byte order of
-        * the host on which the file was saved to our
-        * byte order, as necessary.
-        */
-       switch (linktype) {
-
-       case DLT_PFLOG:
-               swap_pflog_header(hdr, data);
-               break;
-
-       case DLT_LINUX_SLL:
-               swap_linux_sll_header(hdr, data);
-               break;
-
-       case DLT_LINUX_SLL2:
-               swap_linux_sll2_header(hdr, data);
-               break;
-
-       case DLT_USB_LINUX:
-               swap_linux_usb_header(hdr, data, 0);
-               break;
-
-       case DLT_USB_LINUX_MMAPPED:
-               swap_linux_usb_header(hdr, data, 1);
-               break;
-
-       case DLT_NFLOG:
-               swap_nflog_header(hdr, data);
-               break;
-       }
-}
-
-void
-fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
-{
-       const pcap_usb_header_mmapped *usb_hdr;
-
-       usb_hdr = (const pcap_usb_header_mmapped *) data;
-       if (linktype == DLT_USB_LINUX_MMAPPED &&
-           hdr->caplen >= sizeof (pcap_usb_header_mmapped)) {
-               /*
-                * In older versions of libpcap, in memory-mapped captures,
-                * the "on-the-bus length" for completion events for
-                * incoming isochronous transfers was miscalculated; it
-                * needed to be calculated based on the* offsets and lengths
-                * in the descriptors, not on the raw URB length, but it
-                * wasn't.
-                *
-                * If this packet contains transferred data (yes, data_flag
-                * is 0 if we *do* have data), and the total on-the-network
-                * length is equal to the value calculated from the raw URB
-                * length, then it might be one of those transfers.
-                *
-                * We only do this if we hae the full USB pseudo-header.
-                */
-               if (!usb_hdr->data_flag &&
-                   hdr->len == sizeof(pcap_usb_header_mmapped) +
-                     (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) {
-                       /*
-                        * It might need fixing; fix it if it's a completion
-                        * event for an incoming isochronous transfer.
-                        */
-                       fix_linux_usb_mmapped_length(hdr, data);
-               }
-       }
-}
index cc944ef6a2e3794da2cbe7f817dd62ee5c0485b0..d765c94763267f20138fdb2eb76ad9ef9b5cd553 100644 (file)
  * pcap-common.h - common code for pcap and pcapng files
  */
 
-/*
- * We use the "receiver-makes-right" approach to byte order,
- * because time is at a premium when we are writing the file.
- * In other words, the pcap_file_header and pcap_pkthdr,
- * records are written in host byte order.
- * Note that the bytes of packet data are written out in the order in
- * which they were received, so multi-byte fields in packets are not
- * written in host byte order, they're written in whatever order the
- * sending machine put them in.
- *
- * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
- * machine (if the file was written in little-end order).
- */
-#define        SWAPLONG(y) \
-    (((((u_int)(y))&0xff)<<24) | \
-     ((((u_int)(y))&0xff00)<<8) | \
-     ((((u_int)(y))&0xff0000)>>8) | \
-     ((((u_int)(y))>>24)&0xff))
-#define        SWAPSHORT(y) \
-     ((u_short)(((((u_int)(y))&0xff)<<8) | \
-                ((((u_int)(y))&0xff00)>>8)))
-
 extern int dlt_to_linktype(int dlt);
 
 extern int linktype_to_dlt(int linktype);
 
-extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr,
-    u_char *data);
-
-extern void fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr,
-    const u_char *data);
-
 extern u_int max_snaplen_for_dlt(int dlt);
index c85acc2c1808e2589a6e41ea4acc5e8292736633..f7d4e0cc80f2c3bfde53bb8b466f9744807aeacb 100644 (file)
@@ -45,6 +45,7 @@
 #include <limits.h>            /* for INT_MAX */
 #include "sockutils.h"
 #include "pcap-int.h"
+#include "pcap-util.h"
 #include "rpcap-protocol.h"
 #include "pcap-rpcap.h"
 
@@ -95,6 +96,7 @@ struct activehosts
        SOCKET sockctrl;
        SSL *ssl;
        uint8_t protocol_version;
+       int byte_swapped;
        struct activehosts *next;
 };
 
@@ -130,6 +132,7 @@ struct pcap_rpcap {
 
        uint8_t protocol_version;       /* negotiated protocol version */
        uint8_t uses_ssl;               /* User asked for rpcaps scheme */
+       int byte_swapped;               /* Server byte order is swapped from ours */
 
        unsigned int TotNetDrops;       /* keeps the number of packets that have been dropped by the network */
 
@@ -684,9 +687,14 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us
                if (ret == 1)
                {
                        /*
-                        * We got a packet.  Hand it to the callback
-                        * and count it so we can return the count.
+                        * We got a packet.
+                        *
+                        * Do whatever post-processing is necessary, hand
+                        * it to the callback, and count it so we can
+                        * return the count.
                         */
+                       pcap_post_process(p->linktype, pr->byte_swapped,
+                           &pkt_header, pkt_data);
                        (*callback)(user, &pkt_header, pkt_data);
                        n++;
                }
@@ -1945,6 +1953,10 @@ static int pcap_setsampling_remote(pcap_t *fp)
  * \param ver: pointer to variable to which to set the protocol version
  * number we selected.
  *
+ * \param byte_swapped: pointer to variable to which to set 1 if the
+ * byte order the server says it has is byte-swapped from ours, 0
+ * otherwise (whether it's the same as ours or is unknown).
+ *
  * \param auth: authentication parameters that have to be sent.
  *
  * \param errbuf: a pointer to a user-allocated buffer (of size
@@ -1955,7 +1967,8 @@ static int pcap_setsampling_remote(pcap_t *fp)
  * \return '0' if everything is fine, '-1' for an error.  For errors,
  * an error message string is returned in the 'errbuf' variable.
  */
-static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver,
+    int *byte_swapped, struct pcap_rmtauth *auth, char *errbuf)
 {
        char sendbuf[RPCAP_NETBUF_SIZE];        /* temporary buffer in which data that has to be sent is buffered */
        int sendbufidx = 0;                     /* index which keeps the number of bytes currently buffered */
@@ -1967,6 +1980,8 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmt
        uint32_t plen;
        struct rpcap_authreply authreply;       /* authentication reply message */
        uint8_t ourvers;
+       int has_byte_order;                     /* The server sent its version of the byte-order magic number */
+       u_int their_byte_order_magic;           /* Here's what it is */
 
        if (auth)
        {
@@ -2071,8 +2086,10 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmt
        plen = header.plen;
        if (plen != 0)
        {
-               /* Yes - is it big enough to be version information? */
-               if (plen < sizeof(struct rpcap_authreply))
+               size_t reply_len;
+
+               /* Yes - is it big enough to include version information? */
+               if (plen < sizeof(struct rpcap_authreply_old))
                {
                        /* No - discard it and fail. */
                        snprintf(errbuf, PCAP_ERRBUF_SIZE,
@@ -2081,9 +2098,34 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmt
                        return -1;
                }
 
+               /* Yes - does it include server byte order information? */
+               if (plen == sizeof(struct rpcap_authreply_old))
+               {
+                       /* No - just read the version information */
+                       has_byte_order = 0;
+                       reply_len = sizeof(struct rpcap_authreply_old);
+               }
+               else if (plen >= sizeof(struct rpcap_authreply_old))
+               {
+                       /* Yes - read it all. */
+                       has_byte_order = 1;
+                       reply_len = sizeof(struct rpcap_authreply);
+               }
+               else
+               {
+                       /*
+                        * Too long for old reply, too short for new reply.
+                        * Discard it and fail.
+                        */
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "Authenticaton reply from server is too short");
+                       (void)rpcap_discard(sockctrl, ssl, plen, NULL);
+                       return -1;
+               }
+
                /* Read the reply body */
                if (rpcap_recv(sockctrl, ssl, (char *)&authreply,
-                   sizeof(struct rpcap_authreply), &plen, errbuf) == -1)
+                   reply_len, &plen, errbuf) == -1)
                {
                        (void)rpcap_discard(sockctrl, ssl, plen, NULL);
                        return -1;
@@ -2106,12 +2148,32 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmt
                            "The server's minimum supported protocol version is greater than its maximum supported protocol version");
                        return -1;
                }
+
+               if (has_byte_order)
+               {
+                       their_byte_order_magic = authreply.byte_order_magic;
+               }
+               else
+               {
+                       /*
+                        * The server didn't tell us what its byte
+                        * order is; assume it's ours.
+                        */
+                       their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC;;
+               }
        }
        else
        {
                /* No - it supports only version 0. */
                authreply.minvers = 0;
                authreply.maxvers = 0;
+
+               /*
+                * And it didn't tell us what its byte order is; assume
+                * it's ours.
+                */
+               has_byte_order = 0;
+               their_byte_order_magic = RPCAP_BYTE_ORDER_MAGIC;
        }
 
        /*
@@ -2144,6 +2206,27 @@ static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8_t *ver, struct pcap_rmt
                        goto novers;
        }
 
+       /*
+        * Is the server byte order the opposite of ours?
+        */
+       if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC)
+       {
+               /* No, it's the same. */
+               *byte_swapped = 0;
+       }
+       else if (their_byte_order_magic == RPCAP_BYTE_ORDER_MAGIC_SWAPPED)
+       {
+               /* Yes, it's the opposite of ours. */
+               *byte_swapped = 1;
+       }
+       else
+       {
+               /* They sent us something bogus. */
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "The server did not send us a valid byte order value");
+               return -1;
+       }
+
        *ver = ourvers;
        return 0;
 
@@ -2164,7 +2247,8 @@ static const char userinfo_allowed_symbols[] = "-._~!&'()*+,;=";
  * struct created from a username and password parsed out of the userinfo
  * portion of a URI.
  */
-static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8_t *ver, const char *userinfo, char *errbuf)
+static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8_t *ver,
+    int *byte_swapped, const char *userinfo, char *errbuf)
 {
        struct pcap_rmtauth auth;
        const char *ptr;
@@ -2222,10 +2306,11 @@ static int rpcap_doauth_userinfo(SOCKET sockctrl, SSL *ssl, uint8_t *ver, const
                        }
                }
 
-               return rpcap_doauth(sockctrl, ssl, ver, &auth, errbuf);
+               return rpcap_doauth(sockctrl, ssl, ver, byte_swapped, &auth,
+                   errbuf);
        }
 
-       return rpcap_doauth(sockctrl, ssl, ver, NULL, errbuf);
+       return rpcap_doauth(sockctrl, ssl, ver, byte_swapped, NULL, errbuf);
 }
 
 
@@ -2249,8 +2334,8 @@ pcap_setnonblock_rpcap(pcap_t *p, int nonblock _U_)
 static int
 rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
     int *activep, SOCKET *sockctrlp, uint8_t *uses_sslp, SSL **sslp,
-    int rmt_flags, uint8_t *protocol_versionp, char *host, char *port,
-    char *iface, char *errbuf)
+    int rmt_flags, uint8_t *protocol_versionp, int *byte_swappedp,
+    char *host, char *port, char *iface, char *errbuf)
 {
        int type;
        int auth_result;
@@ -2303,6 +2388,7 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
                *sockctrlp = activeconn->sockctrl;
                *sslp = activeconn->ssl;
                *protocol_versionp = activeconn->protocol_version;
+               *byte_swappedp = activeconn->byte_swapped;
        }
        else
        {
@@ -2371,13 +2457,13 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
 
                if (auth == NULL && *userinfo != '\0')
                {
-                       auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp, protocol_versionp,
-                           userinfo, errbuf);
+                       auth_result = rpcap_doauth_userinfo(*sockctrlp, *sslp,
+                           protocol_versionp, byte_swappedp, userinfo, errbuf);
                }
                else
                {
-                       auth_result = rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
-                           errbuf);
+                       auth_result = rpcap_doauth(*sockctrlp, *sslp,
+                           protocol_versionp, byte_swappedp, auth, errbuf);
                }
 
                if (auth_result == -1)
@@ -2446,6 +2532,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
        SOCKET sockctrl;
        SSL *ssl = NULL;
        uint8_t protocol_version;               /* negotiated protocol version */
+       int byte_swapped;                       /* server is known to be byte-swapped */
        int active;
        uint32_t plen;
        char sendbuf[RPCAP_NETBUF_SIZE];        /* temporary buffer in which data to be sent is buffered */
@@ -2491,8 +2578,8 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
         * Attempt to set up the session with the server.
         */
        if (rpcap_setup_session(fp->opt.device, auth, &active, &sockctrl,
-           &pr->uses_ssl, &ssl, flags, &protocol_version, host, ctrlport,
-           iface, errbuf) == -1)
+           &pr->uses_ssl, &ssl, flags, &protocol_version, &byte_swapped,
+           host, ctrlport, iface, errbuf) == -1)
        {
                /* Session setup failed. */
                pcap_close(fp);
@@ -2541,6 +2628,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
        pr->rmt_sockctrl = sockctrl;
        pr->ctrl_ssl = ssl;
        pr->protocol_version = protocol_version;
+       pr->byte_swapped = byte_swapped;
        pr->rmt_clientside = 1;
 
        /* This code is duplicated from the end of this function */
@@ -2612,6 +2700,7 @@ int
 pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
 {
        uint8_t protocol_version;       /* protocol version */
+       int byte_swapped;               /* Server byte order is swapped from ours */
        SOCKET sockctrl;                /* socket descriptor of the control connection */
        SSL *ssl = NULL;                /* optional SSL handler for sockctrl */
        uint32_t plen;
@@ -2633,7 +2722,8 @@ pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_i
         * Attempt to set up the session with the server.
         */
        if (rpcap_setup_session(source, auth, &active, &sockctrl, &uses_ssl,
-           &ssl, 0, &protocol_version, host, port, NULL, errbuf) == -1)
+           &ssl, 0, &protocol_version, &byte_swapped, host, port, NULL,
+           errbuf) == -1)
        {
                /* Session setup failed. */
                return -1;
@@ -2925,6 +3015,7 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha
        SOCKET sockctrl;                                /* keeps the main socket identifier */
        SSL *ssl = NULL;                                /* Optional SSL handler for sockctrl */
        uint8_t protocol_version;               /* negotiated protocol version */
+       int byte_swapped;                       /* 1 if server byte order is known to be the reverse of ours */
        struct activehosts *temp, *prev;        /* temp var needed to scan he host list chain */
 
        *connectinghost = 0;            /* just in case */
@@ -3035,7 +3126,8 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha
        /*
         * Send authentication to the remote machine.
         */
-       if (rpcap_doauth(sockctrl, ssl, &protocol_version, auth, errbuf) == -1)
+       if (rpcap_doauth(sockctrl, ssl, &protocol_version, &byte_swapped,
+           auth, errbuf) == -1)
        {
                /* Unrecoverable error. */
                rpcap_senderror(sockctrl, ssl, 0, PCAP_ERR_REMOTEACCEPT, errbuf, NULL);
@@ -3100,6 +3192,7 @@ SOCKET pcap_remoteact_accept_ex(const char *address, const char *port, const cha
        temp->sockctrl = sockctrl;
        temp->ssl = ssl;
        temp->protocol_version = protocol_version;
+       temp->byte_swapped = byte_swapped;
        temp->next = NULL;
 
        return sockctrl;
diff --git a/pcap-util.c b/pcap-util.c
new file mode 100644 (file)
index 0000000..7f92caf
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-common.c - common code for pcap and pcapng files
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pcap-types.h>
+
+#include "pcap-int.h"
+#include "extract.h"
+#include "pcap-usb-linux-common.h"
+
+#include "pcap-util.h"
+
+#include "pflog.h"
+#include "pcap/can_socketcan.h"
+#include "pcap/sll.h"
+#include "pcap/usb.h"
+#include "pcap/nflog.h"
+
+/*
+ * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields
+ * that are saved in host byte order.
+ *
+ * When reading a DLT_PFLOG packet, we need to convert those fields from
+ * the byte order of the host that wrote the file to this host's byte
+ * order.
+ */
+static void
+swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       u_int pfloghdr_length;
+       struct pfloghdr *pflhdr = (struct pfloghdr *)buf;
+
+       if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) ||
+           length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
+               /* Not enough data to have the uid field */
+               return;
+       }
+
+       pfloghdr_length = pflhdr->length;
+
+       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
+               /* Header doesn't include uid field */
+               return;
+       }
+       pflhdr->uid = SWAPLONG(pflhdr->uid);
+
+       if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) ||
+           length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
+               /* Not enough data to have the pid field */
+               return;
+       }
+       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
+               /* Header doesn't include pid field */
+               return;
+       }
+       pflhdr->pid = SWAPLONG(pflhdr->pid);
+
+       if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) ||
+           length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
+               /* Not enough data to have the rule_uid field */
+               return;
+       }
+       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
+               /* Header doesn't include rule_uid field */
+               return;
+       }
+       pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid);
+
+       if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) ||
+           length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
+               /* Not enough data to have the rule_pid field */
+               return;
+       }
+       if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
+               /* Header doesn't include rule_pid field */
+               return;
+       }
+       pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid);
+}
+
+/*
+ * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or
+ * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload,
+ * with the CAN ID being in host byte order.
+ *
+ * When reading a DLT_LINUX_SLL packet, we need to check for those
+ * packets and convert the CAN ID from the byte order of the host that
+ * wrote the file to this host's byte order.
+ */
+static void
+swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       struct sll_header *shdr = (struct sll_header *)buf;
+       uint16_t protocol;
+       pcap_can_socketcan_hdr *chdr;
+
+       if (caplen < (u_int) sizeof(struct sll_header) ||
+           length < (u_int) sizeof(struct sll_header)) {
+               /* Not enough data to have the protocol field */
+               return;
+       }
+
+       protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
+       if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
+               return;
+
+       /*
+        * SocketCAN packet; fix up the packet's header.
+        */
+       chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
+       if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
+           length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
+               /* Not enough data to have the CAN ID */
+               return;
+       }
+       chdr->can_id = SWAPLONG(chdr->can_id);
+}
+
+/*
+ * The same applies for DLT_LINUX_SLL2.
+ */
+static void
+swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       struct sll2_header *shdr = (struct sll2_header *)buf;
+       uint16_t protocol;
+       pcap_can_socketcan_hdr *chdr;
+
+       if (caplen < (u_int) sizeof(struct sll2_header) ||
+           length < (u_int) sizeof(struct sll2_header)) {
+               /* Not enough data to have the protocol field */
+               return;
+       }
+
+       protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol);
+       if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
+               return;
+
+       /*
+        * SocketCAN packet; fix up the packet's header.
+        */
+       chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header));
+       if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) ||
+           length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) {
+               /* Not enough data to have the CAN ID */
+               return;
+       }
+       chdr->can_id = SWAPLONG(chdr->can_id);
+}
+
+/*
+ * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
+ * byte order when capturing (it's supplied directly from a
+ * memory-mapped buffer shared by the kernel).
+ *
+ * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we
+ * need to convert it from the byte order of the host that wrote the
+ * file to this host's byte order.
+ */
+static void
+swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
+    int header_len_64_bytes)
+{
+       pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
+       bpf_u_int32 offset = 0;
+
+       /*
+        * "offset" is the offset *past* the field we're swapping;
+        * we skip the field *before* checking to make sure
+        * the captured data length includes the entire field.
+        */
+
+       /*
+        * The URB id is a totally opaque value; do we really need to
+        * convert it to the reading host's byte order???
+        */
+       offset += 8;                    /* skip past id */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->id = SWAPLL(uhdr->id);
+
+       offset += 4;                    /* skip past various 1-byte fields */
+
+       offset += 2;                    /* skip past bus_id */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
+
+       offset += 2;                    /* skip past various 1-byte fields */
+
+       offset += 8;                    /* skip past ts_sec */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
+
+       offset += 4;                    /* skip past ts_usec */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
+
+       offset += 4;                    /* skip past status */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->status = SWAPLONG(uhdr->status);
+
+       offset += 4;                    /* skip past urb_len */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->urb_len = SWAPLONG(uhdr->urb_len);
+
+       offset += 4;                    /* skip past data_len */
+       if (hdr->caplen < offset)
+               return;
+       uhdr->data_len = SWAPLONG(uhdr->data_len);
+
+       if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+               offset += 4;                    /* skip past s.iso.error_count */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
+
+               offset += 4;                    /* skip past s.iso.numdesc */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
+       } else
+               offset += 8;                    /* skip USB setup header */
+
+       /*
+        * With the old header, there are no isochronous descriptors
+        * after the header.
+        *
+        * With the new header, the actual number of descriptors in
+        * the header is not s.iso.numdesc, it's ndesc - only the
+        * first N descriptors, for some value of N, are put into
+        * the header, and ndesc is set to the actual number copied.
+        * In addition, if s.iso.numdesc is negative, no descriptors
+        * are captured, and ndesc is set to 0.
+        */
+       if (header_len_64_bytes) {
+               /*
+                * This is either the "version 1" header, with
+                * 16 bytes of additional fields at the end, or
+                * a "version 0" header from a memory-mapped
+                * capture, with 16 bytes of zeroed-out padding
+                * at the end.  Byte swap them as if this were
+                * a "version 1" header.
+                */
+               offset += 4;                    /* skip past interval */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->interval = SWAPLONG(uhdr->interval);
+
+               offset += 4;                    /* skip past start_frame */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->start_frame = SWAPLONG(uhdr->start_frame);
+
+               offset += 4;                    /* skip past xfer_flags */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
+
+               offset += 4;                    /* skip past ndesc */
+               if (hdr->caplen < offset)
+                       return;
+               uhdr->ndesc = SWAPLONG(uhdr->ndesc);
+
+               if (uhdr->transfer_type == URB_ISOCHRONOUS) {
+                       /* swap the values in struct linux_usb_isodesc */
+                       usb_isodesc *pisodesc;
+                       uint32_t i;
+
+                       pisodesc = (usb_isodesc *)(void *)(buf+offset);
+                       for (i = 0; i < uhdr->ndesc; i++) {
+                               offset += 4;            /* skip past status */
+                               if (hdr->caplen < offset)
+                                       return;
+                               pisodesc->status = SWAPLONG(pisodesc->status);
+
+                               offset += 4;            /* skip past offset */
+                               if (hdr->caplen < offset)
+                                       return;
+                               pisodesc->offset = SWAPLONG(pisodesc->offset);
+
+                               offset += 4;            /* skip past len */
+                               if (hdr->caplen < offset)
+                                       return;
+                               pisodesc->len = SWAPLONG(pisodesc->len);
+
+                               offset += 4;            /* skip past padding */
+
+                               pisodesc++;
+                       }
+               }
+       }
+}
+
+/*
+ * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order
+ * data.  They begin with a fixed-length header with big-endian fields,
+ * followed by a set of TLVs, where the type and length are in host
+ * byte order but the values are either big-endian or are a raw byte
+ * sequence that's the same regardless of the host's byte order.
+ *
+ * When reading a DLT_NFLOG packet, we need to convert the type and
+ * length values from the byte order of the host that wrote the file
+ * to the byte order of this host.
+ */
+static void
+swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
+{
+       u_char *p = buf;
+       nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
+       nflog_tlv_t *tlv;
+       u_int caplen = hdr->caplen;
+       u_int length = hdr->len;
+       uint16_t size;
+
+       if (caplen < (u_int) sizeof(nflog_hdr_t) ||
+           length < (u_int) sizeof(nflog_hdr_t)) {
+               /* Not enough data to have any TLVs. */
+               return;
+       }
+
+       if (nfhdr->nflog_version != 0) {
+               /* Unknown NFLOG version */
+               return;
+       }
+
+       length -= sizeof(nflog_hdr_t);
+       caplen -= sizeof(nflog_hdr_t);
+       p += sizeof(nflog_hdr_t);
+
+       while (caplen >= sizeof(nflog_tlv_t)) {
+               tlv = (nflog_tlv_t *) p;
+
+               /* Swap the type and length. */
+               tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
+               tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
+
+               /* Get the length of the TLV. */
+               size = tlv->tlv_length;
+               if (size % 4 != 0)
+                       size += 4 - size % 4;
+
+               /* Is the TLV's length less than the minimum? */
+               if (size < sizeof(nflog_tlv_t)) {
+                       /* Yes. Give up now. */
+                       return;
+               }
+
+               /* Do we have enough data for the full TLV? */
+               if (caplen < size || length < size) {
+                       /* No. */
+                       return;
+               }
+
+               /* Skip over the TLV. */
+               length -= size;
+               caplen -= size;
+               p += size;
+       }
+}
+
+static void
+swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
+{
+       /*
+        * Convert pseudo-headers from the byte order of
+        * the host on which the file was saved to our
+        * byte order, as necessary.
+        */
+       switch (linktype) {
+
+       case DLT_PFLOG:
+               swap_pflog_header(hdr, data);
+               break;
+
+       case DLT_LINUX_SLL:
+               swap_linux_sll_header(hdr, data);
+               break;
+
+       case DLT_LINUX_SLL2:
+               swap_linux_sll2_header(hdr, data);
+               break;
+
+       case DLT_USB_LINUX:
+               swap_linux_usb_header(hdr, data, 0);
+               break;
+
+       case DLT_USB_LINUX_MMAPPED:
+               swap_linux_usb_header(hdr, data, 1);
+               break;
+
+       case DLT_NFLOG:
+               swap_nflog_header(hdr, data);
+               break;
+       }
+}
+
+void
+pcap_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr,
+    u_char *data)
+{
+       if (swapped)
+               swap_pseudo_headers(linktype, hdr, data);
+
+       fixup_pcap_pkthdr(linktype, hdr, data);
+}
+
+void
+fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
+{
+       const pcap_usb_header_mmapped *usb_hdr;
+
+       usb_hdr = (const pcap_usb_header_mmapped *) data;
+       if (linktype == DLT_USB_LINUX_MMAPPED &&
+           hdr->caplen >= sizeof (pcap_usb_header_mmapped)) {
+               /*
+                * In older versions of libpcap, in memory-mapped captures,
+                * the "on-the-bus length" for completion events for
+                * incoming isochronous transfers was miscalculated; it
+                * needed to be calculated based on the* offsets and lengths
+                * in the descriptors, not on the raw URB length, but it
+                * wasn't.
+                *
+                * If this packet contains transferred data (yes, data_flag
+                * is 0 if we *do* have data), and the total on-the-network
+                * length is equal to the value calculated from the raw URB
+                * length, then it might be one of those transfers.
+                *
+                * We only do this if we hae the full USB pseudo-header.
+                */
+               if (!usb_hdr->data_flag &&
+                   hdr->len == sizeof(pcap_usb_header_mmapped) +
+                     (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) {
+                       /*
+                        * It might need fixing; fix it if it's a completion
+                        * event for an incoming isochronous transfer.
+                        */
+                       fix_linux_usb_mmapped_length(hdr, data);
+               }
+       }
+}
diff --git a/pcap-util.h b/pcap-util.h
new file mode 100644 (file)
index 0000000..de95819
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-util.h - common code for various files
+ */
+
+/*
+ * We use the "receiver-makes-right" approach to byte order;
+ * because time is at a premium when we are writing the file.
+ * In other words, the pcap_file_header and pcap_pkthdr,
+ * records are written in host byte order.
+ * Note that the bytes of packet data are written out in the order in
+ * which they were received, so multi-byte fields in packets are not
+ * written in host byte order, they're written in whatever order the
+ * sending machine put them in.
+ *
+ * We also use this for fixing up packet data headers from a remote
+ * capture, where the server may have a different byte order from the
+ * client.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define        SWAPLONG(y) \
+    (((((u_int)(y))&0xff)<<24) | \
+     ((((u_int)(y))&0xff00)<<8) | \
+     ((((u_int)(y))&0xff0000)>>8) | \
+     ((((u_int)(y))>>24)&0xff))
+#define        SWAPSHORT(y) \
+     ((u_short)(((((u_int)(y))&0xff)<<8) | \
+                ((((u_int)(y))&0xff00)>>8)))
+
+extern void pcap_post_process(int linktype, int swapped,
+    struct pcap_pkthdr *hdr, u_char *data);
+
+extern void fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr,
+    const u_char *data);
+
index 7f6574c1078668a072d406dbc41a34469cede77c..ffb401d302e6c2aa274faac524827630d00f18dd 100644 (file)
@@ -151,6 +151,25 @@ struct rpcap_header
  * Older servers don't provide this; they support only version 0.
  */
 struct rpcap_authreply
+{
+       uint8_t minvers;                /* Minimum version supported */
+       uint8_t maxvers;                /* Maximum version supported */
+       uint8_t pad[2];                 /* Pad to 4-byte boundary **/
+       uint32_t byte_order_magic;      /* RPCAP_BYTE_ORDER_MAGIC, in server byte order */
+};
+
+/*
+ * Any resemblance between this and the pcap file magic number
+ * is purely coincidental, trust me.
+ */
+#define RPCAP_BYTE_ORDER_MAGIC         0xa1b2c3d4U
+#define RPCAP_BYTE_ORDER_MAGIC_SWAPPED 0xd4c3b2a1U
+
+/*
+ * Older version of authentication reply, without byte order indication
+ * and padding.
+ */
+struct rpcap_authreply_old
 {
        uint8_t minvers;        /* Minimum version supported */
        uint8_t maxvers;        /* Maximum version supported */
index c5e2290800e8175219c2709e2452c4ad4e4db97f..0f3dd27153325de1ee77ac2798dfb77574356df1 100644 (file)
@@ -1371,11 +1371,16 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32_t plen)
                goto error;
 
        //
-       // Indicate to our peer what versions we support.
+       // Indicate to our peer what versions we support and what our
+       // version of the byte-order magic is (which will tell the
+       // client whether our byte order differs from theirs, in which
+       // case they will need to byte-swap some fields in some
+       // link-layer types' headers).
        //
        memset(authreply, 0, sizeof(struct rpcap_authreply));
        authreply->minvers = RPCAP_MIN_VERSION;
        authreply->maxvers = RPCAP_MAX_VERSION;
+       authreply->byte_order_magic = RPCAP_BYTE_ORDER_MAGIC;
 
        // Send the reply.
        if (sock_send(pars->sockctrl, pars->ssl, sendbuf, sendbufidx, errbuf, PCAP_ERRBUF_SIZE) == -1)
index 05119b579545d8a5f172f7740dc9eed8b4249a77..0aed3e8ffe0d50107345c2e8f9e9df0cefb23cd4 100644 (file)
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -46,6 +46,7 @@
 #include <limits.h> /* for INT_MAX */
 
 #include "pcap-int.h"
+#include "pcap-util.h"
 
 #include "pcap-common.h"
 
@@ -705,10 +706,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
        }
        *data = p->buffer;
 
-       if (p->swapped)
-               swap_pseudo_headers(p->linktype, hdr, *data);
-
-       fixup_pcap_pkthdr(p->linktype, hdr, *data);
+       pcap_post_process(p->linktype, p->swapped, hdr, *data);
 
        return (1);
 }
index 4791b288c0fd108b74091be2addbb945cc5173c3..058a7244d62a42f119f27bc529888060eca84bae 100644 (file)
@@ -34,6 +34,7 @@
 #include <string.h>
 
 #include "pcap-int.h"
+#include "pcap-util.h"
 
 #include "pcap-common.h"
 
@@ -1511,10 +1512,7 @@ found:
        if (*data == NULL)
                return (-1);
 
-       if (p->swapped)
-               swap_pseudo_headers(p->linktype, hdr, *data);
-
-       fixup_pcap_pkthdr(p->linktype, hdr, *data);
+       pcap_post_process(p->linktype, p->swapped, hdr, *data);
 
        return (1);
 }