summaryrefslogtreecommitdiffstats
path: root/wiretap/libpcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap/libpcap.c')
-rw-r--r--wiretap/libpcap.c1590
1 files changed, 1590 insertions, 0 deletions
diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c
new file mode 100644
index 00000000..f3538078
--- /dev/null
+++ b/wiretap/libpcap.c
@@ -0,0 +1,1590 @@
+/* libpcap.c
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "wtap-int.h"
+#include "file_wrappers.h"
+#include "required_file_handlers.h"
+#include "pcap-common.h"
+#include "pcap-encap.h"
+#include "libpcap.h"
+#include "erf-common.h"
+#include <wsutil/ws_assert.h>
+
+/* See source to the "libpcap" library for information on the "libpcap"
+ file format. */
+
+/*
+ * Private per-wtap_t data needed to read a file.
+ */
+typedef enum {
+ NOT_SWAPPED,
+ SWAPPED,
+ MAYBE_SWAPPED
+} swapped_type_t;
+
+/*
+ * Variants of pcap, some distinguished by the magic number and some,
+ * alas, not.
+ *
+ * (Don't do that. Srsly.)
+ */
+typedef enum {
+ PCAP, /* OG pcap */
+ PCAP_NSEC, /* PCAP with nanosecond resolution */
+ PCAP_AIX, /* AIX pcap */
+ PCAP_SS990417, /* Modified, from 1999-04-17 patch */
+ PCAP_SS990915, /* Modified, from 1999-09-15 patch */
+ PCAP_SS991029, /* Modified, from 1999-10-29 patch */
+ PCAP_NOKIA, /* Nokia pcap */
+ PCAP_UNKNOWN /* Unknown as yet */
+} pcap_variant_t;
+
+typedef struct {
+ gboolean byte_swapped;
+ swapped_type_t lengths_swapped;
+ guint16 version_major;
+ guint16 version_minor;
+ pcap_variant_t variant;
+ int fcs_len;
+ void *encap_priv;
+} libpcap_t;
+
+/* Try to read the first few records of the capture file. */
+static gboolean libpcap_try_variants(wtap *wth, const pcap_variant_t *variants,
+ size_t n_variants, int *err, gchar **err_info);
+static int libpcap_try(wtap *wth, int *err, gchar **err_info);
+static int libpcap_try_record(wtap *wth, int *err, gchar **err_info);
+
+static gboolean libpcap_read(wtap *wth, wtap_rec *rec, Buffer *buf,
+ int *err, gchar **err_info, gint64 *data_offset);
+static gboolean libpcap_seek_read(wtap *wth, gint64 seek_off,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
+static gboolean libpcap_read_packet(wtap *wth, FILE_T fh,
+ wtap_rec *rec, Buffer *buf, int *err, gchar **err_info);
+static int libpcap_read_header(wtap *wth, FILE_T fh, int *err, gchar **err_info,
+ struct pcaprec_ss990915_hdr *hdr);
+static void libpcap_close(wtap *wth);
+
+static gboolean libpcap_dump_pcap(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info);
+static gboolean libpcap_dump_pcap_nsec(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info);
+static gboolean libpcap_dump_pcap_ss990417(wtap_dumper *wdh,
+ const wtap_rec *rec, const guint8 *pd, int *err, gchar **err_info);
+static gboolean libpcap_dump_pcap_ss990915(wtap_dumper *wdh,
+ const wtap_rec *rec, const guint8 *pd, int *err, gchar **err_info);
+static gboolean libpcap_dump_pcap_ss991029(wtap_dumper *wdh,
+ const wtap_rec *rec, const guint8 *pd, int *err, gchar **err_info);
+static gboolean libpcap_dump_pcap_nokia(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info);
+
+/*
+ * Subfields of the field containing the link-layer header type.
+ *
+ * Link-layer header types are assigned for both pcap and
+ * pcapng, and the same value must work with both. In pcapng,
+ * the link-layer header type field in an Interface Description
+ * Block is 16 bits, so only the bottommost 16 bits of the
+ * link-layer header type in a pcap file can be used for the
+ * header type value.
+ *
+ * In libpcap, the upper 16 bits, from the top down, are divided into:
+ *
+ * A 4-bit "FCS length" field, to allow the FCS length to
+ * be specified, just as it can be specified in the if_fcslen
+ * field of the pcapng IDB. The field is in units of 16 bits,
+ * i.e. 1 means 16 bits of FCS, 2 means 32 bits of FCS, etc..
+ *
+ * A reserved bit, which must be zero.
+ *
+ * An "FCS length present" flag; if 0, the "FCS length" field
+ * should be ignored, and if 1, the "FCS length" field should
+ * be used.
+ *
+ * 10 reserved bits, which must be zero. They were originally
+ * intended to be used as a "class" field, allowing additional
+ * classes of link-layer types to be defined, with a class value
+ * of 0 indicating that the link-layer type is a LINKTYPE_ value.
+ * A value of 0x224 was, at one point, used by NetBSD to define
+ * "raw" packet types, with the lower 16 bits containing a
+ * NetBSD AF_ value; see
+ *
+ * https://marc.info/?l=tcpdump-workers&m=98296750229149&w=2
+ *
+ * It's unknown whether those were ever used in capture files,
+ * or if the intent was just to use it as a link-layer type
+ * for BPF programs; NetBSD's libpcap used to support them in
+ * the BPF code generator, but it no longer does so. If it
+ * was ever used in capture files, or if classes other than
+ * "LINKTYPE_ value" are ever useful in capture files, we could
+ * re-enable this, and use the reserved 16 bits following the
+ * link-layer type in pcapng files to hold the class information
+ * there. (Note, BTW, that LINKTYPE_RAW/DLT_RAW is now being
+ * interpreted by libpcap, tcpdump, and Wireshark as "raw IP",
+ * including both IPv4 and IPv6, with the version number in the
+ * header being checked to see which it is, not just "raw IPv4";
+ * there are LINKTYPE_IPV4/DLT_IPV4 and LINKTYPE_IPV6/DLT_IPV6
+ * values if "these are IPv{4,6} and only IPv{4,6} packets"
+ * types are needed.)
+ *
+ * Or we might be able to use it for other purposes.
+ */
+#define LT_LINKTYPE(x) ((x) & 0x0000FFFF)
+#define LT_RESERVED1(x) ((x) & 0x03FF0000)
+#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000)
+#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28)
+#define LT_FCS_DATALINK_EXT(x) (((x) & 0xF) << 28) | 0x04000000)
+
+/*
+ * Private file type/subtype values; pcap and nanosecond-resolution
+ * pcap are imported from wiretap/file_access.c.
+ */
+static int pcap_aix_file_type_subtype = -1;
+static int pcap_ss990417_file_type_subtype = -1;
+static int pcap_ss990915_file_type_subtype = -1;
+static int pcap_ss991029_file_type_subtype = -1;
+static int pcap_nokia_file_type_subtype = -1;
+
+/*
+ * pcap variants that use the standard magic number.
+ */
+static const pcap_variant_t variants_standard[] = {
+ PCAP,
+ PCAP_SS990417,
+ PCAP_NOKIA
+};
+#define N_VARIANTS_STANDARD G_N_ELEMENTS(variants_standard)
+
+/*
+ * pcap variants that use the modified magic number.
+ */
+static const pcap_variant_t variants_modified[] = {
+ PCAP_SS991029,
+ PCAP_SS990915
+};
+#define N_VARIANTS_MODIFIED G_N_ELEMENTS(variants_modified)
+
+wtap_open_return_val libpcap_open(wtap *wth, int *err, gchar **err_info)
+{
+ guint32 magic;
+ struct pcap_hdr hdr;
+ gboolean byte_swapped;
+ pcap_variant_t variant;
+ libpcap_t *libpcap;
+ int skip_size = 0;
+ int sizebytes;
+
+ /* Read in the number that should be at the start of a "libpcap" file */
+ if (!wtap_read_bytes(wth->fh, &magic, sizeof magic, err, err_info)) {
+ if (*err != WTAP_ERR_SHORT_READ)
+ return WTAP_OPEN_ERROR;
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ switch (magic) {
+
+ case PCAP_MAGIC:
+ /* Host that wrote it has our byte order, and was running
+ a program using either standard or ss990417 libpcap,
+ or maybe it was written by AIX. That means we don't
+ yet know the variant. */
+ byte_swapped = FALSE;
+ variant = PCAP_UNKNOWN;
+ break;
+
+ case PCAP_SWAPPED_MAGIC:
+ /* Host that wrote it has a byte order opposite to ours,
+ and was running a program using either standard or
+ ss990417 libpcap, or maybe it was written by AIX.
+ That means we don't yet know the variant. */
+ byte_swapped = TRUE;
+ variant = PCAP_UNKNOWN;
+ break;
+
+ case PCAP_IXIAHW_MAGIC:
+ case PCAP_IXIASW_MAGIC:
+ /* Weird Ixia variant that has extra crud, written in our
+ byte order. It's otherwise like standard pcap. */
+ skip_size = 1;
+ byte_swapped = FALSE;
+ variant = PCAP;
+ break;
+
+ case PCAP_SWAPPED_IXIAHW_MAGIC:
+ case PCAP_SWAPPED_IXIASW_MAGIC:
+ /* Weird Ixia variant that has extra crud, written in a
+ byte order opposite to ours. It's otherwise like
+ standard pcap. */
+ skip_size = 1;
+ byte_swapped = TRUE;
+ variant = PCAP;
+ break;
+
+ case PCAP_MODIFIED_MAGIC:
+ /* Host that wrote it has our byte order, and was running
+ a program using either ss990915 or ss991029 libpcap.
+ That means we don't yet know the variant; there's
+ no obvious default, so default to "unknown". */
+ byte_swapped = FALSE;
+ variant = PCAP_UNKNOWN;
+ break;
+
+ case PCAP_SWAPPED_MODIFIED_MAGIC:
+ /* Host that wrote it out has a byte order opposite to
+ ours, and was running a program using either ss990915
+ or ss991029 libpcap. That means we don't yet know
+ the variant; there's no obvious default, so default
+ to "unknown". */
+ byte_swapped = TRUE;
+ variant = PCAP_UNKNOWN;
+ break;
+
+ case PCAP_NSEC_MAGIC:
+ /* Host that wrote it has our byte order, and was writing
+ the file in a format similar to standard libpcap
+ except that the time stamps have nanosecond resolution. */
+ byte_swapped = FALSE;
+ variant = PCAP_NSEC;
+ break;
+
+ case PCAP_SWAPPED_NSEC_MAGIC:
+ /* Host that wrote it out has a byte order opposite to
+ ours, and was writing the file in a format similar to
+ standard libpcap except that the time stamps have
+ nanosecond resolution. */
+ byte_swapped = TRUE;
+ variant = PCAP_NSEC;
+ break;
+
+ default:
+ /* Not a "libpcap" type we know about. */
+ return WTAP_OPEN_NOT_MINE;
+ }
+
+ /* Read the rest of the header. */
+ if (!wtap_read_bytes(wth->fh, &hdr, sizeof hdr, err, err_info))
+ return WTAP_OPEN_ERROR;
+ if (skip_size==1 && !wtap_read_bytes(wth->fh, &sizebytes, sizeof sizebytes, err, err_info))
+ return WTAP_OPEN_ERROR;
+
+ if (byte_swapped) {
+ /* Byte-swap the header fields about which we care. */
+ magic = GUINT32_SWAP_LE_BE(magic);
+ hdr.version_major = GUINT16_SWAP_LE_BE(hdr.version_major);
+ hdr.version_minor = GUINT16_SWAP_LE_BE(hdr.version_minor);
+ hdr.snaplen = GUINT32_SWAP_LE_BE(hdr.snaplen);
+ hdr.network = GUINT32_SWAP_LE_BE(hdr.network);
+ }
+ if (hdr.version_major < 2) {
+ /* We only support version 2.0 and later. */
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = ws_strdup_printf("pcap: major version %u unsupported",
+ hdr.version_major);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /* This is a libpcap file */
+ wth->subtype_read = libpcap_read;
+ wth->subtype_seek_read = libpcap_seek_read;
+ wth->subtype_close = libpcap_close;
+ wth->snapshot_length = hdr.snaplen;
+ libpcap = g_new0(libpcap_t, 1);
+ wth->priv = (void *)libpcap;
+ /*
+ * Fill in the information we already know or can determine
+ * at this point, so the private data is usable by the code
+ * that tries reading packets as a heuristic to guess the
+ * variant.
+ */
+ libpcap->byte_swapped = byte_swapped;
+ /* In file format version 2.3, the order of the "incl_len" and
+ "orig_len" fields in the per-packet header was reversed,
+ in order to match the BPF header layout.
+
+ Therefore, in files with versions prior to that, we must swap
+ those two fields.
+
+ Unfortunately, some files were, according to a comment in the
+ "libpcap" source, written with version 2.3 in their headers
+ but without the interchanged fields, so if "incl_len" is
+ greater than "orig_len" - which would make no sense - we
+ assume that we need to swap them in version 2.3 files
+ as well.
+
+ In addition, DG/UX's tcpdump uses version 543.0, and writes
+ the two fields in the pre-2.3 order. */
+ switch (hdr.version_major) {
+
+ case 2:
+ if (hdr.version_minor < 3)
+ libpcap->lengths_swapped = SWAPPED;
+ else if (hdr.version_minor == 3)
+ libpcap->lengths_swapped = MAYBE_SWAPPED;
+ else
+ libpcap->lengths_swapped = NOT_SWAPPED;
+ break;
+
+ case 543:
+ libpcap->lengths_swapped = SWAPPED;
+ break;
+
+ default:
+ libpcap->lengths_swapped = NOT_SWAPPED;
+ break;
+ }
+ libpcap->version_major = hdr.version_major;
+ libpcap->version_minor = hdr.version_minor;
+ /*
+ * Check whether this is an AIX pcap before we convert the
+ * link-layer type in the header file to an encapsulation,
+ * because AIX pcaps use RFC 1573 ifType values in the header.
+ *
+ * AIX pcap files use the standard magic number, and have a
+ * major and minor version of 2.
+ *
+ * Unfortunately, that's also true of older versions of libpcap,
+ * so we need to do some heuristics to try to identify AIX pcap
+ * files.
+ */
+ if (magic == PCAP_MAGIC && hdr.version_major == 2 &&
+ hdr.version_minor == 2) {
+ /*
+ * The AIX libpcap uses RFC 1573 ifType values rather
+ * than LINKTYPE_/DLT_ values in the header; the ifType
+ * values for LAN devices are:
+ *
+ * Ethernet 6
+ * Token Ring 9
+ * FDDI 15
+ *
+ * which correspond to LINKTYPE_IEEE802_5/DLT_IEEE802 (used
+ * for Token Ring), LINKTYPE_PPP/DLT_PPP, and
+ * LINKTYPE_SLIP_BSDOS/DLT_SLIP_BSDOS, respectively, and
+ * the ifType value for a loopback interface is 24, which
+ * currently isn't used by any version of libpcap I know
+ * about (and, as tcpdump.org are assigning LINKTYPE_/DLT_
+ * values above 100, and NetBSD started assigning values
+ * starting at 50, and the values chosen by other libpcaps
+ * appear to stop at 19, it's probably not going to be used
+ * by any libpcap in the future).
+ *
+ * So we shall assume that if the network type is 6, 9, 15,
+ * or 24 it's AIX libpcap.
+ *
+ * We also assume those older versions of libpcap didn't use
+ * LINKTYPE_IEEE802_5/DLT_IEEE802 for Token Ring, and didn't
+ * use LINKTYPE_SLIP_BSDOS/DLT_SLIP_BSDOS as that came later.
+ * It may have used LINKTYPE_PPP/DLT_PPP, however, in which
+ * case we're out of luck; we assume it's Token Ring in AIX
+ * libpcap rather than PPP in standard libpcap, as you're
+ * probably more likely to be handing an AIX libpcap token-
+ *ring capture than an old (pre-libpcap 0.4) PPP capture to
+ * Wireshark.
+ *
+ * AIX pcap files didn't use the upper 16 bits, so we don't
+ * need to ignore them here - they'll be 0.
+ */
+ switch (hdr.network) {
+
+ case 6:
+ hdr.network = 1; /* LINKTYPE_EN10MB, Ethernet */
+ variant = PCAP_AIX;
+ break;
+
+ case 9:
+ hdr.network = 6; /* LINKTYPE_IEEE802_5, Token Ring */
+ variant = PCAP_AIX;
+ break;
+
+ case 15:
+ hdr.network = 10; /* LINKTYPE_FDDI, FDDI */
+ variant = PCAP_AIX;
+ break;
+
+ case 24:
+ hdr.network = 0; /* LINKTYPE_NULL, loopback */
+ variant = PCAP_AIX;
+ break;
+ }
+ }
+
+ /*
+ * Check the main reserved field.
+ */
+ if (LT_RESERVED1(hdr.network) != 0) {
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = ws_strdup_printf("pcap: network type reserved field not zero (0x%08x)",
+ LT_RESERVED1(hdr.network));
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Map the link-layer type from the "network" field in
+ * the header to a Wiretap encapsulation.
+ */
+ wth->file_encap = wtap_pcap_encap_to_wtap_encap(LT_LINKTYPE(hdr.network));
+ if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = ws_strdup_printf("pcap: network type %u unknown or unsupported",
+ hdr.network);
+ return WTAP_OPEN_ERROR;
+ }
+
+ /*
+ * Extract the FCS information, if present.
+ */
+ libpcap->fcs_len = -1;
+ if (LT_FCS_LENGTH_PRESENT(hdr.network)) {
+ /*
+ * We have an FCS length, in units of 16 bits.
+ * Convert it to bits.
+ */
+ libpcap->fcs_len = LT_FCS_LENGTH(hdr.network) * 16;
+ }
+
+ libpcap->encap_priv = NULL;
+
+ /*
+ * If this file has the standard magic number, it could be
+ * one of a number of variants, including regular pcap, the
+ * AIX variant, the ss990417 variant, and a Nokia variant.
+ * The ss990417 variant is used in, for example, Red Hat 6.1,
+ * so some versions of AIX, RH 6.1, and some Nokia devices
+ * write files that can't be read by any software that expects
+ * standard libpcap packet record headers if the magic number
+ * is the standard magic number (e.g., any program such as
+ * tcpdump that uses libpcap, when using the standard libpcap,
+ * and Wireshark if we don't do the heuristics below).
+ *
+ * If this file has the patched magic number, used by the
+ * ss990915 and ss991029 variants, then it could be either
+ * of those. The ss991029 variant uses the same packet
+ * record header as the ss990417 variant, but the ss990915
+ * variant uses a packet record header with some additional
+ * fields and it is used in, for example, SuSE 6.3, so SuSE
+ * 6.3 writes files that can't be read by any software that
+ * expects ss990417 packet record headers if the magic number
+ * is the modified magic number.
+ *
+ * So, for the standard and modified magic number:
+ *
+ * For the standard magic number, we first do some heuristic
+ * checks of data from the file header to see if it looks like
+ * an AIX libpcap file. If so, we choose PCAP_AIX as the variant,
+ * and we don't have to do any more guessing.
+ *
+ * Otherwise, we determine the variant by, for each variant,
+ * trying to read the first few packets as if that file were
+ * in that variant's format, and seeing whether the packet
+ * record headers make sense.
+ *
+ * But don't do the latter if the input is a pipe; that would mean
+ * the open won't complete until two packets have been written to
+ * the pipe, unless the pipe is closed after one packet has been
+ * written, so a program reading from the file won't see the
+ * first packet until the second packet has been written.
+ */
+ switch (magic) {
+
+ case PCAP_MAGIC:
+ /*
+ * Original libpcap magic.
+ *
+ * If we still don't know the variant, look at the first
+ * few packets to see what type of per-packet header they
+ * have.
+ *
+ * Default to PCAP, as that's probably what this is;
+ * libpcap_try_variants() will just give up if we're
+ * reading from a pipe.
+ */
+ if (variant == PCAP_UNKNOWN) {
+ if (wth->ispipe) {
+ /*
+ * We can't do the heuristics.
+ * Just go with standard libpcap.
+ */
+ libpcap->variant = PCAP;
+ } else {
+ /*
+ * Try the variants that use the standard
+ * pcap magic number.
+ */
+ if (!libpcap_try_variants(wth, variants_standard,
+ N_VARIANTS_STANDARD, err, err_info)) {
+ /*
+ * File read error.
+ */
+ return WTAP_OPEN_ERROR;
+ }
+ }
+ } else {
+ /*
+ * Use the variant we found.
+ */
+ libpcap->variant = variant;
+ }
+ break;
+
+ case PCAP_MODIFIED_MAGIC:
+ /*
+ * Modified libpcap magic, from Alexey's later two
+ * patches.
+ *
+ * This might be one of two different flavors of
+ * pcap file, with different modified per-packet
+ * headers.
+ *
+ * If we're reading from a pipe, we don't have an
+ * obvious choice to use as a default.
+ */
+ if (wth->ispipe) {
+ /*
+ * We can't do the heuristics.
+ * There's no obvious choice to use as a
+ * default, so just report an error.
+ */
+ *err = WTAP_ERR_UNSUPPORTED;
+ *err_info = g_strdup("pcap: that type of pcap file can't be read from a pipe");
+ return WTAP_OPEN_ERROR;
+ } else {
+ /*
+ * Try the variants that use the modified
+ * pcap magic number.
+ */
+ if (!libpcap_try_variants(wth, variants_modified,
+ N_VARIANTS_MODIFIED, err, err_info)) {
+ /*
+ * File read error.
+ */
+ return WTAP_OPEN_ERROR;
+ }
+ }
+ break;
+
+ default:
+ /*
+ * None of these require heuristics to guess the
+ * variant; just use the variant we found.
+ */
+ libpcap->variant = variant;
+ break;
+ }
+
+ /*
+ * Set the file type and subtype, and handle some variants
+ * specially.
+ */
+ switch (libpcap->variant) {
+
+ case PCAP:
+ wth->file_type_subtype = pcap_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ break;
+
+ case PCAP_NSEC:
+ wth->file_type_subtype = pcap_nsec_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_NSEC;
+ break;
+
+ case PCAP_SS990417:
+ wth->file_type_subtype = pcap_ss990417_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ break;
+
+ case PCAP_SS990915:
+ wth->file_type_subtype = pcap_ss990915_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ break;
+
+ case PCAP_SS991029:
+ wth->file_type_subtype = pcap_ss991029_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ break;
+
+ case PCAP_AIX:
+ wth->file_type_subtype = pcap_aix_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_NSEC;
+ break;
+
+ case PCAP_NOKIA:
+ wth->file_type_subtype = pcap_nokia_file_type_subtype;
+ wth->file_tsprec = WTAP_TSPREC_USEC;
+ /*
+ * We treat a DLT_ value of 13 specially - it appears
+ * that in Nokia libpcap format, it's some form of ATM
+ * with what I suspect is a pseudo-header (even though
+ * Nokia's IPSO is based on FreeBSD, which #defines
+ * DLT_SLIP_BSDOS as 13).
+ *
+ * Treat 13 as WTAP_ENCAP_ATM_PDUS, rather than as what
+ * we normally treat it.
+ */
+ if (hdr.network == 13)
+ wth->file_encap = WTAP_ENCAP_ATM_PDUS;
+ break;
+
+ default:
+ ws_assert_not_reached();
+ }
+
+ if (wth->file_encap == WTAP_ENCAP_ERF) {
+ /* Reset the ERF interface lookup table */
+ libpcap->encap_priv = erf_priv_create();
+ } else {
+ /*
+ * Add an IDB; we don't know how many interfaces were
+ * involved, so we just say one interface, about which
+ * we only know the link-layer type, snapshot length,
+ * and time stamp resolution.
+ */
+ wtap_add_generated_idb(wth);
+ }
+
+ return WTAP_OPEN_MINE;
+}
+
+static gboolean libpcap_try_variants(wtap *wth, const pcap_variant_t *variants,
+ size_t n_variants, int *err, gchar **err_info)
+{
+ libpcap_t *libpcap = (libpcap_t *)wth->priv;
+#define MAX_FIGURES_OF_MERIT \
+ MAX(N_VARIANTS_MODIFIED, N_VARIANTS_STANDARD)
+ int figures_of_merit[MAX_FIGURES_OF_MERIT];
+ int best_variant;
+ gint64 first_packet_offset;
+
+ first_packet_offset = file_tell(wth->fh);
+ for (size_t i = 0; i < n_variants; i++) {
+ libpcap->variant = variants[i];
+ figures_of_merit[i] = libpcap_try(wth, err, err_info);
+ if (figures_of_merit[i] == -1) {
+ /*
+ * Well, we couldn't even read it. Give up.
+ */
+ return FALSE;
+ }
+ if (figures_of_merit[i] == 0) {
+ /*
+ * This format doesn't have any issues.
+ * Put the seek pointer back, and finish,
+ * using that format as the subtype.
+ */
+ if (file_seek(wth->fh, first_packet_offset, SEEK_SET,
+ err) == -1) {
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ /*
+ * OK, we've recorded the figure of merit for this
+ * one; go back to the first packet and try the
+ * next one.
+ */
+ if (file_seek(wth->fh, first_packet_offset, SEEK_SET,
+ err) == -1) {
+ return FALSE;
+ }
+ }
+
+ /*
+ * OK, none are perfect; let's see which one is least bad.
+ */
+ best_variant = INT_MAX;
+ for (size_t i = 0; i < n_variants; i++) {
+ /*
+ * Is this subtype better than the last one we saw?
+ */
+ if (figures_of_merit[i] < best_variant) {
+ /*
+ * Yes. Choose it until we find a better one.
+ */
+ libpcap->variant = variants[i];
+ best_variant = figures_of_merit[i];
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Maximum number of records to try to read. Must be >= 2.
+ */
+#define MAX_RECORDS_TO_TRY 3
+
+/* Try to read the first MAX_RECORDS_TO_TRY records of the capture file. */
+static int libpcap_try(wtap *wth, int *err, gchar **err_info)
+{
+ int ret;
+ int i;
+
+ /*
+ * Attempt to read the first record.
+ */
+ ret = libpcap_try_record(wth, err, err_info);
+ if (ret != 0) {
+ /*
+ * Error or mismatch; return the error indication or
+ * the figure of merit (demerit?).
+ */
+ return ret;
+ }
+
+ /*
+ * Now attempt to read the next MAX_RECORDS_TO_TRY-1 records.
+ * Get the maximum figure of (de?)merit, as that represents the
+ * figure of merit for the record that had the most problems.
+ */
+ for (i = 1; i < MAX_RECORDS_TO_TRY; i++) {
+ /*
+ * Attempt to read this record.
+ */
+ ret = libpcap_try_record(wth, err, err_info);
+ if (ret != 0) {
+ /*
+ * Error or mismatch; return the error indication or
+ * the figure of merit (demerit?).
+ */
+ return ret;
+ }
+ }
+
+ /* They all succeeded. */
+ return 0;
+}
+
+/* Read the header of the next packet and, if that succeeds, read the
+ data of the next packet.
+
+ Return -1 on an I/O error, 0 on success, or a positive number if the
+ header looks corrupt. The higher the positive number, the more things
+ are wrong with the header; this is used by the heuristics that try to
+ guess what type of file it is, with the type with the fewest problems
+ being chosen. */
+static int libpcap_try_record(wtap *wth, int *err, gchar **err_info)
+{
+ /*
+ * pcaprec_ss990915_hdr is the largest header type.
+ */
+ struct pcaprec_ss990915_hdr rec_hdr;
+ int ret;
+
+ if (!libpcap_read_header(wth, wth->fh, err, err_info, &rec_hdr)) {
+ if (*err == 0) {
+ /*
+ * EOF - assume the file is in this format.
+ * This means it doesn't have all the
+ * records we're trying to read.
+ */
+ return 0;
+ }
+ if (*err == WTAP_ERR_SHORT_READ) {
+ /*
+ * Short read; this might be a corrupt
+ * file in this format or might not be
+ * in this format. Return a figure of
+ * merit of 1.
+ */
+ return 1;
+ }
+ /* Hard error. */
+ return -1;
+ }
+
+ ret = 0; /* start out presuming everything's OK */
+
+ /*
+ * The only file types for which we have to do variant
+ * determination by looking at packets have microsecond
+ * resolution; treat fractions-of-a-second values >= 1 000 000
+ * as an indication that the header format might not be
+ * what we think it is.
+ */
+ if (rec_hdr.hdr.ts_usec >= 1000000)
+ ret++;
+
+ if (rec_hdr.hdr.incl_len > wtap_max_snaplen_for_encap(wth->file_encap)) {
+ /*
+ * Probably either a corrupt capture file or a file
+ * of a type different from the one we're trying.
+ */
+ ret++;
+ }
+
+ if (rec_hdr.hdr.orig_len > 128*1024*1024) {
+ /*
+ * In theory I guess the on-the-wire packet size can be
+ * arbitrarily large, and it can certainly be larger than the
+ * maximum snapshot length which bounds the snapshot size,
+ * but any file claiming 128MB in a single packet is *probably*
+ * corrupt, and treating them as such makes the heuristics
+ * much more reliable. See, for example,
+ *
+ * https://gitlab.com/wireshark/wireshark/-/issues/9634
+ *
+ * (128MB is an arbitrary size at this point, chosen to be
+ * large enough for the largest D-Bus packet).
+ */
+ ret++;
+ }
+
+ if (rec_hdr.hdr.incl_len > wth->snapshot_length) {
+ /*
+ * This is not a fatal error, and packets that have one
+ * such packet probably have thousands. For discussion,
+ * see
+ * https://www.wireshark.org/lists/wireshark-dev/201307/msg00076.html
+ * and related messages.
+ *
+ * The packet contents will be copied to a Buffer, which
+ * expands as necessary to hold the contents; we don't have
+ * to worry about fixed-length buffers allocated based on
+ * the original snapshot length.
+ *
+ * We just treat this as an indication that we might be
+ * trying the wrong file type here.
+ */
+ ret++;
+ }
+
+ if (rec_hdr.hdr.incl_len > rec_hdr.hdr.orig_len) {
+ /*
+ * Another hint that this might be the wrong file type.
+ */
+ ret++;
+ }
+
+ if (ret != 0) {
+ /*
+ * Might be the wrong file type; stop trying, and give
+ * this as the figure of merit for this file type.
+ */
+ return ret;
+ }
+
+ /*
+ * Now skip over the record's data, under the assumption that
+ * the header is sane.
+ */
+ if (!wtap_read_bytes(wth->fh, NULL, rec_hdr.hdr.incl_len, err,
+ err_info)) {
+ if (*err == WTAP_ERR_SHORT_READ) {
+ /*
+ * Short read - treat that as a suggestion that
+ * the header isn't sane, and return a figure of
+ * merit value of 1.
+ */
+ return 1;
+ }
+ /* Hard error. */
+ return -1;
+ }
+
+ /* Success. */
+ return 0;
+}
+
+/* Read the next packet */
+static gboolean libpcap_read(wtap *wth, wtap_rec *rec, Buffer *buf,
+ int *err, gchar **err_info, gint64 *data_offset)
+{
+ *data_offset = file_tell(wth->fh);
+
+ return libpcap_read_packet(wth, wth->fh, rec, buf, err, err_info);
+}
+
+static gboolean
+libpcap_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info)
+{
+ if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
+ return FALSE;
+
+ if (!libpcap_read_packet(wth, wth->random_fh, rec, buf, err,
+ err_info)) {
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+libpcap_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
+ Buffer *buf, int *err, gchar **err_info)
+{
+ struct pcaprec_ss990915_hdr hdr;
+ guint packet_size;
+ guint orig_size;
+ int phdr_len;
+ libpcap_t *libpcap = (libpcap_t *)wth->priv;
+ gboolean is_nokia;
+
+ if (!libpcap_read_header(wth, fh, err, err_info, &hdr))
+ return FALSE;
+
+ if (hdr.hdr.incl_len > wtap_max_snaplen_for_encap(wth->file_encap)) {
+ /*
+ * Probably a corrupt capture file; return an error,
+ * so that our caller doesn't blow up trying to allocate
+ * space for an immensely-large packet.
+ */
+ *err = WTAP_ERR_BAD_FILE;
+ if (err_info != NULL) {
+ *err_info = ws_strdup_printf("pcap: File has %u-byte packet, bigger than maximum of %u",
+ hdr.hdr.incl_len,
+ wtap_max_snaplen_for_encap(wth->file_encap));
+ }
+ return FALSE;
+ }
+
+ packet_size = hdr.hdr.incl_len;
+ orig_size = hdr.hdr.orig_len;
+
+ /*
+ * AIX appears to put 3 bytes of padding in front of FDDI
+ * frames; strip that crap off.
+ */
+ if (libpcap->variant == PCAP_AIX &&
+ (wth->file_encap == WTAP_ENCAP_FDDI ||
+ wth->file_encap == WTAP_ENCAP_FDDI_BITSWAPPED)) {
+ /*
+ * The packet size is really a record size and includes
+ * the padding.
+ */
+ packet_size -= 3;
+ orig_size -= 3;
+
+ /*
+ * Skip the padding.
+ */
+ if (!wtap_read_bytes(fh, NULL, 3, err, err_info))
+ return FALSE;
+ }
+
+ is_nokia = (libpcap->variant == PCAP_NOKIA);
+ phdr_len = pcap_process_pseudo_header(fh, is_nokia,
+ wth->file_encap, packet_size, rec, err, err_info);
+ if (phdr_len < 0)
+ return FALSE; /* error */
+
+ /*
+ * Don't count any pseudo-header as part of the packet.
+ */
+ orig_size -= phdr_len;
+ packet_size -= phdr_len;
+
+ rec->rec_type = REC_TYPE_PACKET;
+ rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
+ rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
+
+ /* Update the timestamp, if not already done */
+ if (wth->file_encap != WTAP_ENCAP_ERF) {
+ rec->ts.secs = hdr.hdr.ts_sec;
+ if (libpcap->variant == PCAP_NSEC ||
+ libpcap->variant == PCAP_AIX)
+ rec->ts.nsecs = hdr.hdr.ts_usec;
+ else
+ rec->ts.nsecs = hdr.hdr.ts_usec * 1000;
+ } else {
+ int interface_id;
+ /* Set interface ID for ERF format */
+ rec->presence_flags |= WTAP_HAS_INTERFACE_ID;
+ if ((interface_id = erf_populate_interface_from_header((erf_t*) libpcap->encap_priv, wth, &rec->rec_header.packet_header.pseudo_header, err, err_info)) < 0)
+ return FALSE;
+
+ rec->rec_header.packet_header.interface_id = (guint) interface_id;
+ }
+ rec->rec_header.packet_header.caplen = packet_size;
+ rec->rec_header.packet_header.len = orig_size;
+
+ /*
+ * Read the packet data.
+ */
+ if (!wtap_read_packet_bytes(fh, buf, packet_size, err, err_info))
+ return FALSE; /* failed */
+
+ pcap_read_post_process(is_nokia, wth->file_encap, rec,
+ ws_buffer_start_ptr(buf), libpcap->byte_swapped, libpcap->fcs_len);
+ return TRUE;
+}
+
+/* Read the header of the next packet.
+
+ Return FALSE on an error, TRUE on success. */
+static int libpcap_read_header(wtap *wth, FILE_T fh, int *err, gchar **err_info,
+ struct pcaprec_ss990915_hdr *hdr)
+{
+ int bytes_to_read;
+ guint32 temp;
+ libpcap_t *libpcap = (libpcap_t *)wth->priv;
+
+ switch (libpcap->variant) {
+
+ case PCAP:
+ case PCAP_AIX:
+ case PCAP_NSEC:
+ bytes_to_read = sizeof (struct pcaprec_hdr);
+ break;
+
+ case PCAP_SS990417:
+ case PCAP_SS991029:
+ bytes_to_read = sizeof (struct pcaprec_modified_hdr);
+ break;
+
+ case PCAP_SS990915:
+ bytes_to_read = sizeof (struct pcaprec_ss990915_hdr);
+ break;
+
+ case PCAP_NOKIA:
+ bytes_to_read = sizeof (struct pcaprec_nokia_hdr);
+ break;
+
+ default:
+ bytes_to_read = 0;
+ ws_assert_not_reached();
+ }
+ if (!wtap_read_bytes_or_eof(fh, hdr, bytes_to_read, err, err_info))
+ return FALSE;
+
+ if (libpcap->byte_swapped) {
+ /* Byte-swap the record header fields. */
+ hdr->hdr.ts_sec = GUINT32_SWAP_LE_BE(hdr->hdr.ts_sec);
+ hdr->hdr.ts_usec = GUINT32_SWAP_LE_BE(hdr->hdr.ts_usec);
+ hdr->hdr.incl_len = GUINT32_SWAP_LE_BE(hdr->hdr.incl_len);
+ hdr->hdr.orig_len = GUINT32_SWAP_LE_BE(hdr->hdr.orig_len);
+ }
+
+ /* Swap the "incl_len" and "orig_len" fields, if necessary. */
+ switch (libpcap->lengths_swapped) {
+
+ case NOT_SWAPPED:
+ break;
+
+ case MAYBE_SWAPPED:
+ if (hdr->hdr.incl_len <= hdr->hdr.orig_len) {
+ /*
+ * The captured length is <= the actual length,
+ * so presumably they weren't swapped.
+ */
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case SWAPPED:
+ temp = hdr->hdr.orig_len;
+ hdr->hdr.orig_len = hdr->hdr.incl_len;
+ hdr->hdr.incl_len = temp;
+ break;
+ }
+
+ return TRUE;
+}
+
+/* Returns 0 if we could write the specified encapsulation type,
+ an error indication otherwise. */
+static int libpcap_dump_can_write_encap(int encap)
+{
+ /* Per-packet encapsulations aren't supported. */
+ if (encap == WTAP_ENCAP_PER_PACKET)
+ return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+
+ if (wtap_wtap_encap_to_pcap_encap(encap) == -1)
+ return WTAP_ERR_UNWRITABLE_ENCAP;
+
+ return 0;
+}
+
+static gboolean libpcap_dump_write_file_header(wtap_dumper *wdh, guint32 magic,
+ int *err)
+{
+ struct pcap_hdr file_hdr;
+
+ if (!wtap_dump_file_write(wdh, &magic, sizeof magic, err))
+ return FALSE;
+
+ /* current "libpcap" format is 2.4 */
+ file_hdr.version_major = 2;
+ file_hdr.version_minor = 4;
+ file_hdr.thiszone = 0; /* XXX - current offset? */
+ file_hdr.sigfigs = 0; /* unknown, but also apparently unused */
+ /*
+ * Tcpdump cannot handle capture files with a snapshot length of 0,
+ * as BPF filters return either 0 if they fail or the snapshot length
+ * if they succeed, and a snapshot length of 0 means success is
+ * indistinguishable from failure and the filter expression would
+ * reject all packets.
+ *
+ * A snapshot length of 0, inside Wiretap, means "snapshot length
+ * unknown"; if the snapshot length supplied to us is 0, we make
+ * the snapshot length in the header file the maximum for the
+ * link-layer type we'll be writing.
+ */
+ file_hdr.snaplen = (wdh->snaplen != 0) ? (guint)wdh->snaplen :
+ wtap_max_snaplen_for_encap(wdh->file_encap);
+ file_hdr.network = wtap_wtap_encap_to_pcap_encap(wdh->file_encap);
+ if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Good old fashioned pcap.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap(wtap_dumper *wdh, int *err, gchar **err_info _U_)
+{
+ /* This is a libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_MAGIC, err);
+}
+
+/* Like classic pcap, but with nanosecond resolution.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap_nsec(wtap_dumper *wdh, int *err, gchar **err_info _U_)
+{
+ /* This is a nanosecond-resolution libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap_nsec;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_NSEC_MAGIC, err);
+}
+
+/* Modified, but with the old magic, sigh.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap_ss990417(wtap_dumper *wdh, int *err,
+ gchar **err_info _U_)
+{
+ /* This is a modified-by-patch-SS990417 libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap_ss990417;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_MAGIC, err);
+}
+
+/* New magic, extra crap.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap_ss990915(wtap_dumper *wdh, int *err,
+ gchar **err_info _U_)
+{
+ /* This is a modified-by-patch-SS990915 libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap_ss990915;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_MODIFIED_MAGIC, err);
+}
+
+/* Same magic as SS990915, *different* extra crap, sigh.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap_ss991029(wtap_dumper *wdh, int *err,
+ gchar **err_info _U_)
+{
+ /* This is a modified-by-patch-SS991029 libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap_ss991029;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_MODIFIED_MAGIC, err);
+}
+
+static void libpcap_close(wtap *wth)
+{
+ libpcap_t *libpcap = (libpcap_t *)wth->priv;
+
+ if (libpcap->encap_priv) {
+ switch (wth->file_encap) {
+
+ case WTAP_ENCAP_ERF:
+ erf_priv_free((erf_t*) libpcap->encap_priv);
+ break;
+
+ default:
+ g_free(libpcap->encap_priv);
+ break;
+ }
+ }
+}
+
+/* Nokia libpcap of some sort.
+ Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
+ failure */
+static gboolean
+libpcap_dump_open_pcap_nokia(wtap_dumper *wdh, int *err, gchar **err_info _U_)
+{
+ /* This is a Nokia libpcap file */
+ wdh->subtype_write = libpcap_dump_pcap_nokia;
+
+ /* Write the file header. */
+ return libpcap_dump_write_file_header(wdh, PCAP_MAGIC, err);
+}
+
+static gboolean
+libpcap_dump_write_packet(wtap_dumper *wdh, const wtap_rec *rec,
+ struct pcaprec_hdr *hdr, size_t hdr_size, const guint8 *pd, int *err)
+{
+ const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
+ int phdrsize;
+
+ phdrsize = pcap_get_phdr_size(wdh->file_encap, pseudo_header);
+
+ /* We can only write packet records. */
+ if (rec->rec_type != REC_TYPE_PACKET) {
+ *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
+ return FALSE;
+ }
+
+ /*
+ * Make sure this packet doesn't have a link-layer type that
+ * differs from the one for the file.
+ */
+ if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
+ *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
+ return FALSE;
+ }
+
+ /*
+ * Don't write anything we're not willing to read.
+ * (The cast is to prevent an overflow.)
+ */
+ if ((guint64)rec->rec_header.packet_header.caplen + phdrsize > wtap_max_snaplen_for_encap(wdh->file_encap)) {
+ *err = WTAP_ERR_PACKET_TOO_LARGE;
+ return FALSE;
+ }
+
+ hdr->incl_len = rec->rec_header.packet_header.caplen + phdrsize;
+ hdr->orig_len = rec->rec_header.packet_header.len + phdrsize;
+
+ if (!wtap_dump_file_write(wdh, hdr, hdr_size, err))
+ return FALSE;
+
+ if (!pcap_write_phdr(wdh, wdh->file_encap, pseudo_header, err))
+ return FALSE;
+
+ if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
+ return FALSE;
+ return TRUE;
+}
+
+/* Good old fashioned pcap.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap(wtap_dumper *wdh, const wtap_rec *rec, const guint8 *pd,
+ int *err, gchar **err_info _U_)
+{
+ struct pcaprec_hdr rec_hdr;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.ts_usec = rec->ts.nsecs / 1000;
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+/* Like classic pcap, but with nanosecond resolution.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap_nsec(wtap_dumper *wdh, const wtap_rec *rec, const guint8 *pd,
+ int *err, gchar **err_info _U_)
+{
+ struct pcaprec_hdr rec_hdr;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.ts_usec = rec->ts.nsecs;
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+/* Modified, but with the old magic, sigh.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap_ss990417(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_)
+{
+ struct pcaprec_modified_hdr rec_hdr;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.hdr.ts_usec = rec->ts.nsecs / 1000;
+ /* XXX - what should we supply here?
+
+ Alexey's "libpcap" looks up the interface in the system's
+ interface list if "ifindex" is non-zero, and prints
+ the interface name. It ignores "protocol", and uses
+ "pkt_type" to tag the packet as "host", "broadcast",
+ "multicast", "other host", "outgoing", or "none of the
+ above", but that's it.
+
+ If the capture we're writing isn't a modified or
+ RH 6.1 capture, we'd have to do some work to
+ generate the packet type and interface index - and
+ we can't generate the interface index unless we
+ just did the capture ourselves in any case.
+
+ I'm inclined to continue to punt; systems other than
+ those with the older patch can read standard "libpcap"
+ files, and systems with the older patch, e.g. RH 6.1,
+ will just have to live with this. */
+ rec_hdr.ifindex = 0;
+ rec_hdr.protocol = 0;
+ rec_hdr.pkt_type = 0;
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr.hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+/* New magic, extra crap.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap_ss990915(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_)
+{
+ struct pcaprec_ss990915_hdr rec_hdr;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.hdr.ts_usec = rec->ts.nsecs / 1000;
+ rec_hdr.ifindex = 0;
+ rec_hdr.protocol = 0;
+ rec_hdr.pkt_type = 0;
+ rec_hdr.cpu1 = 0;
+ rec_hdr.cpu2 = 0;
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr.hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+/* Same magic as SS990915, *different* extra crap, sigh.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap_ss991029(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_)
+{
+ struct pcaprec_modified_hdr rec_hdr;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.hdr.ts_usec = rec->ts.nsecs / 1000;
+ /* XXX - what should we supply here?
+
+ Alexey's "libpcap" looks up the interface in the system's
+ interface list if "ifindex" is non-zero, and prints
+ the interface name. It ignores "protocol", and uses
+ "pkt_type" to tag the packet as "host", "broadcast",
+ "multicast", "other host", "outgoing", or "none of the
+ above", but that's it.
+
+ If the capture we're writing isn't a modified or
+ RH 6.1 capture, we'd have to do some work to
+ generate the packet type and interface index - and
+ we can't generate the interface index unless we
+ just did the capture ourselves in any case.
+
+ I'm inclined to continue to punt; systems other than
+ those with the older patch can read standard "libpcap"
+ files, and systems with the older patch, e.g. RH 6.1,
+ will just have to live with this. */
+ rec_hdr.ifindex = 0;
+ rec_hdr.protocol = 0;
+ rec_hdr.pkt_type = 0;
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr.hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+/* Nokia libpcap of some sort.
+ Write a record for a packet to a dump file.
+ Returns TRUE on success, FALSE on failure. */
+static gboolean
+libpcap_dump_pcap_nokia(wtap_dumper *wdh, const wtap_rec *rec,
+ const guint8 *pd, int *err, gchar **err_info _U_)
+{
+ struct pcaprec_nokia_hdr rec_hdr;
+ const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
+
+ /*
+ * Some code that reads libpcap files may handle time
+ * stamps as unsigned, but most of it probably handles
+ * them as signed.
+ */
+ if (rec->ts.secs < 0 || rec->ts.secs > G_MAXINT32) {
+ *err = WTAP_ERR_TIME_STAMP_NOT_SUPPORTED;
+ return FALSE;
+ }
+ rec_hdr.hdr.ts_sec = (guint32) rec->ts.secs;
+ rec_hdr.hdr.ts_usec = rec->ts.nsecs / 1000;
+ /* restore the "mysterious stuff" that came with the packet */
+ memcpy(rec_hdr.stuff, pseudo_header->nokia.stuff, 4);
+ return libpcap_dump_write_packet(wdh, rec, &rec_hdr.hdr, sizeof rec_hdr,
+ pd, err);
+}
+
+static const struct supported_block_type pcap_blocks_supported[] = {
+ /*
+ * We support packet blocks, with no comments or other options.
+ */
+ { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
+};
+
+static const struct file_type_subtype_info pcap_info = {
+ /* Gianluca Varenni suggests that we add "deprecated" to the description. */
+ "Wireshark/tcpdump/... - pcap", "pcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap, NULL
+};
+
+static const struct file_type_subtype_info pcap_nsec_info = {
+ "Wireshark/tcpdump/... - nanosecond pcap", "nsecpcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap_nsec, NULL
+};
+
+static const struct file_type_subtype_info pcap_aix_info = {
+ "AIX tcpdump - pcap", "aixpcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ NULL, NULL, NULL
+};
+
+static const struct file_type_subtype_info pcap_ss990417_info = {
+ "RedHat 6.1 tcpdump - pcap", "rh6_1pcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap_ss990417, NULL
+};
+
+static const struct file_type_subtype_info pcap_ss990915_info = {
+ "SuSE 6.3 tcpdump - pcap", "suse6_3pcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap_ss990915, NULL
+};
+
+static const struct file_type_subtype_info pcap_ss991029_info = {
+ "Modified tcpdump - pcap", "modpcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap_ss991029, NULL
+};
+
+static const struct file_type_subtype_info pcap_nokia_info = {
+ "Nokia tcpdump - pcap", "nokiapcap", "pcap", "cap;dmp",
+ FALSE, BLOCKS_SUPPORTED(pcap_blocks_supported),
+ libpcap_dump_can_write_encap, libpcap_dump_open_pcap_nokia, NULL
+};
+
+void register_pcap(void)
+{
+ pcap_file_type_subtype = wtap_register_file_type_subtype(&pcap_info);
+ pcap_nsec_file_type_subtype = wtap_register_file_type_subtype(&pcap_nsec_info);
+ pcap_aix_file_type_subtype = wtap_register_file_type_subtype(&pcap_aix_info);
+ pcap_ss990417_file_type_subtype = wtap_register_file_type_subtype(&pcap_ss990417_info);
+ pcap_ss990915_file_type_subtype = wtap_register_file_type_subtype(&pcap_ss990915_info);
+ pcap_ss991029_file_type_subtype = wtap_register_file_type_subtype(&pcap_ss991029_info);
+ pcap_nokia_file_type_subtype = wtap_register_file_type_subtype(&pcap_nokia_info);
+
+ /*
+ * We now call the libpcap file format just pcap, but we allow
+ * the various variants of it to be specified using names
+ * containing "libpcap" as well as "pcap", for backwards
+ * compatibility.
+ *
+ * Register names for that purpose.
+ */
+ wtap_register_compatibility_file_subtype_name("libpcap", "pcap");
+ wtap_register_compatibility_file_subtype_name("nseclibpcap", "nsecpcap");
+ wtap_register_compatibility_file_subtype_name("aixlibpcap", "aixpcap");
+ wtap_register_compatibility_file_subtype_name("modlibpcap", "modpcap");
+ wtap_register_compatibility_file_subtype_name("nokialibpcap", "nokiapcap");
+ wtap_register_compatibility_file_subtype_name("rh6_1libpcap", "rh6_1pcap");
+ wtap_register_compatibility_file_subtype_name("suse6_3libpcap", "suse6_3pcap");
+
+ /*
+ * Register names for backwards compatibility with the
+ * wtap_filetypes table in Lua.
+ */
+ wtap_register_backwards_compatibility_lua_name("PCAP",
+ pcap_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_NSEC",
+ pcap_nsec_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_AIX",
+ pcap_aix_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_SS990417",
+ pcap_ss990417_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_SS990915",
+ pcap_ss990915_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_SS991029",
+ pcap_ss991029_file_type_subtype);
+ wtap_register_backwards_compatibility_lua_name("PCAP_NOKIA",
+ pcap_nokia_file_type_subtype);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */