summaryrefslogtreecommitdiffstats
path: root/freebsd/contrib/libpcap/sf-pcap-ng.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/contrib/libpcap/sf-pcap-ng.c')
-rw-r--r--freebsd/contrib/libpcap/sf-pcap-ng.c647
1 files changed, 481 insertions, 166 deletions
diff --git a/freebsd/contrib/libpcap/sf-pcap-ng.c b/freebsd/contrib/libpcap/sf-pcap-ng.c
index 0cc595d8..209c1424 100644
--- a/freebsd/contrib/libpcap/sf-pcap-ng.c
+++ b/freebsd/contrib/libpcap/sf-pcap-ng.c
@@ -32,9 +32,9 @@ static const char rcsid[] _U_ =
#include "config.h"
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <pcap-stdinc.h>
-#else /* WIN32 */
+#else /* _WIN32 */
#if HAVE_INTTYPES_H
#include <inttypes.h>
#elif HAVE_STDINT_H
@@ -44,7 +44,7 @@ static const char rcsid[] _U_ =
#include <sys/bitypes.h>
#endif
#include <sys/types.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
#include <errno.h>
#include <memory.h>
@@ -123,6 +123,7 @@ struct section_header_block {
* that means that this code can't read the file.
*/
#define PCAP_NG_VERSION_MAJOR 1
+#define PCAP_NG_VERSION_MINOR 0
/*
* Interface Description Block.
@@ -203,6 +204,32 @@ struct block_cursor {
bpf_u_int32 block_type;
};
+typedef enum {
+ PASS_THROUGH,
+ SCALE_UP_DEC,
+ SCALE_DOWN_DEC,
+ SCALE_UP_BIN,
+ SCALE_DOWN_BIN
+} tstamp_scale_type_t;
+
+/*
+ * Per-interface information.
+ */
+struct pcap_ng_if {
+ u_int tsresol; /* time stamp resolution */
+ tstamp_scale_type_t scale_type; /* how to scale */
+ u_int scale_factor; /* time stamp scale factor for power-of-10 tsresol */
+ u_int64_t tsoffset; /* time stamp offset */
+};
+
+struct pcap_ng_sf {
+ u_int user_tsresol; /* time stamp resolution requested by the user */
+ bpf_u_int32 ifcount; /* number of interfaces seen in this capture */
+ bpf_u_int32 ifaces_size; /* size of array below */
+ struct pcap_ng_if *ifaces; /* array of interface information */
+};
+
+static void pcap_ng_cleanup(pcap_t *p);
static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
u_char **data);
@@ -215,13 +242,13 @@ read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
amt_read = fread(buf, 1, bytes_to_read, fp);
if (amt_read != bytes_to_read) {
if (ferror(fp)) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
} else {
if (amt_read == 0 && !fail_on_eof)
return (0); /* EOF */
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"truncated dump file; tried to read %lu bytes, only got %lu",
(unsigned long)bytes_to_read,
(unsigned long)amt_read);
@@ -236,12 +263,14 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
{
int status;
struct block_header bhdr;
+ u_char *bdata;
+ size_t data_remaining;
status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf);
if (status <= 0)
return (status); /* error or EOF */
- if (p->sf.swapped) {
+ if (p->swapped) {
bhdr.block_type = SWAPLONG(bhdr.block_type);
bhdr.total_length = SWAPLONG(bhdr.total_length);
}
@@ -254,7 +283,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
* memory if we read a malformed file.
*/
if (bhdr.total_length > 16*1024*1024) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"pcap-ng block size %u > maximum %u",
bhdr.total_length, 16*1024*1024);
return (-1);
@@ -266,7 +295,7 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
*/
if (bhdr.total_length < sizeof(struct block_header) +
sizeof(struct block_trailer)) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"block in pcap-ng dump file has a length of %u < %lu",
bhdr.total_length,
(unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer)));
@@ -280,11 +309,14 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
/*
* No - make it big enough.
*/
- p->buffer = realloc(p->buffer, bhdr.total_length);
- if (p->buffer == NULL) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ void *bigger_buffer;
+
+ bigger_buffer = realloc(p->buffer, bhdr.total_length);
+ if (bigger_buffer == NULL) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
return (-1);
}
+ p->buffer = bigger_buffer;
}
/*
@@ -292,16 +324,16 @@ read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
* of the block.
*/
memcpy(p->buffer, &bhdr, sizeof(bhdr));
- if (read_bytes(fp, p->buffer + sizeof(bhdr),
- bhdr.total_length - sizeof(bhdr), 1, errbuf) == -1)
+ bdata = (u_char *)p->buffer + sizeof(bhdr);
+ data_remaining = bhdr.total_length - sizeof(bhdr);
+ if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1)
return (-1);
/*
* Initialize the cursor.
*/
- cursor->data = p->buffer + sizeof(bhdr);
- cursor->data_remaining = bhdr.total_length - sizeof(bhdr) -
- sizeof(struct block_trailer);
+ cursor->data = bdata;
+ cursor->data_remaining = data_remaining - sizeof(struct block_trailer);
cursor->block_type = bhdr.block_type;
return (1);
}
@@ -317,7 +349,7 @@ get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
* the block data.
*/
if (cursor->data_remaining < chunk_size) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"block of type %u in pcap-ng dump file is too short",
cursor->block_type);
return (NULL);
@@ -348,7 +380,7 @@ get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
opthdr->option_code = SWAPSHORT(opthdr->option_code);
opthdr->option_length = SWAPSHORT(opthdr->option_length);
}
@@ -380,7 +412,7 @@ get_optvalue_from_block_data(struct block_cursor *cursor,
static int
process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
- u_int64_t *tsoffset, char *errbuf)
+ u_int64_t *tsoffset, int *is_binary, char *errbuf)
{
struct option_header *opthdr;
void *optvalue;
@@ -418,7 +450,7 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
case OPT_ENDOFOPT:
if (opthdr->option_length != 0) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has opt_endofopt option with length %u != 0",
opthdr->option_length);
return (-1);
@@ -427,27 +459,29 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
case IF_TSRESOL:
if (opthdr->option_length != 1) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has if_tsresol option with length %u != 1",
opthdr->option_length);
return (-1);
}
if (saw_tsresol) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has more than one if_tsresol option");
return (-1);
}
saw_tsresol = 1;
- tsresol_opt = *(u_int *)optvalue;
+ memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt));
if (tsresol_opt & 0x80) {
/*
* Resolution is negative power of 2.
*/
+ *is_binary = 1;
*tsresol = 1 << (tsresol_opt & 0x7F);
} else {
/*
* Resolution is negative power of 10.
*/
+ *is_binary = 0;
*tsresol = 1;
for (i = 0; i < tsresol_opt; i++)
*tsresol *= 10;
@@ -457,11 +491,11 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
* Resolution is too high.
*/
if (tsresol_opt & 0x80) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block if_tsresol option resolution 2^-%u is too high",
tsresol_opt & 0x7F);
} else {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block if_tsresol option resolution 10^-%u is too high",
tsresol_opt);
}
@@ -471,19 +505,19 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
case IF_TSOFFSET:
if (opthdr->option_length != 8) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has if_tsoffset option with length %u != 8",
opthdr->option_length);
return (-1);
}
if (saw_tsoffset) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Interface Description Block has more than one if_tsoffset option");
return (-1);
}
saw_tsoffset = 1;
memcpy(tsoffset, optvalue, sizeof(*tsoffset));
- if (p->sf.swapped)
+ if (p->swapped)
*tsoffset = SWAPLL(*tsoffset);
break;
@@ -496,25 +530,204 @@ done:
return (0);
}
+static int
+add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
+{
+ struct pcap_ng_sf *ps;
+ u_int tsresol;
+ u_int64_t tsoffset;
+ int is_binary;
+
+ ps = p->priv;
+
+ /*
+ * Count this interface.
+ */
+ ps->ifcount++;
+
+ /*
+ * Grow the array of per-interface information as necessary.
+ */
+ if (ps->ifcount > ps->ifaces_size) {
+ /*
+ * We need to grow the array.
+ */
+ bpf_u_int32 new_ifaces_size;
+ struct pcap_ng_if *new_ifaces;
+
+ if (ps->ifaces_size == 0) {
+ /*
+ * It's currently empty.
+ *
+ * (The Clang static analyzer doesn't do enough,
+ * err, umm, dataflow *analysis* to realize that
+ * ps->ifaces_size == 0 if ps->ifaces == NULL,
+ * and so complains about a possible zero argument
+ * to realloc(), so we check for the former
+ * condition to shut it up.
+ *
+ * However, it doesn't complain that one of the
+ * multiplications below could overflow, which is
+ * a real, albeit extremely unlikely, problem (you'd
+ * need a pcap-ng file with tens of millions of
+ * interfaces).)
+ */
+ new_ifaces_size = 1;
+ new_ifaces = malloc(sizeof (struct pcap_ng_if));
+ } else {
+ /*
+ * It's not currently empty; double its size.
+ * (Perhaps overkill once we have a lot of interfaces.)
+ *
+ * Check for overflow if we double it.
+ */
+ if (ps->ifaces_size * 2 < ps->ifaces_size) {
+ /*
+ * The maximum number of interfaces before
+ * ps->ifaces_size overflows is the largest
+ * possible 32-bit power of 2, as we do
+ * size doubling.
+ */
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "more than %u interfaces in the file",
+ 0x80000000U);
+ return (0);
+ }
+
+ /*
+ * ps->ifaces_size * 2 doesn't overflow, so it's
+ * safe to multiply.
+ */
+ new_ifaces_size = ps->ifaces_size * 2;
+
+ /*
+ * Now make sure that's not so big that it overflows
+ * if we multiply by sizeof (struct pcap_ng_if).
+ *
+ * That can happen on 32-bit platforms, with a 32-bit
+ * size_t; it shouldn't happen on 64-bit platforms,
+ * with a 64-bit size_t, as new_ifaces_size is
+ * 32 bits.
+ */
+ if (new_ifaces_size * sizeof (struct pcap_ng_if) < new_ifaces_size) {
+ /*
+ * As this fails only with 32-bit size_t,
+ * the multiplication was 32x32->32, and
+ * the largest 32-bit value that can safely
+ * be multiplied by sizeof (struct pcap_ng_if)
+ * without overflow is the largest 32-bit
+ * (unsigned) value divided by
+ * sizeof (struct pcap_ng_if).
+ */
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "more than %u interfaces in the file",
+ 0xFFFFFFFFU / ((u_int)sizeof (struct pcap_ng_if)));
+ return (0);
+ }
+ new_ifaces = realloc(ps->ifaces, new_ifaces_size * sizeof (struct pcap_ng_if));
+ }
+ if (new_ifaces == NULL) {
+ /*
+ * We ran out of memory.
+ * Give up.
+ */
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "out of memory for per-interface information (%u interfaces)",
+ ps->ifcount);
+ return (0);
+ }
+ ps->ifaces_size = new_ifaces_size;
+ ps->ifaces = new_ifaces;
+ }
+
+ /*
+ * Set the default time stamp resolution and offset.
+ */
+ tsresol = 1000000; /* microsecond resolution */
+ is_binary = 0; /* which is a power of 10 */
+ tsoffset = 0; /* absolute timestamps */
+
+ /*
+ * Now look for various time stamp options, so we know
+ * how to interpret the time stamps for this interface.
+ */
+ if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary,
+ errbuf) == -1)
+ return (0);
+
+ ps->ifaces[ps->ifcount - 1].tsresol = tsresol;
+ ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset;
+
+ /*
+ * Determine whether we're scaling up or down or not
+ * at all for this interface.
+ */
+ if (tsresol == ps->user_tsresol) {
+ /*
+ * The resolution is the resolution the user wants,
+ * so we don't have to do scaling.
+ */
+ ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH;
+ } else if (tsresol > ps->user_tsresol) {
+ /*
+ * The resolution is greater than what the user wants,
+ * so we have to scale the timestamps down.
+ */
+ if (is_binary)
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_BIN;
+ else {
+ /*
+ * Calculate the scale factor.
+ */
+ ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol;
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC;
+ }
+ } else {
+ /*
+ * The resolution is less than what the user wants,
+ * so we have to scale the timestamps up.
+ */
+ if (is_binary)
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_BIN;
+ else {
+ /*
+ * Calculate the scale factor.
+ */
+ ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol;
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC;
+ }
+ }
+ return (1);
+}
+
/*
* Check whether this is a pcap-ng savefile and, if it is, extract the
* relevant information from the header.
*/
-int
-pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
+pcap_t *
+pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
+ int *err)
{
size_t amt_read;
bpf_u_int32 total_length;
bpf_u_int32 byte_order_magic;
struct block_header *bhdrp;
struct section_header_block *shbp;
+ pcap_t *p;
+ int swapped = 0;
+ struct pcap_ng_sf *ps;
int status;
struct block_cursor cursor;
struct interface_description_block *idbp;
/*
+ * Assume no read errors.
+ */
+ *err = 0;
+
+ /*
* Check whether the first 4 bytes of the file are the block
- * type for a pcap-ng savefile.
+ * type for a pcap-ng savefile.
*/
if (magic != BT_SHB) {
/*
@@ -526,7 +739,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
* this as possibly being a pcap-ng file transferred
* between UN*X and Windows in text file format?
*/
- return (0); /* nope */
+ return (NULL); /* nope */
}
/*
@@ -543,32 +756,34 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
amt_read = fread(&total_length, 1, sizeof(total_length), fp);
if (amt_read < sizeof(total_length)) {
if (ferror(fp)) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
- return (-1); /* fail */
+ *err = 1;
+ return (NULL); /* fail */
}
/*
* Possibly a weird short text file, so just say
* "not pcap-ng".
*/
- return (0);
+ return (NULL);
}
amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp);
if (amt_read < sizeof(byte_order_magic)) {
if (ferror(fp)) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
- return (-1); /* fail */
+ *err = 1;
+ return (NULL); /* fail */
}
/*
* Possibly a weird short text file, so just say
* "not pcap-ng".
*/
- return (0);
+ return (NULL);
}
if (byte_order_magic != BYTE_ORDER_MAGIC) {
byte_order_magic = SWAPLONG(byte_order_magic);
@@ -576,9 +791,9 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
/*
* Not a pcap-ng file.
*/
- return (0);
+ return (NULL);
}
- p->sf.swapped = 1;
+ swapped = 1;
total_length = SWAPLONG(total_length);
}
@@ -586,12 +801,49 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
* Check the sanity of the total length.
*/
if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Section Header Block in pcap-ng dump file has a length of %u < %lu",
total_length,
(unsigned long)(sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)));
- return (-1);
+ *err = 1;
+ return (NULL);
+ }
+
+ /*
+ * OK, this is a good pcap-ng file.
+ * Allocate a pcap_t for it.
+ */
+ p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf));
+ if (p == NULL) {
+ /* Allocation failed. */
+ *err = 1;
+ return (NULL);
}
+ p->swapped = swapped;
+ ps = p->priv;
+
+ /*
+ * What precision does the user want?
+ */
+ switch (precision) {
+
+ case PCAP_TSTAMP_PRECISION_MICRO:
+ ps->user_tsresol = 1000000;
+ break;
+
+ case PCAP_TSTAMP_PRECISION_NANO:
+ ps->user_tsresol = 1000000000;
+ break;
+
+ default:
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unknown time stamp resolution %u", precision);
+ free(p);
+ *err = 1;
+ return (NULL);
+ }
+
+ p->opt.tstamp_precision = precision;
/*
* Allocate a buffer into which to read blocks. We default to
@@ -610,8 +862,10 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
p->bufsize = total_length;
p->buffer = malloc(p->bufsize);
if (p->buffer == NULL) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
- return (-1);
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ free(p);
+ *err = 1;
+ return (NULL);
}
/*
@@ -619,17 +873,17 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
* of the SHB.
*/
bhdrp = (struct block_header *)p->buffer;
- shbp = (struct section_header_block *)(p->buffer + sizeof(struct block_header));
+ shbp = (struct section_header_block *)((u_char *)p->buffer + sizeof(struct block_header));
bhdrp->block_type = magic;
bhdrp->total_length = total_length;
shbp->byte_order_magic = byte_order_magic;
if (read_bytes(fp,
- p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
+ (u_char *)p->buffer + (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)),
1, errbuf) == -1)
goto fail;
- if (p->sf.swapped) {
+ if (p->swapped) {
/*
* Byte-swap the fields we've read.
*/
@@ -640,21 +894,21 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
* XXX - we don't care about the section length.
*/
}
- if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "unknown pcap-ng savefile major version number %u",
- shbp->major_version);
+ /* currently only SHB version 1.0 is supported */
+ if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
+ shbp->minor_version == PCAP_NG_VERSION_MINOR)) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unsupported pcap-ng savefile version %u.%u",
+ shbp->major_version, shbp->minor_version);
goto fail;
}
- p->sf.version_major = shbp->major_version;
- p->sf.version_minor = shbp->minor_version;
+ p->version_major = shbp->major_version;
+ p->version_minor = shbp->minor_version;
/*
- * Set the default time stamp resolution and offset.
+ * Save the time stamp resolution the user requested.
*/
- p->sf.tsresol = 1000000; /* microsecond resolution */
- p->sf.tsscale = 1; /* multiply by 1 to scale to microseconds */
- p->sf.tsoffset = 0; /* absolute timestamps */
+ p->opt.tstamp_precision = precision;
/*
* Now start looking for an Interface Description Block.
@@ -666,7 +920,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
status = read_block(fp, p, &cursor, errbuf);
if (status == 0) {
/* EOF - no IDB in this file */
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has no Interface Description Blocks");
goto fail;
}
@@ -687,42 +941,28 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
idbp->linktype = SWAPSHORT(idbp->linktype);
idbp->snaplen = SWAPLONG(idbp->snaplen);
}
/*
- * Count this interface.
+ * Interface capture length sanity check
*/
- p->sf.ifcount++;
+ if (idbp->snaplen > MAXIMUM_SNAPLEN) {
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "invalid interface capture length %u, "
+ "bigger than maximum of %u",
+ idbp->snaplen, MAXIMUM_SNAPLEN);
+ goto fail;
+ }
/*
- * Now look for various time stamp options, so
- * we know how to interpret the time stamps.
+ * Try to add this interface.
*/
- if (process_idb_options(p, &cursor, &p->sf.tsresol,
- &p->sf.tsoffset, errbuf) == -1)
+ if (!add_interface(p, &cursor, errbuf))
goto fail;
- /*
- * Compute the scaling factor to convert the
- * sub-second part of the time stamp to
- * microseconds.
- */
- if (p->sf.tsresol > 1000000) {
- /*
- * Higher than microsecond resolution;
- * scale down to microseconds.
- */
- p->sf.tsscale = (p->sf.tsresol / 1000000);
- } else {
- /*
- * Lower than microsecond resolution;
- * scale up to microseconds.
- */
- p->sf.tsscale = (1000000 / p->sf.tsresol);
- }
goto done;
case BT_EPB:
@@ -733,7 +973,7 @@ pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
* not valid, as we don't know what link-layer
* encapsulation the packet has.
*/
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has a packet block before any Interface Description Blocks");
goto fail;
@@ -751,13 +991,26 @@ done:
p->linktype = linktype_to_dlt(idbp->linktype);
p->linktype_ext = 0;
- p->sf.next_packet_op = pcap_ng_next_packet;
+ p->next_packet_op = pcap_ng_next_packet;
+ p->cleanup_op = pcap_ng_cleanup;
- return (1);
+ return (p);
fail:
+ free(ps->ifaces);
free(p->buffer);
- return (-1);
+ free(p);
+ *err = 1;
+ return (NULL);
+}
+
+static void
+pcap_ng_cleanup(pcap_t *p)
+{
+ struct pcap_ng_sf *ps = p->priv;
+
+ free(ps->ifaces);
+ sf_cleanup(p);
}
/*
@@ -768,6 +1021,7 @@ fail:
static int
pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
{
+ struct pcap_ng_sf *ps = p->priv;
struct block_cursor cursor;
int status;
struct enhanced_packet_block *epbp;
@@ -776,9 +1030,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
bpf_u_int32 interface_id = 0xFFFFFFFF;
struct interface_description_block *idbp;
struct section_header_block *shbp;
- FILE *fp = p->sf.rfile;
- u_int tsresol;
- u_int64_t tsoffset;
+ FILE *fp = p->rfile;
u_int64_t t, sec, frac;
/*
@@ -810,7 +1062,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
/* these were written in opposite byte order */
interface_id = SWAPLONG(epbp->interface_id);
hdr->caplen = SWAPLONG(epbp->caplen);
@@ -825,7 +1077,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
epbp->timestamp_low;
}
goto found;
-
+
case BT_SPB:
/*
* Get a pointer to the fixed-length portion of the
@@ -845,7 +1097,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
/* these were written in opposite byte order */
hdr->len = SWAPLONG(spbp->len);
} else
@@ -857,7 +1109,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* and the packet length.
*/
hdr->caplen = hdr->len;
- if (hdr->caplen > p->snapshot)
+ if (hdr->caplen > (bpf_u_int32)p->snapshot)
hdr->caplen = p->snapshot;
t = 0; /* no time stamps */
goto found;
@@ -875,7 +1127,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
/* these were written in opposite byte order */
interface_id = SWAPSHORT(pbp->interface_id);
hdr->caplen = SWAPLONG(pbp->caplen);
@@ -904,7 +1156,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte-swap it if necessary.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
idbp->linktype = SWAPSHORT(idbp->linktype);
idbp->snaplen = SWAPLONG(idbp->snaplen);
}
@@ -918,50 +1170,23 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* interfaces?
*/
if (p->linktype != idbp->linktype) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"an interface has a type %u different from the type of the first interface",
idbp->linktype);
return (-1);
}
- if (p->snapshot != idbp->snaplen) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ if ((bpf_u_int32)p->snapshot != idbp->snaplen) {
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"an interface has a snapshot length %u different from the type of the first interface",
idbp->snaplen);
return (-1);
}
/*
- * Count this interface.
+ * Try to add this interface.
*/
- p->sf.ifcount++;
-
- /*
- * Set the default time stamp resolution and offset.
- */
- tsresol = 1000000; /* microsecond resolution */
- tsoffset = 0; /* absolute timestamps */
-
- /*
- * Now look for various time stamp options, to
- * make sure they're the same.
- *
- * XXX - we could, in theory, handle multiple
- * different resolutions and offsets, but we
- * don't do so for now.
- */
- if (process_idb_options(p, &cursor, &tsresol, &tsoffset,
- p->errbuf) == -1)
- return (-1);
- if (tsresol != p->sf.tsresol) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "an interface has a time stamp resolution different from the time stamp resolution of the first interface");
+ if (!add_interface(p, &cursor, p->errbuf))
return (-1);
- }
- if (tsoffset != p->sf.tsoffset) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "an interface has a time stamp offset different from the time stamp offset of the first interface");
- return (-1);
- }
break;
case BT_SHB:
@@ -979,7 +1204,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* the same as that of the previous section.
* We'll check for that later.
*/
- if (p->sf.swapped) {
+ if (p->swapped) {
shbp->byte_order_magic =
SWAPLONG(shbp->byte_order_magic);
shbp->major_version =
@@ -1003,7 +1228,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Byte order changes.
*/
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"the file has sections with different byte orders");
return (-1);
@@ -1011,7 +1236,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
/*
* Not a valid SHB.
*/
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"the file has a section with a bad byte order magic field");
return (-1);
}
@@ -1021,7 +1246,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* we handle.
*/
if (shbp->major_version != PCAP_NG_VERSION_MAJOR) {
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"unknown pcap-ng savefile major version number %u",
shbp->major_version);
return (-1);
@@ -1036,7 +1261,7 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* any IDBs, we'll fail when we see a packet
* block.)
*/
- p->sf.ifcount = 0;
+ ps->ifcount = 0;
break;
default:
@@ -1044,43 +1269,148 @@ pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
* Not a packet block, IDB, or SHB; ignore it.
*/
break;
- }
+ }
}
found:
/*
* Is the interface ID an interface we know?
*/
- if (interface_id >= p->sf.ifcount) {
+ if (interface_id >= ps->ifcount) {
/*
* Yes. Fail.
*/
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"a packet arrived on interface %u, but there's no Interface Description Block for that interface",
interface_id);
return (-1);
}
/*
- * Convert the time stamp to a struct timeval.
+ * Convert the time stamp to seconds and fractions of a second,
+ * with the fractions being in units of the file-supplied resolution.
*/
- sec = t / p->sf.tsresol + p->sf.tsoffset;
- frac = t % p->sf.tsresol;
- if (p->sf.tsresol > 1000000) {
+ sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset;
+ frac = t % ps->ifaces[interface_id].tsresol;
+
+ /*
+ * Convert the fractions from units of the file-supplied resolution
+ * to units of the user-requested resolution.
+ */
+ switch (ps->ifaces[interface_id].scale_type) {
+
+ case PASS_THROUGH:
/*
- * Higher than microsecond resolution; scale down to
- * microseconds.
+ * The interface resolution is what the user wants,
+ * so we're done.
*/
- frac /= p->sf.tsscale;
- } else {
+ break;
+
+ case SCALE_UP_DEC:
+ /*
+ * The interface resolution is less than what the user
+ * wants; scale the fractional part up to the units of
+ * the resolution the user requested by multiplying by
+ * the quotient of the user-requested resolution and the
+ * file-supplied resolution.
+ *
+ * Those resolutions are both powers of 10, and the user-
+ * requested resolution is greater than the file-supplied
+ * resolution, so the quotient in question is an integer.
+ * We've calculated that quotient already, so we just
+ * multiply by it.
+ */
+ frac *= ps->ifaces[interface_id].scale_factor;
+ break;
+
+ case SCALE_UP_BIN:
/*
- * Lower than microsecond resolution; scale up to
- * microseconds.
+ * The interface resolution is less than what the user
+ * wants; scale the fractional part up to the units of
+ * the resolution the user requested by multiplying by
+ * the quotient of the user-requested resolution and the
+ * file-supplied resolution.
+ *
+ * The file-supplied resolution is a power of 2, so the
+ * quotient is not an integer, so, in order to do this
+ * entirely with integer arithmetic, we multiply by the
+ * user-requested resolution and divide by the file-
+ * supplied resolution.
+ *
+ * XXX - Is there something clever we could do here,
+ * given that we know that the file-supplied resolution
+ * is a power of 2? Doing a multiplication followed by
+ * a division runs the risk of overflowing, and involves
+ * two non-simple arithmetic operations.
*/
- frac *= p->sf.tsscale;
+ frac *= ps->user_tsresol;
+ frac /= ps->ifaces[interface_id].tsresol;
+ break;
+
+ case SCALE_DOWN_DEC:
+ /*
+ * The interface resolution is greater than what the user
+ * wants; scale the fractional part up to the units of
+ * the resolution the user requested by multiplying by
+ * the quotient of the user-requested resolution and the
+ * file-supplied resolution.
+ *
+ * Those resolutions are both powers of 10, and the user-
+ * requested resolution is less than the file-supplied
+ * resolution, so the quotient in question isn't an
+ * integer, but its reciprocal is, and we can just divide
+ * by the reciprocal of the quotient. We've calculated
+ * the reciprocal of that quotient already, so we must
+ * divide by it.
+ */
+ frac /= ps->ifaces[interface_id].scale_factor;
+ break;
+
+
+ case SCALE_DOWN_BIN:
+ /*
+ * The interface resolution is greater than what the user
+ * wants; convert the fractional part to units of the
+ * resolution the user requested by multiplying by the
+ * quotient of the user-requested resolution and the
+ * file-supplied resolution. We do that by multiplying
+ * by the user-requested resolution and dividing by the
+ * file-supplied resolution, as the quotient might not
+ * fit in an integer.
+ *
+ * The file-supplied resolution is a power of 2, so the
+ * quotient is not an integer, and neither is its
+ * reciprocal, so, in order to do this entirely with
+ * integer arithmetic, we multiply by the user-requested
+ * resolution and divide by the file-supplied resolution.
+ *
+ * XXX - Is there something clever we could do here,
+ * given that we know that the file-supplied resolution
+ * is a power of 2? Doing a multiplication followed by
+ * a division runs the risk of overflowing, and involves
+ * two non-simple arithmetic operations.
+ */
+ frac *= ps->user_tsresol;
+ frac /= ps->ifaces[interface_id].tsresol;
+ break;
}
- hdr->ts.tv_sec = sec;
- hdr->ts.tv_usec = frac;
+#ifdef _WIN32
+ /*
+ * tv_sec and tv_used in the Windows struct timeval are both
+ * longs.
+ */
+ hdr->ts.tv_sec = (long)sec;
+ hdr->ts.tv_usec = (long)frac;
+#else
+ /*
+ * tv_sec in the UN*X struct timeval is a time_t; tv_usec is
+ * suseconds_t in UN*Xes that work the way the current Single
+ * UNIX Standard specify - but not all older UN*Xes necessarily
+ * support that type, so just cast to int.
+ */
+ hdr->ts.tv_sec = (time_t)sec;
+ hdr->ts.tv_usec = (int)frac;
+#endif
/*
* Get a pointer to the packet data.
@@ -1089,23 +1419,8 @@ found:
if (*data == NULL)
return (-1);
- if (p->sf.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);
}