aboutsummaryrefslogtreecommitdiff
path: root/sf-pcap-ng.c
diff options
context:
space:
mode:
Diffstat (limited to 'sf-pcap-ng.c')
-rw-r--r--sf-pcap-ng.c405
1 files changed, 284 insertions, 121 deletions
diff --git a/sf-pcap-ng.c b/sf-pcap-ng.c
index fae408679a5d..0c02829e71e5 100644
--- a/sf-pcap-ng.c
+++ b/sf-pcap-ng.c
@@ -30,9 +30,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
@@ -42,7 +42,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>
@@ -121,6 +121,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,8 +204,10 @@ struct block_cursor {
typedef enum {
PASS_THROUGH,
- SCALE_UP,
- SCALE_DOWN
+ SCALE_UP_DEC,
+ SCALE_DOWN_DEC,
+ SCALE_UP_BIN,
+ SCALE_DOWN_BIN
} tstamp_scale_type_t;
/*
@@ -212,14 +215,15 @@ typedef enum {
*/
struct pcap_ng_if {
u_int tsresol; /* time stamp resolution */
- u_int64_t tsoffset; /* time stamp offset */
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 arrary below */
+ bpf_u_int32 ifaces_size; /* size of array below */
struct pcap_ng_if *ifaces; /* array of interface information */
};
@@ -236,13 +240,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);
@@ -257,6 +261,8 @@ 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)
@@ -275,7 +281,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);
@@ -287,7 +293,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)));
@@ -301,11 +307,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;
}
/*
@@ -313,16 +322,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);
}
@@ -338,7 +347,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);
@@ -401,7 +410,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;
@@ -439,7 +448,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);
@@ -448,13 +457,13 @@ 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);
}
@@ -464,11 +473,13 @@ process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
/*
* 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;
@@ -478,11 +489,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);
}
@@ -492,13 +503,13 @@ 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);
}
@@ -523,6 +534,7 @@ 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;
@@ -538,43 +550,107 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
/*
* We need to grow the array.
*/
- if (ps->ifaces == NULL) {
+ 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).)
*/
- ps->ifaces_size = 1;
- ps->ifaces = malloc(sizeof (struct pcap_ng_if));
+ 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.
*/
- ps->ifaces_size *= 2;
- ps->ifaces = realloc(ps->ifaces, ps->ifaces_size * sizeof (struct pcap_ng_if));
+ 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 (ps->ifaces == NULL) {
+ if (new_ifaces == NULL) {
/*
* We ran out of memory.
* Give up.
*/
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ 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, errbuf) == -1)
+ if (process_idb_options(p, cursor, &tsresol, &tsoffset, &is_binary,
+ errbuf) == -1)
return (0);
ps->ifaces[ps->ifcount - 1].tsresol = tsresol;
@@ -584,55 +660,40 @@ add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
* Determine whether we're scaling up or down or not
* at all for this interface.
*/
- switch (p->opt.tstamp_precision) {
-
- case PCAP_TSTAMP_PRECISION_MICRO:
- if (tsresol == 1000000) {
- /*
- * The resolution is 1 microsecond,
- * so we don't have to do scaling.
- */
- ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH;
- } else if (tsresol > 1000000) {
- /*
- * The resolution is greater than
- * 1 microsecond, so we have to
- * scale the timestamps down.
- */
- ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN;
- } else {
+ 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 {
/*
- * The resolution is less than 1
- * microsecond, so we have to scale
- * the timestamps up.
+ * Calculate the scale factor.
*/
- ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP;
+ ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol;
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC;
}
- break;
-
- case PCAP_TSTAMP_PRECISION_NANO:
- if (tsresol == 1000000000) {
- /*
- * The resolution is 1 nanosecond,
- * so we don't have to do scaling.
- */
- ps->ifaces[ps->ifcount - 1].scale_type = PASS_THROUGH;
- } else if (tsresol > 1000000000) {
- /*
- * The resolution is greater than
- * 1 nanosecond, so we have to
- * scale the timestamps down.
- */
- ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN;
- } else {
+ } 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 {
/*
- * The resolution is less than 1
- * nanosecond, so we have to scale
- * the timestamps up.
+ * Calculate the scale factor.
*/
- ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP;
+ ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol;
+ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC;
}
- break;
}
return (1);
}
@@ -664,7 +725,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
/*
* 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) {
/*
@@ -693,7 +754,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, 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));
*err = 1;
@@ -709,7 +770,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
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));
*err = 1;
@@ -738,7 +799,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, 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)));
@@ -773,7 +834,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
break;
default:
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"unknown time stamp resolution %u", precision);
free(p);
*err = 1;
@@ -799,7 +860,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
p->bufsize = total_length;
p->buffer = malloc(p->bufsize);
if (p->buffer == NULL) {
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
free(p);
*err = 1;
return (NULL);
@@ -810,12 +871,12 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, 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;
@@ -831,10 +892,12 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, 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->version_major = shbp->major_version;
@@ -855,7 +918,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
status = read_block(fp, p, &cursor, errbuf);
if (status == 0) {
/* EOF - no IDB in this file */
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has no Interface Description Blocks");
goto fail;
}
@@ -882,10 +945,22 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
}
/*
+ * Interface capture length sanity check
+ */
+ 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;
+ }
+
+ /*
* Try to add this interface.
*/
if (!add_interface(p, &cursor, errbuf))
goto fail;
+
goto done;
case BT_EPB:
@@ -896,7 +971,7 @@ pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf,
* not valid, as we don't know what link-layer
* encapsulation the packet has.
*/
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
"the capture file has a packet block before any Interface Description Blocks");
goto fail;
@@ -1000,7 +1075,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
@@ -1032,7 +1107,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;
@@ -1093,13 +1168,13 @@ 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);
@@ -1151,7 +1226,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);
@@ -1159,7 +1234,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);
}
@@ -1169,7 +1244,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);
@@ -1192,7 +1267,7 @@ 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:
@@ -1203,17 +1278,23 @@ found:
/*
* 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 / 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:
@@ -1223,29 +1304,111 @@ found:
*/
break;
- case SCALE_UP:
- case SCALE_DOWN:
+ case SCALE_UP_DEC:
/*
- * The interface resolution is different from what the
- * user wants; scale up or down to that resolution.
+ * 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.
*
- * XXX - if ps->ifaces[interface_id].tsresol is a power
- * of 10, we could just multiply by the quotient of
- * ps->ifaces[interface_id].tsresol and ps->user_tsresol
- * in the scale-up case, and divide by the quotient of
- * ps->user_tsresol and ps->ifaces[interface_id].tsresol
- * in the scale-down case, as we know those are integers,
- * which would involve fewer arithmetic operations.
+ * 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:
+ /*
+ * 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.
*
- * Is there something clever we could do if
- * ps->ifaces[interface_id].tsresol is a power of 2?
+ * 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 *= 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->ifaces[interface_id].tsresol;
- frac /= ps->user_tsresol;
+ 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.