static int add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct pcap_ng_sf *ps; u_int tsresol; u_int64_t tsoffset; ps = p->priv; /* * Count this interface. */ ps->ifcount++; /* * Grow the array of per-interface information as necessary. */ if (ps->ifcount > ps->ifaces_size) { /* * We need to grow the array. */ if (ps->ifaces == NULL) { /* * It's currently empty. */ ps->ifaces_size = 1; ps->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.) */ ps->ifaces_size *= 2; ps->ifaces = realloc(ps->ifaces, ps->ifaces_size * sizeof (struct pcap_ng_if)); } if (ps->ifaces == NULL) { /* * We ran out of memory. * Give up. */ snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory for per-interface information (%u interfaces)", ps->ifcount); return (0); } } /* * Set the default time stamp resolution and offset. */ tsresol = 1000000; /* microsecond resolution */ 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) return (0); ps->ifaces[ps->ifcount - 1].tsresol = tsresol; ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; /* * 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 { /* * The resolution is less than 1 * microsecond, so we have to scale * the timestamps up. */ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; } 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 { /* * The resolution is less than 1 * nanosecond, so we have to scale * the timestamps up. */ ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP; } break; } return (1); }
/* * 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 enhanced_packet_block *epbp; struct simple_packet_block *spbp; struct packet_block *pbp; bpf_u_int32 interface_id = 0xFFFFFFFF; struct interface_description_block *idbp; struct section_header_block *shbp; FILE *fp = p->sf.rfile; u_int tsresol; u_int64_t tsoffset; u_int64_t t, sec, frac; /* * 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 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 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 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 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); } /* * Count this interface. */ p->sf.ifcount++; /* * 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, &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 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 BYTE_ORDER_MAGIC: /* * OK. */ break; case SWAPLONG(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 != PCAP_NG_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->sf.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->sf.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); 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 add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct pcap_ng_sf *ps; u_int tsresol; uint64_t tsoffset; int is_binary; ps = p->priv; /* * Count this interface. */ ps->ifcount++; /* * Grow the array of per-interface information as necessary. */ if (ps->ifcount > ps->ifaces_size) { /* * We need to grow the array. */ 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 pcapng file with tens of millions of * interfaces).) */ 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. */ 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 (new_ifaces == NULL) { /* * We ran out of memory. * Give up. */ 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, &is_binary, errbuf) == -1) return (0); ps->ifaces[ps->ifcount - 1].tsresol = tsresol; ps->ifaces[ps->ifcount - 1].tsoffset = tsoffset; /* * Determine whether we're scaling up or down or not * at all for this interface. */ 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 { /* * Calculate the scale factor. */ ps->ifaces[ps->ifcount - 1].scale_factor = tsresol/ps->user_tsresol; ps->ifaces[ps->ifcount - 1].scale_type = SCALE_DOWN_DEC; } } 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 { /* * Calculate the scale factor. */ ps->ifaces[ps->ifcount - 1].scale_factor = ps->user_tsresol/tsresol; ps->ifaces[ps->ifcount - 1].scale_type = SCALE_UP_DEC; } } return (1); }
/* * Check whether this is a pcap-ng savefile and, if it is, extract the * relevant information from the header. */ int pcap_ng_check_header(pcap_t *p, bpf_u_int32 magic, FILE *fp, char *errbuf) { size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; struct block_header *bhdrp; struct section_header_block *shbp; int status; struct block_cursor cursor; struct interface_description_block *idbp; /* * Check whether the first 4 bytes of the file are the block * type for a pcap-ng savefile. */ if (magic != BT_SHB) { /* * XXX - check whether this looks like what the block * type would be after being munged by mapping between * UN*X and DOS/Windows text file format and, if it * does, look for the byte-order magic number in * the appropriate place and, if we find it, report * this as possibly being a pcap-ng file transferred * between UN*X and Windows in text file format? */ return (0); /* nope */ } /* * OK, they are. However, that's just \n\r\r\n, so it could, * conceivably, be an ordinary text file. * * It could not, however, conceivably be any other type of * capture file, so we can read the rest of the putative * Section Header Block; put the block type in the common * header, read the rest of the common header and the * fixed-length portion of the SHB, and look for the byte-order * magic value. */ amt_read = fread(&total_length, 1, sizeof(total_length), fp); if (amt_read < sizeof(total_length)) { if (ferror(fp)) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "error reading dump file: %s", pcap_strerror(errno)); return (-1); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (0); } 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, "error reading dump file: %s", pcap_strerror(errno)); return (-1); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (0); } if (byte_order_magic != BYTE_ORDER_MAGIC) { byte_order_magic = SWAPLONG(byte_order_magic); if (byte_order_magic != BYTE_ORDER_MAGIC) { /* * Not a pcap-ng file. */ return (0); } p->sf.swapped = 1; total_length = SWAPLONG(total_length); } /* * Check the sanity of the total length. */ if (total_length < sizeof(*bhdrp) + sizeof(*shbp) + sizeof(struct block_trailer)) { 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))); return (-1); } /* * Allocate a buffer into which to read blocks. We default to * the maximum of: * * the total length of the SHB for which we read the header; * * 2K, which should be more than large enough for an Enhanced * Packet Block containing a full-size Ethernet frame, and * leaving room for some options. * * If we find a bigger block, we reallocate the buffer. */ p->bufsize = 2048; if (p->bufsize < total_length) p->bufsize = total_length; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); return (-1); } /* * Copy the stuff we've read to the buffer, and read the rest * of the SHB. */ bhdrp = (struct block_header *)p->buffer; shbp = (struct section_header_block *)(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)), total_length - (sizeof(magic) + sizeof(total_length) + sizeof(byte_order_magic)), 1, errbuf) == -1) goto fail; if (p->sf.swapped) { /* * Byte-swap the fields we've read. */ shbp->major_version = SWAPSHORT(shbp->major_version); shbp->minor_version = SWAPSHORT(shbp->minor_version); /* * 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); goto fail; } p->sf.version_major = shbp->major_version; p->sf.version_minor = shbp->minor_version; /* * Set the default time stamp resolution and offset. */ p->sf.tsresol = 1000000; /* microsecond resolution */ p->sf.tsscale = 1; /* multiply by 1 to scale to microseconds */ p->sf.tsoffset = 0; /* absolute timestamps */ /* * Now start looking for an Interface Description Block. */ for (;;) { /* * Read the next block. */ status = read_block(fp, p, &cursor, errbuf); if (status == 0) { /* EOF - no IDB in this file */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the capture file has no Interface Description Blocks"); goto fail; } if (status == -1) goto fail; /* error */ switch (cursor.block_type) { case BT_IDB: /* * Get a pointer to the fixed-length portion of the * IDB. */ idbp = get_from_block_data(&cursor, sizeof(*idbp), errbuf); if (idbp == NULL) goto fail; /* error */ /* * Byte-swap it if necessary. */ if (p->sf.swapped) { idbp->linktype = SWAPSHORT(idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* * Count this interface. */ p->sf.ifcount++; /* * Now look for various time stamp options, so * we know how to interpret the time stamps. */ if (process_idb_options(p, &cursor, &p->sf.tsresol, &p->sf.tsoffset, errbuf) == -1) goto fail; /* * 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); } goto done; case BT_EPB: case BT_SPB: case BT_PB: /* * Saw a packet before we saw any IDBs. That's * not valid, as we don't know what link-layer * encapsulation the packet has. */ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "the capture file has a packet block before any Interface Description Blocks"); goto fail; default: /* * Just ignore it. */ break; } } done: p->tzoff = 0; /* XXX - not used in pcap */ p->snapshot = idbp->snaplen; p->linktype = linktype_to_dlt(idbp->linktype); p->linktype_ext = 0; p->sf.next_packet_op = pcap_ng_next_packet; return (1); fail: free(p->buffer); return (-1); }