static int process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol, u_int64_t *tsoffset, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; u_char tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ opthdr = get_opthdr_from_block_data(p, cursor, errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (-1); } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (-1); } switch (opthdr->option_code) { case OPT_ENDOFOPT: if (opthdr->option_length != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); } goto done; case IF_TSRESOL: if (opthdr->option_length != 1) { 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, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } if (*tsresol == 0) { /* * Resolution is too high. */ if (tsresol_opt & 0x80) { 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, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } return (-1); } break; case IF_TSOFFSET: if (opthdr->option_length != 8) { 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, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->swapped) *tsoffset = (uint64_t)SWAPLL(*tsoffset); break; default: break; } } done: 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); }
static int process_idb_options(pcap_t *p, struct pcapng_interface_description_fields *idbp, struct block_cursor *cursor, u_int *tsresol, u_int64_t *tsoffset, char *errbuf) { struct pcapng_option_header opthdr; void *optvalue; int saw_tsresol, saw_tsoffset, saw_ifname; u_char tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; saw_ifname = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ if (get_opthdr_from_block_data(&opthdr, p->sf.swapped, cursor, errbuf) == NULL) { /* * Option header is cut short. */ goto fail; /* error */ } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, &opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ goto fail; /* error */ } switch (opthdr.option_code) { case PCAPNG_IF_NAME: if (saw_ifname) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_name option"); goto fail; /* error */ } saw_ifname = 1; break; case PCAPNG_OPT_ENDOFOPT: if (opthdr.option_length != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr.option_length); goto fail; /* error */ } goto done; case PCAPNG_IF_TSRESOL: if (opthdr.option_length != 1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsresol option with length %u != 1", opthdr.option_length); goto fail; /* error */ } if (saw_tsresol) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); goto fail; /* error */ } saw_tsresol = 1; tsresol_opt = *(u_int *)optvalue; if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ *tsresol = 1 << (tsresol_opt & 0x7F); } else { /* * Resolution is negative power of 10. */ *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } if (*tsresol == 0) { /* * Resolution is too high. */ if (tsresol_opt & 0x80) { 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, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); } goto fail; /* error */ } break; case PCAPNG_IF_TSOFFSET: if (opthdr.option_length != 8) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has if_tsoffset option with length %u != 8", opthdr.option_length); goto fail; /* error */ } if (saw_tsoffset) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); goto fail; /* error */ } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->sf.swapped) *tsoffset = SWAPLL(*tsoffset); break; default: break; } } done: /* * Count this interface. */ p->ifcount++; /* * Compute the scaling factor to convert the * sub-second part of the time stamp to * microseconds. */ if (p->sf.tsresol > 1000000) { /* * Higher than microsecond resolution; * scale down to microseconds. */ p->sf.tsscale = (p->sf.tsresol / 1000000); } else { /* * Lower than microsecond resolution; * scale up to microseconds. */ p->sf.tsscale = (1000000 / p->sf.tsresol); } return (0); fail: return (-1); }
static int process_idb_options(pcap_t *p, struct block_cursor *cursor, uint64_t *tsresol, uint64_t *tsoffset, int *is_binary, char *errbuf) { struct option_header *opthdr; void *optvalue; int saw_tsresol, saw_tsoffset; uint8_t tsresol_opt; u_int i; saw_tsresol = 0; saw_tsoffset = 0; while (cursor->data_remaining != 0) { /* * Get the option header. */ opthdr = get_opthdr_from_block_data(p, cursor, errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (-1); } /* * Get option value. */ optvalue = get_optvalue_from_block_data(cursor, opthdr, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (-1); } switch (opthdr->option_code) { case OPT_ENDOFOPT: if (opthdr->option_length != 0) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has opt_endofopt option with length %u != 0", opthdr->option_length); return (-1); } goto done; case IF_TSRESOL: if (opthdr->option_length != 1) { 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) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsresol option"); return (-1); } saw_tsresol = 1; memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt)); if (tsresol_opt & 0x80) { /* * Resolution is negative power of 2. */ uint8_t tsresol_shift = (tsresol_opt & 0x7F); if (tsresol_shift > 63) { /* * Resolution is too high; 2^-{res} * won't fit in a 64-bit value. */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 2^-%u is too high", tsresol_shift); return (-1); } *is_binary = 1; *tsresol = ((uint64_t)1) << tsresol_shift; } else { /* * Resolution is negative power of 10. */ if (tsresol_opt > 19) { /* * Resolution is too high; 2^-{res} * won't fit in a 64-bit value (the * largest power of 10 that fits * in a 64-bit value is 10^19, as * the largest 64-bit unsigned * value is ~1.8*10^19). */ pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block if_tsresol option resolution 10^-%u is too high", tsresol_opt); return (-1); } *is_binary = 0; *tsresol = 1; for (i = 0; i < tsresol_opt; i++) *tsresol *= 10; } break; case IF_TSOFFSET: if (opthdr->option_length != 8) { 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) { pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Interface Description Block has more than one if_tsoffset option"); return (-1); } saw_tsoffset = 1; memcpy(tsoffset, optvalue, sizeof(*tsoffset)); if (p->swapped) *tsoffset = SWAPLL(*tsoffset); break; default: break; } } done: return (0); }