diff options
Diffstat (limited to 'freebsd/contrib/libpcap/sf-pcap.c')
-rw-r--r-- | freebsd/contrib/libpcap/sf-pcap.c | 540 |
1 files changed, 440 insertions, 100 deletions
diff --git a/freebsd/contrib/libpcap/sf-pcap.c b/freebsd/contrib/libpcap/sf-pcap.c index 6fda84f2..d7cb806f 100644 --- a/freebsd/contrib/libpcap/sf-pcap.c +++ b/freebsd/contrib/libpcap/sf-pcap.c @@ -39,9 +39,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 @@ -51,7 +51,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> @@ -72,7 +72,7 @@ static const char rcsid[] _U_ = /* * Setting O_BINARY on DOS/Windows is a bit tricky */ -#if defined(WIN32) +#if defined(_WIN32) #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #elif defined(MSDOS) #if defined(__HIGHC__) @@ -125,25 +125,57 @@ static const char rcsid[] _U_ = static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **datap); /* + * Private data for reading pcap savefiles. + */ +typedef enum { + NOT_SWAPPED, + SWAPPED, + MAYBE_SWAPPED +} swapped_type_t; + +typedef enum { + PASS_THROUGH, + SCALE_UP, + SCALE_DOWN +} tstamp_scale_type_t; + +struct pcap_sf { + size_t hdrsize; + swapped_type_t lengths_swapped; + tstamp_scale_type_t scale_type; +}; + +/* * Check whether this is a pcap savefile and, if it is, extract the * relevant information from the header. */ -int -pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) +pcap_t * +pcap_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, + int *err) { struct pcap_file_header hdr; size_t amt_read; + pcap_t *p; + int swapped = 0; + struct pcap_sf *ps; + + /* + * Assume no read errors. + */ + *err = 0; /* * Check whether the first 4 bytes of the file are the magic * number for a pcap savefile, or for a byte-swapped pcap * savefile. */ - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) { + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) { magic = SWAPLONG(magic); - if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC) - return (0); /* nope */ - p->sf.swapped = 1; + if (magic != TCPDUMP_MAGIC && magic != KUZNETZOV_TCPDUMP_MAGIC && + magic != NSEC_TCPDUMP_MAGIC) + return (NULL); /* nope */ + swapped = 1; } /* @@ -155,22 +187,23 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) sizeof(hdr) - sizeof(hdr.magic), fp); if (amt_read != sizeof(hdr) - sizeof(hdr.magic)) { if (ferror(fp)) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu file header bytes, only got %lu", (unsigned long)sizeof(hdr), (unsigned long)amt_read); } - return (-1); + *err = 1; + return (NULL); } /* * If it's a byte-swapped capture file, byte-swap the header. */ - if (p->sf.swapped) { + if (swapped) { hdr.version_major = SWAPSHORT(hdr.version_major); hdr.version_minor = SWAPSHORT(hdr.version_minor); hdr.thiszone = SWAPLONG(hdr.thiszone); @@ -180,18 +213,106 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) } if (hdr.version_major < PCAP_VERSION_MAJOR) { - snprintf(errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "archaic pcap savefile format"); - return (-1); + *err = 1; + return (NULL); + } + + /* + * currently only versions 2.[0-4] are supported with + * the exception of 543.0 for DG/UX tcpdump. + */ + if (! ((hdr.version_major == PCAP_VERSION_MAJOR && + hdr.version_minor <= PCAP_VERSION_MINOR) || + (hdr.version_major == 543 && + hdr.version_minor == 0))) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unsupported pcap savefile version %u.%u", + hdr.version_major, hdr.version_minor); + *err = 1; + return NULL; + } + + if (hdr.snaplen > MAXIMUM_SNAPLEN) { + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "invalid file capture length %u, bigger than " + "maximum of %u", hdr.snaplen, MAXIMUM_SNAPLEN); + *err = 1; + return NULL; + } + + /* + * OK, this is a good pcap file. + * Allocate a pcap_t for it. + */ + p = pcap_open_offline_common(errbuf, sizeof (struct pcap_sf)); + if (p == NULL) { + /* Allocation failed. */ + *err = 1; + return (NULL); } - p->sf.version_major = hdr.version_major; - p->sf.version_minor = hdr.version_minor; + p->swapped = swapped; + p->version_major = hdr.version_major; + p->version_minor = hdr.version_minor; p->tzoff = hdr.thiszone; p->snapshot = hdr.snaplen; p->linktype = linktype_to_dlt(LT_LINKTYPE(hdr.linktype)); p->linktype_ext = LT_LINKTYPE_EXT(hdr.linktype); - p->sf.next_packet_op = pcap_next_packet; + p->next_packet_op = pcap_next_packet; + + ps = p->priv; + + p->opt.tstamp_precision = precision; + + /* + * Will we need to scale the timestamps to match what the + * user wants? + */ + switch (precision) { + + case PCAP_TSTAMP_PRECISION_MICRO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the user + * wants microseconds; scale the + * precision down. + */ + ps->scale_type = SCALE_DOWN; + } else { + /* + * The file has microseconds, the + * user wants microseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } + break; + + case PCAP_TSTAMP_PRECISION_NANO: + if (magic == NSEC_TCPDUMP_MAGIC) { + /* + * The file has nanoseconds, the + * user wants nanoseconds; nothing to do. + */ + ps->scale_type = PASS_THROUGH; + } else { + /* + * The file has microoseconds, the user + * wants nanoseconds; scale the + * precision up. + */ + ps->scale_type = SCALE_UP; + } + break; + + default: + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "unknown time stamp resolution %u", precision); + free(p); + *err = 1; + return (NULL); + } /* * We interchanged the caplen and len fields at version 2.3, @@ -207,19 +328,19 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) case 2: if (hdr.version_minor < 3) - p->sf.lengths_swapped = SWAPPED; + ps->lengths_swapped = SWAPPED; else if (hdr.version_minor == 3) - p->sf.lengths_swapped = MAYBE_SWAPPED; + ps->lengths_swapped = MAYBE_SWAPPED; else - p->sf.lengths_swapped = NOT_SWAPPED; + ps->lengths_swapped = NOT_SWAPPED; break; case 543: - p->sf.lengths_swapped = SWAPPED; + ps->lengths_swapped = SWAPPED; break; default: - p->sf.lengths_swapped = NOT_SWAPPED; + ps->lengths_swapped = NOT_SWAPPED; break; } @@ -241,7 +362,7 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) * data ourselves and read from that buffer in order to * make that work. */ - p->sf.hdrsize = sizeof(struct pcap_sf_patched_pkthdr); + ps->hdrsize = sizeof(struct pcap_sf_patched_pkthdr); if (p->linktype == DLT_EN10MB) { /* @@ -267,7 +388,7 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) p->snapshot += 14; } } else - p->sf.hdrsize = sizeof(struct pcap_sf_pkthdr); + ps->hdrsize = sizeof(struct pcap_sf_pkthdr); /* * Allocate a buffer for the packet data. @@ -275,17 +396,21 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) p->bufsize = p->snapshot; if (p->bufsize <= 0) { /* - * Bogus snapshot length; use 64KiB as a fallback. + * Bogus snapshot length; use the maximum as a fallback. */ - p->bufsize = 65536; + p->bufsize = MAXIMUM_SNAPLEN; } 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); } - return (1); + p->cleanup_op = sf_cleanup; + + return (p); } /* @@ -296,8 +421,9 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { + struct pcap_sf *ps = p->priv; struct pcap_sf_patched_pkthdr sf_hdr; - FILE *fp = p->sf.rfile; + FILE *fp = p->rfile; size_t amt_read; bpf_u_int32 t; @@ -308,18 +434,18 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) * unpatched libpcap we only read as many bytes as the regular * header has. */ - amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp); - if (amt_read != p->sf.hdrsize) { + amt_read = fread(&sf_hdr, 1, ps->hdrsize, fp); + if (amt_read != ps->hdrsize) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); return (-1); } else { if (amt_read != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %lu header bytes, only got %lu", - (unsigned long)p->sf.hdrsize, + (unsigned long)ps->hdrsize, (unsigned long)amt_read); return (-1); } @@ -328,7 +454,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } } - if (p->sf.swapped) { + if (p->swapped) { /* these were written in opposite byte order */ hdr->caplen = SWAPLONG(sf_hdr.caplen); hdr->len = SWAPLONG(sf_hdr.len); @@ -340,8 +466,34 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) hdr->ts.tv_sec = sf_hdr.ts.tv_sec; hdr->ts.tv_usec = sf_hdr.ts.tv_usec; } + + switch (ps->scale_type) { + + case PASS_THROUGH: + /* + * Just pass the time stamp through. + */ + break; + + case SCALE_UP: + /* + * File has microseconds, user wants nanoseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec * 1000; + break; + + case SCALE_DOWN: + /* + * File has nanoseconds, user wants microseconds; convert + * it. + */ + hdr->ts.tv_usec = hdr->ts.tv_usec / 1000; + break; + } + /* Swap the caplen and len fields, if necessary. */ - switch (p->sf.lengths_swapped) { + switch (ps->lengths_swapped) { case NOT_SWAPPED: break; @@ -367,63 +519,93 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) /* * This can happen due to Solaris 2.3 systems tripping * over the BUFMOD problem and not setting the snapshot - * correctly in the savefile header. If the caplen isn't - * grossly wrong, try to salvage. + * correctly in the savefile header. + * This can also happen with a corrupted savefile or a + * savefile built/modified by a fuzz tester. + * If the caplen isn't grossly wrong, try to salvage. */ - static u_char *tp = NULL; - static size_t tsize = 0; - - if (hdr->caplen > 65535) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "bogus savefile header"); + size_t bytes_to_discard; + size_t bytes_to_read, bytes_read; + char discard_buf[4096]; + + if (hdr->caplen > MAXIMUM_SNAPLEN) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "invalid packet capture length %u, bigger than " + "maximum of %u", hdr->caplen, MAXIMUM_SNAPLEN); return (-1); } - if (tsize < hdr->caplen) { - tsize = ((hdr->caplen + 1023) / 1024) * 1024; - if (tp != NULL) - free((u_char *)tp); - tp = (u_char *)malloc(tsize); - if (tp == NULL) { - tsize = 0; - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BUFMOD hack malloc"); - return (-1); - } - } - amt_read = fread((char *)tp, 1, hdr->caplen, fp); - if (amt_read != hdr->caplen) { + /* + * XXX - we don't grow the buffer here because some + * program might assume that it will never get packets + * bigger than the snapshot length; for example, it might + * copy data from our buffer to a buffer of its own, + * allocated based on the return value of pcap_snapshot(). + * + * Read the first p->bufsize bytes into the buffer. + */ + amt_read = fread(p->buffer, 1, p->bufsize, fp); + if (amt_read != p->bufsize) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + /* + * Yes, this uses hdr->caplen; technically, + * it's true, because we would try to read + * and discard the rest of those bytes, and + * that would fail because we got EOF before + * the read finished. + */ + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } return (-1); } + /* - * We can only keep up to p->bufsize bytes. Since - * caplen > p->bufsize is exactly how we got here, - * we know we can only keep the first p->bufsize bytes - * and must drop the remainder. Adjust caplen accordingly, - * so we don't get confused later as to how many bytes we - * have to play with. + * Now read and discard what's left. + */ + bytes_to_discard = hdr->caplen - p->bufsize; + bytes_read = amt_read; + while (bytes_to_discard != 0) { + bytes_to_read = bytes_to_discard; + if (bytes_to_read > sizeof (discard_buf)) + bytes_to_read = sizeof (discard_buf); + amt_read = fread(discard_buf, 1, bytes_to_read, fp); + bytes_read += amt_read; + if (amt_read != bytes_to_read) { + if (ferror(fp)) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "error reading dump file: %s", + pcap_strerror(errno)); + } else { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "truncated dump file; tried to read %u captured bytes, only got %lu", + hdr->caplen, (unsigned long)bytes_read); + } + return (-1); + } + bytes_to_discard -= amt_read; + } + + /* + * Adjust caplen accordingly, so we don't get confused later + * as to how many bytes we have to play with. */ hdr->caplen = p->bufsize; - memcpy(p->buffer, (char *)tp, p->bufsize); } else { /* read the packet itself */ amt_read = fread(p->buffer, 1, hdr->caplen, fp); if (amt_read != hdr->caplen) { if (ferror(fp)) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "truncated dump file; tried to read %u captured bytes, only got %lu", hdr->caplen, (unsigned long)amt_read); } @@ -432,33 +614,18 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) } *data = p->buffer; - 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); } static int -sf_write_header(FILE *fp, int linktype, int thiszone, int snaplen) +sf_write_header(pcap_t *p, FILE *fp, int linktype, int thiszone, int snaplen) { struct pcap_file_header hdr; - hdr.magic = TCPDUMP_MAGIC; + hdr.magic = p->opt.tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ? NSEC_TCPDUMP_MAGIC : TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; @@ -496,7 +663,7 @@ static pcap_dumper_t * pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) { -#if defined(WIN32) || defined(MSDOS) +#if defined(_WIN32) || defined(MSDOS) /* * If we're writing to the standard output, put it in binary * mode, as savefiles are binary files. @@ -509,8 +676,8 @@ pcap_setup_dump(pcap_t *p, int linktype, FILE *f, const char *fname) else setbuf(f, NULL); #endif - if (sf_write_header(f, linktype, p->tzoff, p->snapshot) == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", fname, pcap_strerror(errno)); if (f != stdout) (void)fclose(f); @@ -533,31 +700,36 @@ pcap_dump_open(pcap_t *p, const char *fname) * link-layer type, so we can't use it. */ if (!p->activated) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: not-yet-activated pcap_t passed to pcap_dump_open", fname); return (NULL); } linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: link-layer type %d isn't supported in savefiles", fname, p->linktype); return (NULL); } linktype |= p->linktype_ext; + if (fname == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } if (fname[0] == '-' && fname[1] == '\0') { f = stdout; fname = "standard output"; } else { -#if !defined(WIN32) && !defined(MSDOS) +#if !defined(_WIN32) && !defined(MSDOS) f = fopen(fname, "w"); #else f = fopen(fname, "wb"); #endif if (f == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); return (NULL); } @@ -570,12 +742,12 @@ pcap_dump_open(pcap_t *p, const char *fname) */ pcap_dumper_t * pcap_dump_fopen(pcap_t *p, FILE *f) -{ +{ int linktype; linktype = dlt_to_linktype(p->linktype); if (linktype == -1) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "stream: link-layer type %d isn't supported in savefiles", p->linktype); return (NULL); @@ -585,6 +757,174 @@ pcap_dump_fopen(pcap_t *p, FILE *f) return (pcap_setup_dump(p, linktype, f, "stream")); } +pcap_dumper_t * +pcap_dump_open_append(pcap_t *p, const char *fname) +{ + FILE *f; + int linktype; + size_t amt_read; + struct pcap_file_header ph; + + linktype = dlt_to_linktype(p->linktype); + if (linktype == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: link-layer type %d isn't supported in savefiles", + fname, linktype); + return (NULL); + } + + if (fname == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "A null pointer was supplied as the file name"); + return NULL; + } + if (fname[0] == '-' && fname[1] == '\0') + return (pcap_setup_dump(p, linktype, stdout, "standard output")); + +#if !defined(_WIN32) && !defined(MSDOS) + f = fopen(fname, "r+"); +#else + f = fopen(fname, "rb+"); +#endif + if (f == NULL) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + return (NULL); + } + + /* + * Try to read a pcap header. + */ + amt_read = fread(&ph, 1, sizeof (ph), f); + if (amt_read != sizeof (ph)) { + if (ferror(f)) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", + fname, pcap_strerror(errno)); + fclose(f); + return (NULL); + } else if (feof(f) && amt_read > 0) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: truncated pcap file header", fname); + fclose(f); + return (NULL); + } + } + +#if defined(_WIN32) || defined(MSDOS) + /* + * We turn off buffering. + * XXX - why? And why not on the standard output? + */ + setbuf(f, NULL); +#endif + + /* + * If a header is already present and: + * + * it's not for a pcap file of the appropriate resolution + * and the right byte order for this machine; + * + * the link-layer header types don't match; + * + * the snapshot lengths don't match; + * + * return an error. + */ + if (amt_read > 0) { + /* + * A header is already present. + * Do the checks. + */ + switch (ph.magic) { + + case TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_MICRO) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case NSEC_TCPDUMP_MAGIC: + if (p->opt.tstamp_precision != PCAP_TSTAMP_PRECISION_NANO) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different time stamp precision, cannot append to file", fname); + fclose(f); + return (NULL); + } + break; + + case SWAPLONG(TCPDUMP_MAGIC): + case SWAPLONG(NSEC_TCPDUMP_MAGIC): + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different byte order, cannot append to file", fname); + fclose(f); + return (NULL); + + case KUZNETZOV_TCPDUMP_MAGIC: + case SWAPLONG(KUZNETZOV_TCPDUMP_MAGIC): + case NAVTEL_TCPDUMP_MAGIC: + case SWAPLONG(NAVTEL_TCPDUMP_MAGIC): + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file to which we can append", fname); + fclose(f); + return (NULL); + + default: + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: not a pcap file", fname); + fclose(f); + return (NULL); + } + + /* + * Good version? + */ + if (ph.version_major != PCAP_VERSION_MAJOR || + ph.version_minor != PCAP_VERSION_MINOR) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: version is %u.%u, cannot append to file", fname, + ph.version_major, ph.version_minor); + fclose(f); + return (NULL); + } + if ((bpf_u_int32)linktype != ph.linktype) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different linktype, cannot append to file", fname); + fclose(f); + return (NULL); + } + if ((bpf_u_int32)p->snapshot != ph.snaplen) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "%s: different snaplen, cannot append to file", fname); + fclose(f); + return (NULL); + } + } else { + /* + * A header isn't present; attempt to write it. + */ + if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + } + + /* + * Start writing at the end of the file. + */ + if (fseek(f, 0, SEEK_END) == -1) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't seek to end of %s: %s", + fname, pcap_strerror(errno)); + (void)fclose(f); + return (NULL); + } + return ((pcap_dumper_t *)f); +} + FILE * pcap_dump_file(pcap_dumper_t *p) { |