void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data) { /* * Convert pseudo-headers from the byte order of * the host on which the file was saved to our * byte order, as necessary. */ switch (linktype) { case DLT_LINUX_SLL: swap_linux_sll_header(hdr, data); break; 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; case DLT_NFLOG: swap_nflog_header(hdr, data); break; } }
/* * Read and return the next packet from the savefile. Return the header * in hdr and a pointer to the contents in data. Return 0 on success, 1 * if there were no more packets, and -1 on an error. */ static int pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { struct pcap_sf_patched_pkthdr sf_hdr; FILE *fp = p->sf.rfile; size_t amt_read; bpf_u_int32 t; /* * Read the packet header; the structure we use as a buffer * is the longer structure for files generated by the patched * libpcap, but if the file has the magic number for an * 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) { if (ferror(fp)) { 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, "truncated dump file; tried to read %lu header bytes, only got %lu", (unsigned long)p->sf.hdrsize, (unsigned long)amt_read); return (-1); } /* EOF */ return (1); } } if (p->sf.swapped) { /* these were written in opposite byte order */ hdr->caplen = SWAPLONG(sf_hdr.caplen); hdr->len = SWAPLONG(sf_hdr.len); hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec); hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec); } else { hdr->caplen = sf_hdr.caplen; hdr->len = sf_hdr.len; hdr->ts.tv_sec = sf_hdr.ts.tv_sec; hdr->ts.tv_usec = sf_hdr.ts.tv_usec; } /* Swap the caplen and len fields, if necessary. */ switch (p->sf.lengths_swapped) { case NOT_SWAPPED: break; case MAYBE_SWAPPED: if (hdr->caplen <= hdr->len) { /* * The captured length is <= the actual length, * so presumably they weren't swapped. */ break; } /* FALLTHROUGH */ case SWAPPED: t = hdr->caplen; hdr->caplen = hdr->len; hdr->len = t; break; } if (hdr->caplen > p->bufsize) { /* * 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. */ static u_char *tp = NULL; static size_t tsize = 0; if (hdr->caplen > 65535) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "bogus savefile header"); 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) { if (ferror(fp)) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); } else { 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. */ 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, "error reading dump file: %s", pcap_strerror(errno)); } else { 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); } } *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; } } return (0); }
/* * Read and return the next packet from the savefile. Return the header * in hdr and a pointer to the contents in data. Return 0 on success, 1 * if there were no more packets, and -1 on an error. */ static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) { struct block_cursor cursor; int status; struct pcapng_enhanced_packet_fields *epbp; struct pcapng_simple_packet_fields *spbp; struct pcapng_packet_fields *pbp; struct pcapng_option_header opthdr; bpf_u_int32 interface_id = 0xFFFFFFFF; struct pcapng_interface_description_fields *idbp; struct pcapng_section_header_fields *shbp; FILE *fp = p->sf.rfile; u_int tsresol; u_int64_t tsoffset; u_int64_t t, sec, frac; unsigned char packetpad; /* * Look for an Enhanced Packet Block, a Simple Packet Block, * or a Packet Block. */ for (;;) { /* * Read the block type and length; those are common * to all blocks. */ status = read_block(fp, p, &cursor, p->errbuf); if (status == 0) return (1); /* EOF */ if (status == -1) return (-1); /* error */ switch (cursor.block_type) { case PCAPNG_BT_EPB: /* * Get a pointer to the fixed-length portion of the * EPB. */ epbp = get_from_block_data(&cursor, sizeof(*epbp), p->errbuf); if (epbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->sf.swapped) { /* these were written in opposite byte order */ interface_id = SWAPLONG(epbp->interface_id); hdr->caplen = SWAPLONG(epbp->caplen); hdr->len = SWAPLONG(epbp->len); t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 | SWAPLONG(epbp->timestamp_low); } else { interface_id = epbp->interface_id; hdr->caplen = epbp->caplen; hdr->len = epbp->len; t = ((u_int64_t)epbp->timestamp_high) << 32 | epbp->timestamp_low; } goto found; case PCAPNG_BT_SPB: /* * Get a pointer to the fixed-length portion of the * SPB. */ spbp = get_from_block_data(&cursor, sizeof(*spbp), p->errbuf); if (spbp == NULL) return (-1); /* error */ /* * SPB packets are assumed to have arrived on * the first interface. */ interface_id = 0; /* * Byte-swap it if necessary. */ if (p->sf.swapped) { /* these were written in opposite byte order */ hdr->len = SWAPLONG(spbp->len); } else hdr->len = spbp->len; /* * The SPB doesn't give the captured length; * it's the minimum of the snapshot length * and the packet length. */ hdr->caplen = hdr->len; if (hdr->caplen > p->snapshot) hdr->caplen = p->snapshot; t = 0; /* no time stamps */ goto found; case PCAPNG_BT_PB: /* * Get a pointer to the fixed-length portion of the * PB. */ pbp = get_from_block_data(&cursor, sizeof(*pbp), p->errbuf); if (pbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->sf.swapped) { /* these were written in opposite byte order */ interface_id = SWAPSHORT(pbp->interface_id); hdr->caplen = SWAPLONG(pbp->caplen); hdr->len = SWAPLONG(pbp->len); t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 | SWAPLONG(pbp->timestamp_low); } else { interface_id = pbp->interface_id; hdr->caplen = pbp->caplen; hdr->len = pbp->len; t = ((u_int64_t)pbp->timestamp_high) << 32 | pbp->timestamp_low; } goto found; case PCAPNG_BT_IDB: /* * Interface Description Block. Get a pointer * to its fixed-length portion. */ idbp = get_from_block_data(&cursor, sizeof(*idbp), p->errbuf); if (idbp == NULL) return (-1); /* error */ /* * Byte-swap it if necessary. */ if (p->sf.swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* * If the link-layer type or snapshot length * differ from the ones for the first IDB we * saw, quit. * * XXX - just discard packets from those * interfaces? */ if (p->linktype != idbp->linktype) { 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, "an interface has a snapshot length %u different from the type of the first interface", idbp->snaplen); return (-1); } /* * 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, idbp, &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"); 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 PCAPNG_BT_SHB: /* * Section Header Block. Get a pointer * to its fixed-length portion. */ shbp = get_from_block_data(&cursor, sizeof(*shbp), p->errbuf); if (shbp == NULL) return (-1); /* error */ /* * Assume the byte order of this section is * the same as that of the previous section. * We'll check for that later. */ if (p->sf.swapped) { shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic); shbp->major_version = SWAPSHORT(shbp->major_version); } /* * Make sure the byte order doesn't change; * pcap_is_swapped() shouldn't change its * return value in the middle of reading a capture. */ switch (shbp->byte_order_magic) { case PCAPNG_BYTE_ORDER_MAGIC: /* * OK. */ break; case SWAPLONG(PCAPNG_BYTE_ORDER_MAGIC): /* * Byte order changes. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has sections with different byte orders"); return (-1); default: /* * Not a valid SHB. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the file has a section with a bad byte order magic field"); return (-1); } /* * Make sure the major version is the version * we handle. */ if (shbp->major_version != PCAPNG_VERSION_MAJOR) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown pcap-ng savefile major version number %u", shbp->major_version); return (-1); } /* * Reset the interface count; this section should * have its own set of IDBs. If any of them * don't have the same interface type, snapshot * length, or resolution as the first interface * we saw, we'll fail. (And if we don't see * any IDBs, we'll fail when we see a packet * block.) */ p->ifcount = 0; break; default: /* * Not a packet block, IDB, or SHB; ignore it. */ break; } } found: /* * Is the interface ID an interface we know? */ if (interface_id >= p->ifcount) { /* * Yes. Fail. */ 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. */ sec = t / p->sf.tsresol + p->sf.tsoffset; frac = t % p->sf.tsresol; if (p->sf.tsresol > 1000000) { /* * Higher than microsecond resolution; scale down to * microseconds. */ frac /= p->sf.tsscale; } else { /* * Lower than microsecond resolution; scale up to * microseconds. */ frac *= p->sf.tsscale; } hdr->ts.tv_sec = sec; hdr->ts.tv_usec = frac; /* * Get a pointer to the packet data. */ *data = get_from_block_data(&cursor, hdr->caplen, p->errbuf); if (*data == NULL) return (-1); /* * Skip padding. */ packetpad = 4 - (hdr->caplen % 4); if (hdr->caplen % 4 != 0 && get_from_block_data(&cursor, packetpad, NULL) == NULL) return (-1); memset(hdr->comment, 0, sizeof(hdr->comment)); if (get_opthdr_from_block_data(&opthdr, p->sf.swapped, &cursor, NULL) != NULL && opthdr.option_code == PCAPNG_OPT_COMMENT && opthdr.option_length > 0) { char *optvalue; optvalue = get_optvalue_from_block_data(&cursor, &opthdr, NULL); if (optvalue == NULL) return (-1); memcpy(hdr->comment, optvalue, sizeof(hdr->comment)); } 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; } } return (0); }