static void * get_optvalue_from_block_data(struct block_cursor *cursor, struct option_header *opthdr, char *errbuf) { size_t padded_option_len; void *optvalue; /* Pad option length to 4-byte boundary */ padded_option_len = opthdr->option_length; padded_option_len = ((padded_option_len + 3)/4)*4; optvalue = get_from_block_data(cursor, padded_option_len, errbuf); if (optvalue == NULL) { /* * Option value is cut short. */ return (NULL); } return (optvalue); }
static struct option_header * get_opthdr_from_block_data(pcap_t *p, struct block_cursor *cursor, char *errbuf) { struct option_header *opthdr; opthdr = get_from_block_data(cursor, sizeof(*opthdr), errbuf); if (opthdr == NULL) { /* * Option header is cut short. */ return (NULL); } /* * Byte-swap it if necessary. */ if (p->swapped) { opthdr->option_code = SWAPSHORT(opthdr->option_code); opthdr->option_length = SWAPSHORT((uint32_t)opthdr->option_length); } return (opthdr); }
struct pcapng_option_header * get_opthdr_from_block_data(struct pcapng_option_header *opthdr, int swapped, struct block_cursor *cursor, char *errbuf) { struct pcapng_option_header *optp; optp = get_from_block_data(cursor, sizeof(*opthdr), errbuf); if (optp == NULL) { /* * Option header is cut short. */ return (NULL); } *opthdr = *optp; /* * Byte-swap it if necessary. */ if (swapped) { opthdr->option_code = SWAPSHORT(opthdr->option_code); opthdr->option_length = SWAPSHORT(opthdr->option_length); } return (opthdr); }
/* * 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 pcap_ng_sf *ps = p->priv; 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->rfile; 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->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->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 ((int)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->swapped) { /* these were written in opposite byte order */ interface_id = SWAPSHORT((uint32_t)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->swapped) { idbp->linktype = SWAPSHORT((uint32_t)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 != (int)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); } /* * Try to add this interface. */ if (!add_interface(p, &cursor, p->errbuf)) 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->swapped) { shbp->byte_order_magic = SWAPLONG(shbp->byte_order_magic); shbp->major_version = SWAPSHORT((uint32_t)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.) */ ps->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 >= ps->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 seconds and fractions of a second, * with the fractions being in units of the file-supplied resolution. */ sec = t / ps->ifaces[interface_id].tsresol + ps->ifaces[interface_id].tsoffset; frac = t % ps->ifaces[interface_id].tsresol; /* * Convert the fractions from units of the file-supplied resolution * to units of the user-requested resolution. */ switch (ps->ifaces[interface_id].scale_type) { case PASS_THROUGH: /* * The interface resolution is what the user wants, * so we're done. */ break; case SCALE_UP: case SCALE_DOWN: /* * The interface resolution is different from what the * user wants; convert the fractions to units of the * resolution the user requested by multiplying by the * quotient of the user-requested resolution and the * file-supplied resolution. We do that by multiplying * by the user-requested resolution and dividing by the * file-supplied resolution, as the quotient might not * fit in an integer. * * XXX - if ps->ifaces[interface_id].tsresol is a power * of 10, we could just multiply by the quotient of * ps->user_tsresol and ps->ifaces[interface_id].tsresol * in the scale-up case, and divide by the quotient of * ps->ifaces[interface_id].tsresol and ps->user_tsresol * in the scale-down case, as we know those will be integers. * That would involve fewer arithmetic operations, and * would run less risk of overflow. * * Is there something clever we could do if * ps->ifaces[interface_id].tsresol is a power of 2? */ frac *= ps->user_tsresol; frac /= ps->ifaces[interface_id].tsresol; break; } hdr->ts.tv_sec = sec; hdr->ts.tv_usec = (suseconds_t)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->swapped) swap_pseudo_headers(p->linktype, hdr, *data); return (0); }
/* * Check whether this is a pcap-ng savefile and, if it is, extract the * relevant information from the header. */ pcap_t * pcap_ng_check_header(bpf_u_int32 magic, FILE *fp, u_int precision, char *errbuf, int *err) { size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; struct block_header *bhdrp; struct section_header_block *shbp; pcap_t *p; int swapped = 0; struct pcap_ng_sf *ps; int status; struct block_cursor cursor; struct interface_description_block *idbp; /* * Assume no read errors. */ *err = 0; /* * 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 (NULL); /* 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)); *err = 1; return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (NULL); } 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)); *err = 1; return (NULL); /* fail */ } /* * Possibly a weird short text file, so just say * "not pcap-ng". */ return (NULL); } 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 (NULL); } 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))); *err = 1; return (NULL); } /* * OK, this is a good pcap-ng file. * Allocate a pcap_t for it. */ p = pcap_open_offline_common(errbuf, sizeof (struct pcap_ng_sf)); if (p == NULL) { /* Allocation failed. */ *err = 1; return (NULL); } p->swapped = swapped; ps = p->priv; /* * What precision does the user want? */ switch (precision) { case PCAP_TSTAMP_PRECISION_MICRO: ps->user_tsresol = 1000000; break; case PCAP_TSTAMP_PRECISION_NANO: ps->user_tsresol = 1000000000; break; default: snprintf(errbuf, PCAP_ERRBUF_SIZE, "unknown time stamp resolution %u", precision); free(p); *err = 1; return (NULL); } p->opt.tstamp_precision = precision; /* * 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 < (int)total_length) p->bufsize = total_length; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory"); free(p); *err = 1; return (NULL); } /* * Copy the stuff we've read to the buffer, and read the rest * of the SHB. */ bhdrp = (struct block_header *)(void *)p->buffer; shbp = (struct section_header_block *)(void *)(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->swapped) { /* * Byte-swap the fields we've read. */ shbp->major_version = SWAPSHORT((uint32_t)shbp->major_version); shbp->minor_version = SWAPSHORT((uint32_t)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->version_major = shbp->major_version; p->version_minor = shbp->minor_version; /* * Save the time stamp resolution the user requested. */ p->opt.tstamp_precision = precision; /* * 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(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->swapped) { idbp->linktype = SWAPSHORT((uint16_t)idbp->linktype); idbp->snaplen = SWAPLONG(idbp->snaplen); } /* * Try to add this interface. */ if (!add_interface(p, &cursor, errbuf)) goto fail; 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(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->next_packet_op = pcap_ng_next_packet; p->cleanup_op = pcap_ng_cleanup; return (p); fail: free(ps->ifaces); free(p->buffer); free(p); *err = 1; return (NULL); }
/* * The block is in p->buffer * We leave the content of the block intact and do not attempt to * correct the byte order as this will be done by the caller. */ static int pcap_ng_next_block(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_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; u_short interface_id = 0xFFFF; unsigned char packetpad; /* * 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 */ memset(hdr, 0, sizeof(struct pcap_pkthdr)); 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) { 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_packet; 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) { 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_packet; 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(epbp->timestamp_high)) << 32 | SWAPLONG(epbp->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_packet; 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 */ /* * 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: { bpf_u_int32 byte_order_magic; u_short major_version; /* * 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) { byte_order_magic = SWAPLONG(shbp->byte_order_magic); major_version = SWAPSHORT(shbp->major_version); } else { byte_order_magic = shbp->byte_order_magic; major_version = 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 (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 (major_version != PCAPNG_VERSION_MAJOR) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown pcap-ng savefile major version number %u", 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; } goto done; found_packet: /* * 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); done: return (0); }
/* * 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, int isng) { size_t amt_read; bpf_u_int32 total_length; bpf_u_int32 byte_order_magic; struct pcapng_block_header *bhdrp; struct pcapng_section_header_fields *shbp; int status; struct block_cursor cursor; struct pcapng_interface_description_fields *idbp; long file_offset = ftell(fp); /* * Check whether the first 4 bytes of the file are the block * type for a pcap-ng savefile. */ if (magic != PCAPNG_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 != PCAPNG_BYTE_ORDER_MAGIC) { byte_order_magic = SWAPLONG(byte_order_magic); if (byte_order_magic != PCAPNG_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 pcapng_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 pcapng_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 pcapng_block_header *)p->buffer; shbp = (struct pcapng_section_header_fields *)(p->buffer + sizeof(struct pcapng_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 != PCAPNG_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(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 PCAPNG_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); } /* * Now look for various time stamp options, so * we know how to interpret the time stamps. */ if (process_idb_options(p, idbp, &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); } p->tzoff = 0; /* XXX - not used in pcap */ p->snapshot = idbp->snaplen; p->linktype = linktype_to_dlt(idbp->linktype); p->linktype_ext = 0; goto done; case PCAPNG_BT_EPB: case PCAPNG_BT_SPB: case PCAPNG_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(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->sf.next_packet_op = isng ? pcap_ng_next_block : pcap_ng_next_packet; /* * Special using block based API */ if (isng) { /* * Rewind to begining of Section Header Block */ if (file_offset < 4) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bad file offset"); goto fail; } file_offset -= 4; fseek(fp, file_offset, SEEK_SET); p->linktype = DLT_PCAPNG; } return (1); fail: free(p->buffer); return (-1); }