diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | pcap-common.c | 433 | ||||
-rw-r--r-- | pcap-common.h | 28 | ||||
-rw-r--r-- | pcap-rpcap.c | 131 | ||||
-rw-r--r-- | pcap-util.c | 474 | ||||
-rw-r--r-- | pcap-util.h | 55 | ||||
-rw-r--r-- | rpcap-protocol.h | 19 | ||||
-rw-r--r-- | rpcapd/daemon.c | 7 | ||||
-rw-r--r-- | sf-pcap.c | 6 | ||||
-rw-r--r-- | sf-pcapng.c | 6 |
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) @@ -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); } |