Skip to content

Commit

Permalink
Byte-swap the T and L in TLVs as necessary when reading an NFLOG file.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
guyharris committed Feb 3, 2014
1 parent 1afede1 commit 13d800e
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 39 deletions.
1 change: 1 addition & 0 deletions Makefile.in
Expand Up @@ -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 \
Expand Down
91 changes: 88 additions & 3 deletions pcap-common.c
Expand Up @@ -41,6 +41,7 @@

#include "pcap-int.h"
#include "pcap/usb.h"
#include "pcap/nflog.h"

#include "pcap-common.h"

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
}
4 changes: 2 additions & 2 deletions pcap-common.h
Expand Up @@ -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);
59 changes: 59 additions & 0 deletions 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
19 changes: 2 additions & 17 deletions sf-pcap-ng.c
Expand Up @@ -1269,23 +1269,8 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
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);
}
19 changes: 2 additions & 17 deletions sf-pcap.c
Expand Up @@ -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);
}
Expand Down

0 comments on commit 13d800e

Please sign in to comment.