summaryrefslogtreecommitdiff
path: root/pcap-common.c
diff options
context:
space:
mode:
authorGuy Harris <gharris@sonic.net>2022-08-06 04:00:43 -0700
committerGuy Harris <gharris@sonic.net>2022-08-06 04:00:43 -0700
commitdc14a7babca1471809bee6872539ff836937840e (patch)
tree509a5c102eeb6b9f459c355dd022a5d7a7645a36 /pcap-common.c
parent26b8f2e55c25a0c6a1e17d2e9590063224890d6a (diff)
downloadlibpcap-dc14a7babca1471809bee6872539ff836937840e.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.)
Diffstat (limited to 'pcap-common.c')
-rw-r--r--pcap-common.c433
1 files changed, 0 insertions, 433 deletions
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);
- }
- }
-}