summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile.in3
-rw-r--r--pcap-common.c433
-rw-r--r--pcap-common.h28
-rw-r--r--pcap-rpcap.c131
-rw-r--r--pcap-util.c474
-rw-r--r--pcap-util.h55
-rw-r--r--rpcap-protocol.h19
-rw-r--r--rpcapd/daemon.c7
-rw-r--r--sf-pcap.c6
-rw-r--r--sf-pcapng.c6
11 files changed, 673 insertions, 490 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 982a0d0a..b8cdcb82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/Makefile.in b/Makefile.in
index 2b1875d7..b5de882d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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 \
diff --git a/pcap-common.c b/pcap-common.c
index 80851cf7..9738325b 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -28,15 +28,6 @@
#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);
- }
- }
-}
diff --git a/pcap-common.h b/pcap-common.h
index cc944ef6..d765c947 100644
--- a/pcap-common.h
+++ b/pcap-common.h
@@ -21,36 +21,8 @@
* 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);
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index c85acc2c..f7d4e0cc 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -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
index 00000000..7f92cafc
--- /dev/null
+++ b/pcap-util.c
@@ -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
index 00000000..de958191
--- /dev/null
+++ b/pcap-util.h
@@ -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);
+
diff --git a/rpcap-protocol.h b/rpcap-protocol.h
index 7f6574c1..ffb401d3 100644
--- a/rpcap-protocol.h
+++ b/rpcap-protocol.h
@@ -152,6 +152,25 @@ struct rpcap_header
*/
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 */
};
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index c5e22908..0f3dd271 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -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)
diff --git a/sf-pcap.c b/sf-pcap.c
index 05119b57..0aed3e8f 100644
--- 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);
}
diff --git a/sf-pcapng.c b/sf-pcapng.c
index 4791b288..058a7244 100644
--- a/sf-pcapng.c
+++ b/sf-pcapng.c
@@ -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);
}