diff options
Diffstat (limited to 'sf-pcap-ng.c')
-rw-r--r-- | sf-pcap-ng.c | 405 |
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. |