aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2014-02-02 20:04:02 -0800
committerGuy Harris <guy@alum.mit.edu>2014-02-02 20:04:02 -0800
commit13d800e5f69260cdd96735152a8d72fe8b9e7e47 (patch)
tree32008657648ad07ad77edd4096338e1506abb398
parent1afede12639585b32f85444c477555ed04783dbf (diff)
downloadlibpcap-13d800e5f69260cdd96735152a8d72fe8b9e7e47.tar.gz
Byte-swap the T and L in TLVs as necessary when reading an NFLOG file.
That means that, when reading a LINKTYPE_NFLOG file, the type and length values are in the byte order of the host *reading* the file, rather than the host that *wrote* the file, just as they're in the byte order of the host capturing the traffic if you're doing a live capture of NFLOG messages. That way, when reading a LINKTYPE_NFLOG file and writing another one from those packets, the type and length in the output file will be in the byte order of the host writing the file, rather than the byte order of the host that wrote the input file. Export the nflog.h file containing the declarations and definitions we need, for use by tcpdump and other programs reading LINKTYPE_NFLOG files. Put the bulk of the byte-swapping code into a common routine, for use by pcap and pcap-ng readers, while we're at it.
-rw-r--r--Makefile.in1
-rw-r--r--pcap-common.c91
-rw-r--r--pcap-common.h4
-rw-r--r--pcap/nflog.h59
-rw-r--r--sf-pcap-ng.c19
-rw-r--r--sf-pcap.c19
6 files changed, 154 insertions, 39 deletions
diff --git a/Makefile.in b/Makefile.in
index 99954581..47f5a06b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -105,6 +105,7 @@ PUBHDR = \
pcap/bluetooth.h \
pcap/ipnet.h \
pcap/namedb.h \
+ pcap/nflog.h \
pcap/pcap.h \
pcap/sll.h \
pcap/vlan.h \
diff --git a/pcap-common.c b/pcap-common.c
index f26d22ec..bddb5c09 100644
--- a/pcap-common.c
+++ b/pcap-common.c
@@ -41,6 +41,7 @@
#include "pcap-int.h"
#include "pcap/usb.h"
+#include "pcap/nflog.h"
#include "pcap-common.h"
@@ -1080,10 +1081,10 @@ linktype_to_dlt(int linktype)
* memory-mapped buffer shared by the kernel).
*
* When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED capture file,
- * we need to convert it from the capturing host's byte order to
- * the reading host's byte order.
+ * we need to convert it from the byte order of the host that wrote
+ * the file to this host's byte order.
*/
-void
+static void
swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
int header_len_64_bytes)
{
@@ -1210,3 +1211,87 @@ swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
}
}
}
+
+/*
+ * 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 capture file, 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;
+ u_int16_t size;
+
+ if (caplen < (int) sizeof(nflog_hdr_t) || length < (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 (length >= 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;
+
+ /* Do we have enough data for the full TLV? */
+ if (size > length || size > caplen) {
+ /* 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_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;
+ }
+}
diff --git a/pcap-common.h b/pcap-common.h
index 0c80ba32..6ac5bcd2 100644
--- a/pcap-common.h
+++ b/pcap-common.h
@@ -21,5 +21,5 @@ extern int dlt_to_linktype(int dlt);
extern int linktype_to_dlt(int linktype);
-extern void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
- int header_len_64_bytes);
+extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr,
+ u_char *data);
diff --git a/pcap/nflog.h b/pcap/nflog.h
new file mode 100644
index 00000000..f15f02ac
--- /dev/null
+++ b/pcap/nflog.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, Petar Alilovic,
+ * Faculty of Electrical Engineering and Computing, University of Zagreb
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#ifndef _PCAP_NFLOG_H__
+#define _PCAP_NFLOG_H__
+
+/*
+ * Structure of an NFLOG header and TLV parts, as described at
+ * http://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
+ *
+ * The NFLOG header is big-endian.
+ *
+ * The TLV length and type are in host byte order. The value is either
+ * big-endian or is an array of bytes in some externally-specified byte
+ * order (text string, link-layer address, link-layer header, packet
+ * data, etc.).
+ */
+typedef struct nflog_hdr {
+ u_int8_t nflog_family; /* adress family */
+ u_int8_t nflog_version; /* version */
+ u_int16_t nflog_rid; /* resource ID */
+} nflog_hdr_t;
+
+typedef struct nflog_tlv {
+ u_int16_t tlv_length; /* tlv length */
+ u_int16_t tlv_type; /* tlv type */
+ void* tlv_value; /* tlv value */
+} nflog_tlv_t;
+
+/*
+ * TLV types.
+ */
+#define NFULA_PAYLOAD 9 /* packet payload */
+
+#endif
diff --git a/sf-pcap-ng.c b/sf-pcap-ng.c
index 71fa057e..e0c1fb1b 100644
--- a/sf-pcap-ng.c
+++ b/sf-pcap-ng.c
@@ -1269,23 +1269,8 @@ found:
if (*data == NULL)
return (-1);
- if (p->swapped) {
- /*
- * Convert pseudo-headers from the byte order of
- * the host on which the file was saved to our
- * byte order, as necessary.
- */
- switch (p->linktype) {
-
- 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;
- }
- }
+ if (p->swapped)
+ swap_pseudo_headers(p->linktype, hdr, *data);
return (0);
}
diff --git a/sf-pcap.c b/sf-pcap.c
index d129dc7b..b298131a 100644
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -559,23 +559,8 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
}
*data = p->buffer;
- if (p->swapped) {
- /*
- * Convert pseudo-headers from the byte order of
- * the host on which the file was saved to our
- * byte order, as necessary.
- */
- switch (p->linktype) {
-
- 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;
- }
- }
+ if (p->swapped)
+ swap_pseudo_headers(p->linktype, hdr, *data);
return (0);
}