aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <gharris@sonic.net>2022-08-06 04:00:43 -0700
committerGuy Harris <gharris@sonic.net>2022-08-27 17:35:47 -0700
commit8f673ec2450ea521dd81e0340cacb1cf7e47c65e (patch)
tree85687866244a3d97607787c12bcad618504a40af
parentdb808064ab25b9d06332cc84331163b8c8f352a5 (diff)
downloadlibpcap-8f673ec2450ea521dd81e0340cacb1cf7e47c65e.tar.gz
rpcap: have the server tell the client its byte order.
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.) (backported from commit dc14a7babca1471809bee6872539ff836937840e)
-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.c119
-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, 666 insertions, 485 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c03e2ad..42e7861d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1194,6 +1194,7 @@ set(PROJECT_SOURCE_LIST_C
optimize.c
pcap-common.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 5dc731c3..f5cb23d8 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-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 ee48339d..b1caee38 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"
@@ -1405,427 +1396,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 f15b2102..7cfa512f 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 protocol_version;
+ int byte_swapped;
struct activehosts *next;
};
@@ -130,6 +132,7 @@ struct pcap_rpcap {
uint8 protocol_version; /* negotiated protocol version */
uint8 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 *ver, struct pcap_rmtauth *auth, char *errbuf)
+static int rpcap_doauth(SOCKET sockctrl, SSL *ssl, uint8 *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 *ver, struct pcap_rmtau
uint32 plen;
struct rpcap_authreply authreply; /* authentication reply message */
uint8 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 *ver, struct pcap_rmtau
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 *ver, struct pcap_rmtau
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 *ver, struct pcap_rmtau
"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 *ver, struct pcap_rmtau
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;
@@ -2176,8 +2259,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 *uses_sslp, SSL **sslp,
- int rmt_flags, uint8 *protocol_versionp, char *host, char *port,
- char *iface, char *errbuf)
+ int rmt_flags, uint8 *protocol_versionp, int *byte_swappedp,
+ char *host, char *port, char *iface, char *errbuf)
{
int type;
struct activehosts *activeconn; /* active connection, if there is one */
@@ -2227,6 +2310,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
{
@@ -2293,8 +2377,8 @@ rpcap_setup_session(const char *source, struct pcap_rmtauth *auth,
#endif
}
- if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp, auth,
- errbuf) == -1)
+ if (rpcap_doauth(*sockctrlp, *sslp, protocol_versionp,
+ byte_swappedp, auth, errbuf) == -1)
{
#ifdef HAVE_OPENSSL
if (*sslp)
@@ -2360,6 +2444,7 @@ pcap_t *pcap_open_rpcap(const char *source, int snaplen, int flags, int read_tim
SOCKET sockctrl;
SSL *ssl = NULL;
uint8 protocol_version; /* negotiated protocol version */
+ int byte_swapped; /* server is known to be byte-swapped */
int active;
uint32 plen;
char sendbuf[RPCAP_NETBUF_SIZE]; /* temporary buffer in which data to be sent is buffered */
@@ -2405,8 +2490,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);
@@ -2455,6 +2540,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 */
@@ -2526,6 +2612,7 @@ int
pcap_findalldevs_ex_remote(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
{
uint8 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 plen;
@@ -2547,7 +2634,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;
@@ -2839,6 +2927,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 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 */
@@ -2949,7 +3038,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);
@@ -3014,6 +3104,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 88d5133a..a93b0a8b 100644
--- a/rpcap-protocol.h
+++ b/rpcap-protocol.h
@@ -157,6 +157,25 @@ struct rpcap_header
*/
struct rpcap_authreply
{
+ uint8 minvers; /* Minimum version supported */
+ uint8 maxvers; /* Maximum version supported */
+ uint8 pad[2]; /* Pad to 4-byte boundary **/
+ uint32 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 minvers; /* Minimum version supported */
uint8 maxvers; /* Maximum version supported */
};
diff --git a/rpcapd/daemon.c b/rpcapd/daemon.c
index 3cf2dc75..9b0f8285 100644
--- a/rpcapd/daemon.c
+++ b/rpcapd/daemon.c
@@ -1371,11 +1371,16 @@ daemon_msg_auth_req(struct daemon_slpars *pars, uint32 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 90fac890..254dbdb5 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"
@@ -706,10 +707,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);
}