summaryrefslogtreecommitdiff
path: root/sf-pcap.c
diff options
context:
space:
mode:
authorJean-Benoit MARTIN <jean-benoit.martin@open.eurogiciel.org>2014-11-07 15:44:25 +0100
committerJean-Benoit MARTIN <jean-benoit.martin@open.eurogiciel.org>2014-11-07 15:44:25 +0100
commita2db57476cfba84fc739ff1c5d907f03c7058257 (patch)
tree191a29b1ba93dade032af9edeea1353e54682c38 /sf-pcap.c
parent9a7f43d7ff4426a843b26762ca48a1a81a89bada (diff)
downloadlibpcap-a2db57476cfba84fc739ff1c5d907f03c7058257.tar.gz
libpcap-a2db57476cfba84fc739ff1c5d907f03c7058257.tar.bz2
libpcap-a2db57476cfba84fc739ff1c5d907f03c7058257.zip
Imported Upstream version 1.6.1upstream/1.6.1
Diffstat (limited to 'sf-pcap.c')
-rw-r--r--sf-pcap.c214
1 files changed, 164 insertions, 50 deletions
diff --git a/sf-pcap.c b/sf-pcap.c
index 2b31a2b..8180bc9 100644
--- a/sf-pcap.c
+++ b/sf-pcap.c
@@ -123,25 +123,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;
}
/*
@@ -162,13 +194,14 @@ pcap_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf)
(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,16 +213,81 @@ 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,
"archaic pcap savefile format");
- return (-1);
+ *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:
+ 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,
@@ -205,19 +303,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;
}
@@ -239,7 +337,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) {
/*
@@ -265,7 +363,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.
@@ -273,17 +371,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);
+ free(p);
+ *err = 1;
+ return (NULL);
}
- return (1);
+ p->cleanup_op = sf_cleanup;
+
+ return (p);
}
/*
@@ -294,8 +396,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;
@@ -306,8 +409,8 @@ 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,
"error reading dump file: %s",
@@ -317,7 +420,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
if (amt_read != 0) {
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);
}
@@ -326,7 +429,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);
@@ -338,8 +441,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;
@@ -371,7 +500,7 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
static u_char *tp = NULL;
static size_t tsize = 0;
- if (hdr->caplen > 65535) {
+ if (hdr->caplen > MAXIMUM_SNAPLEN) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"bogus savefile header");
return (-1);
@@ -430,33 +559,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;
@@ -507,7 +621,7 @@ 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) {
+ if (sf_write_header(p, f, linktype, p->tzoff, p->snapshot) == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Can't write to %s: %s",
fname, pcap_strerror(errno));
if (f != stdout)