12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475 |
- /*
- * Copyright (c) 1993, 1994, 1995, 1996, 1997
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that: (1) source code distributions
- * retain the above copyright notice and this paragraph in its entirety, (2)
- * distributions including binary code include the above copyright notice and
- * this paragraph in its entirety in the documentation or other materials
- * provided with the distribution, and (3) all advertising materials mentioning
- * features or use of this software display the following acknowledgement:
- * ``This product includes software developed by the University of California,
- * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
- * the University nor the names of its contributors may be used to endorse
- * or promote products derived from this software without specific prior
- * written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * sf-pcapng.c - pcapng-file-format-specific code from savefile.c
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <pcap/pcap-inttypes.h>
- #include <errno.h>
- #include <memory.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "pcap-int.h"
- #include "pcap-common.h"
- #ifdef HAVE_OS_PROTO_H
- #include "os-proto.h"
- #endif
- #include "sf-pcapng.h"
- /*
- * Block types.
- */
- /*
- * Common part at the beginning of all blocks.
- */
- struct block_header {
- bpf_u_int32 block_type;
- bpf_u_int32 total_length;
- };
- /*
- * Common trailer at the end of all blocks.
- */
- struct block_trailer {
- bpf_u_int32 total_length;
- };
- /*
- * Common options.
- */
- #define OPT_ENDOFOPT 0 /* end of options */
- #define OPT_COMMENT 1 /* comment string */
- /*
- * Option header.
- */
- struct option_header {
- u_short option_code;
- u_short option_length;
- };
- /*
- * Structures for the part of each block type following the common
- * part.
- */
- /*
- * Section Header Block.
- */
- #define BT_SHB 0x0A0D0D0A
- struct section_header_block {
- bpf_u_int32 byte_order_magic;
- u_short major_version;
- u_short minor_version;
- uint64_t section_length;
- /* followed by options and trailer */
- };
- /*
- * Byte-order magic value.
- */
- #define BYTE_ORDER_MAGIC 0x1A2B3C4D
- /*
- * Current version number. If major_version isn't PCAP_NG_VERSION_MAJOR,
- * that means that this code can't read the file.
- */
- #define PCAP_NG_VERSION_MAJOR 1
- #define PCAP_NG_VERSION_MINOR 0
- /*
- * Interface Description Block.
- */
- #define BT_IDB 0x00000001
- struct interface_description_block {
- u_short linktype;
- u_short reserved;
- bpf_u_int32 snaplen;
- /* followed by options and trailer */
- };
- /*
- * Options in the IDB.
- */
- #define IF_NAME 2 /* interface name string */
- #define IF_DESCRIPTION 3 /* interface description string */
- #define IF_IPV4ADDR 4 /* interface's IPv4 address and netmask */
- #define IF_IPV6ADDR 5 /* interface's IPv6 address and prefix length */
- #define IF_MACADDR 6 /* interface's MAC address */
- #define IF_EUIADDR 7 /* interface's EUI address */
- #define IF_SPEED 8 /* interface's speed, in bits/s */
- #define IF_TSRESOL 9 /* interface's time stamp resolution */
- #define IF_TZONE 10 /* interface's time zone */
- #define IF_FILTER 11 /* filter used when capturing on interface */
- #define IF_OS 12 /* string OS on which capture on this interface was done */
- #define IF_FCSLEN 13 /* FCS length for this interface */
- #define IF_TSOFFSET 14 /* time stamp offset for this interface */
- /*
- * Enhanced Packet Block.
- */
- #define BT_EPB 0x00000006
- struct enhanced_packet_block {
- bpf_u_int32 interface_id;
- bpf_u_int32 timestamp_high;
- bpf_u_int32 timestamp_low;
- bpf_u_int32 caplen;
- bpf_u_int32 len;
- /* followed by packet data, options, and trailer */
- };
- /*
- * Simple Packet Block.
- */
- #define BT_SPB 0x00000003
- struct simple_packet_block {
- bpf_u_int32 len;
- /* followed by packet data and trailer */
- };
- /*
- * Packet Block.
- */
- #define BT_PB 0x00000002
- struct packet_block {
- u_short interface_id;
- u_short drops_count;
- bpf_u_int32 timestamp_high;
- bpf_u_int32 timestamp_low;
- bpf_u_int32 caplen;
- bpf_u_int32 len;
- /* followed by packet data, options, and trailer */
- };
- /*
- * Block cursor - used when processing the contents of a block.
- * Contains a pointer into the data being processed and a count
- * of bytes remaining in the block.
- */
- struct block_cursor {
- u_char *data;
- size_t data_remaining;
- bpf_u_int32 block_type;
- };
- typedef enum {
- PASS_THROUGH,
- SCALE_UP_DEC,
- SCALE_DOWN_DEC,
- SCALE_UP_BIN,
- SCALE_DOWN_BIN
- } tstamp_scale_type_t;
- /*
- * Per-interface information.
- */
- struct pcap_ng_if {
- uint64_t tsresol; /* time stamp resolution */
- tstamp_scale_type_t scale_type; /* how to scale */
- uint64_t scale_factor; /* time stamp scale factor for power-of-10 tsresol */
- uint64_t tsoffset; /* time stamp offset */
- };
- /*
- * Per-pcap_t private data.
- *
- * max_blocksize is the maximum size of a block that we'll accept. We
- * reject blocks bigger than this, so we don't consume too much memory
- * with a truly huge block. It can change as we see IDBs with different
- * link-layer header types. (Currently, we don't support IDBs with
- * different link-layer header types, but we will support it in the
- * future, when we offer file-reading APIs that support it.)
- *
- * XXX - that's an issue on ILP32 platforms, where the maximum block
- * size of 2^31-1 would eat all but one byte of the entire address space.
- * It's less of an issue on ILP64/LLP64 platforms, but the actual size
- * of the address space may be limited by 1) the number of *significant*
- * address bits (currently, x86-64 only supports 48 bits of address), 2)
- * any limitations imposed by the operating system; 3) any limitations
- * imposed by the amount of available backing store for anonymous pages,
- * so we impose a limit regardless of the size of a pointer.
- */
- struct pcap_ng_sf {
- uint64_t user_tsresol; /* time stamp resolution requested by the user */
- u_int max_blocksize; /* don't grow buffer size past this */
- bpf_u_int32 ifcount; /* number of interfaces seen in this capture */
- bpf_u_int32 ifaces_size; /* size of array below */
- struct pcap_ng_if *ifaces; /* array of interface information */
- };
- /*
- * Maximum block size for a given maximum snapshot length; we calculate
- * this based
- *
- * We define it as the size of an EPB with a max_snaplen-sized
- * packet and 128KB of options.
- */
- #define MAX_BLOCKSIZE(max_snaplen) (sizeof (struct block_header) + \
- sizeof (struct enhanced_packet_block) + \
- (max_snaplen) + 131072 + \
- sizeof (struct block_trailer))
- static void pcap_ng_cleanup(pcap_t *p);
- static int pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr,
- u_char **data);
- static int
- read_bytes(FILE *fp, void *buf, size_t bytes_to_read, int fail_on_eof,
- char *errbuf)
- {
- size_t amt_read;
- amt_read = fread(buf, 1, bytes_to_read, fp);
- if (amt_read != bytes_to_read) {
- if (ferror(fp)) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "error reading dump file");
- } else {
- if (amt_read == 0 && !fail_on_eof)
- return (0); /* EOF */
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "truncated dump file; tried to read %lu bytes, only got %lu",
- (unsigned long)bytes_to_read,
- (unsigned long)amt_read);
- }
- return (-1);
- }
- return (1);
- }
- static int
- read_block(FILE *fp, pcap_t *p, struct block_cursor *cursor, char *errbuf)
- {
- struct pcap_ng_sf *ps;
- int status;
- struct block_header bhdr;
- u_char *bdata;
- size_t data_remaining;
- ps = p->priv;
- status = read_bytes(fp, &bhdr, sizeof(bhdr), 0, errbuf);
- if (status <= 0)
- return (status); /* error or EOF */
- if (p->swapped) {
- bhdr.block_type = SWAPLONG(bhdr.block_type);
- bhdr.total_length = SWAPLONG(bhdr.total_length);
- }
- /*
- * Is this block "too big"?
- *
- * We choose 16MB as "too big", for now, so that we handle
- * "reasonably" large buffers but don't chew up all the
- * memory if we read a malformed file.
- */
- if (bhdr.total_length > 16*1024*1024) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "pcapng block size %u > maximum %u",
- bhdr.total_length, 16*1024*1024);
- return (-1);
- }
- /*
- * Is this block "too small" - i.e., is it shorter than a block
- * header plus a block trailer?
- */
- if (bhdr.total_length < sizeof(struct block_header) +
- sizeof(struct block_trailer)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "block in pcapng dump file has a length of %u < %lu",
- bhdr.total_length,
- (unsigned long)(sizeof(struct block_header) + sizeof(struct block_trailer)));
- return (-1);
- }
- /*
- * Is the buffer big enough?
- */
- if (p->bufsize < bhdr.total_length) {
- /*
- * No - make it big enough, unless it's too big.
- */
- void *bigger_buffer;
- if (bhdr.total_length > ps->max_blocksize) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "block is larger than maximum block size %u",
- ps->max_blocksize);
- return (-1);
- }
- bigger_buffer = realloc(p->buffer, bhdr.total_length);
- if (bigger_buffer == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
- return (-1);
- }
- p->buffer = bigger_buffer;
- }
- /*
- * Copy the stuff we've read to the buffer, and read the rest
- * of the block.
- */
- memcpy(p->buffer, &bhdr, sizeof(bhdr));
- bdata = (u_char *)p->buffer + sizeof(bhdr);
- data_remaining = bhdr.total_length - sizeof(bhdr);
- if (read_bytes(fp, bdata, data_remaining, 1, errbuf) == -1)
- return (-1);
- /*
- * Initialize the cursor.
- */
- cursor->data = bdata;
- cursor->data_remaining = data_remaining - sizeof(struct block_trailer);
- cursor->block_type = bhdr.block_type;
- return (1);
- }
- static void *
- get_from_block_data(struct block_cursor *cursor, size_t chunk_size,
- char *errbuf)
- {
- void *data;
- /*
- * Make sure we have the specified amount of data remaining in
- * the block data.
- */
- if (cursor->data_remaining < chunk_size) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "block of type %u in pcapng dump file is too short",
- cursor->block_type);
- return (NULL);
- }
- /*
- * Return the current pointer, and skip past the chunk.
- */
- data = cursor->data;
- cursor->data += chunk_size;
- cursor->data_remaining -= chunk_size;
- return (data);
- }
- 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(opthdr->option_length);
- }
- return (opthdr);
- }
- 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 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);
- }
- static int
- add_interface(pcap_t *p, struct block_cursor *cursor, char *errbuf)
- {
- struct pcap_ng_sf *ps;
- uint64_t 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 pcapng 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 pcapng 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 pcapng 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)) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "error reading dump file");
- *err = 1;
- return (NULL); /* fail */
- }
- /*
- * Possibly a weird short text file, so just say
- * "not pcapng".
- */
- return (NULL);
- }
- amt_read = fread(&byte_order_magic, 1, sizeof(byte_order_magic), fp);
- if (amt_read < sizeof(byte_order_magic)) {
- if (ferror(fp)) {
- pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
- errno, "error reading dump file");
- *err = 1;
- return (NULL); /* fail */
- }
- /*
- * Possibly a weird short text file, so just say
- * "not pcapng".
- */
- 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 pcapng 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)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "Section Header Block in pcapng 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 pcapng 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:
- pcap_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, up to
- * the maximum size. We start out with a maximum size based
- * on a maximum snapshot length of MAXIMUM_SNAPLEN; if we see
- * any link-layer header types with a larger maximum snapshot
- * length, we boost the maximum.
- */
- p->bufsize = 2048;
- if (p->bufsize < total_length)
- p->bufsize = total_length;
- p->buffer = malloc(p->bufsize);
- if (p->buffer == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "out of memory");
- free(p);
- *err = 1;
- return (NULL);
- }
- ps->max_blocksize = MAX_BLOCKSIZE(MAXIMUM_SNAPLEN);
- /*
- * 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 *)((u_char *)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,
- (u_char *)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(shbp->major_version);
- shbp->minor_version = SWAPSHORT(shbp->minor_version);
- /*
- * XXX - we don't care about the section length.
- */
- }
- /* currently only SHB version 1.0 is supported */
- if (! (shbp->major_version == PCAP_NG_VERSION_MAJOR &&
- shbp->minor_version == PCAP_NG_VERSION_MINOR)) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "unsupported pcapng savefile version %u.%u",
- shbp->major_version, shbp->minor_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 */
- pcap_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(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.
- */
- pcap_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;
- if (p->snapshot <= 0) {
- /*
- * Bogus snapshot length; use the maximum for this
- * link-layer type as a fallback.
- *
- * XXX - the only reason why snapshot is signed is
- * that pcap_snapshot() returns an int, not an
- * unsigned int.
- */
- p->snapshot = max_snaplen_for_dlt(idbp->linktype);
- }
- p->linktype = linktype_to_dlt(idbp->linktype);
- p->linktype_ext = 0;
- /*
- * If the maximum block size for a packet with the maximum
- * snapshot length for this DLT_ is bigger than the current
- * maximum block size, increase the maximum.
- */
- if (MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype)) > ps->max_blocksize)
- ps->max_blocksize = MAX_BLOCKSIZE(max_snaplen_for_dlt(p->linktype));
- 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);
- }
- static void
- pcap_ng_cleanup(pcap_t *p)
- {
- struct pcap_ng_sf *ps = p->priv;
- free(ps->ifaces);
- sf_cleanup(p);
- }
- /*
- * 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;
- uint64_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 = ((uint64_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 = ((uint64_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 (hdr->caplen > (bpf_u_int32)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(pbp->interface_id);
- hdr->caplen = SWAPLONG(pbp->caplen);
- hdr->len = SWAPLONG(pbp->len);
- t = ((uint64_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 = ((uint64_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(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) {
- pcap_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 ((bpf_u_int32)p->snapshot != idbp->snaplen) {
- pcap_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(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.
- */
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "the file has sections with different byte orders");
- return (-1);
- default:
- /*
- * Not a valid SHB.
- */
- pcap_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) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "unknown pcapng 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.
- */
- pcap_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);
- }
- if (hdr->caplen > (bpf_u_int32)p->snapshot) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "invalid packet capture length %u, bigger than "
- "snaplen of %d", hdr->caplen, p->snapshot);
- 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_DEC:
- /*
- * The interface resolution is less than what the user
- * wants; scale the fractional part up to the units of
- * the resolution the user requested by multiplying by
- * the quotient of the user-requested resolution and the
- * file-supplied resolution.
- *
- * Those resolutions are both powers of 10, and the user-
- * requested resolution is greater than the file-supplied
- * resolution, so the quotient in question is an integer.
- * We've calculated that quotient already, so we just
- * multiply by it.
- */
- frac *= ps->ifaces[interface_id].scale_factor;
- break;
- case SCALE_UP_BIN:
- /*
- * The interface resolution is less than what the user
- * wants; scale the fractional part up to the units of
- * the resolution the user requested by multiplying by
- * the quotient of the user-requested resolution and the
- * file-supplied resolution.
- *
- * The file-supplied resolution is a power of 2, so the
- * quotient is not an integer, so, in order to do this
- * entirely with integer arithmetic, we multiply by the
- * user-requested resolution and divide by the file-
- * supplied resolution.
- *
- * XXX - Is there something clever we could do here,
- * given that we know that the file-supplied resolution
- * is a power of 2? Doing a multiplication followed by
- * a division runs the risk of overflowing, and involves
- * two non-simple arithmetic operations.
- */
- frac *= ps->user_tsresol;
- frac /= ps->ifaces[interface_id].tsresol;
- break;
- case SCALE_DOWN_DEC:
- /*
- * The interface resolution is greater than what the user
- * wants; scale the fractional part up to the units of
- * the resolution the user requested by multiplying by
- * the quotient of the user-requested resolution and the
- * file-supplied resolution.
- *
- * Those resolutions are both powers of 10, and the user-
- * requested resolution is less than the file-supplied
- * resolution, so the quotient in question isn't an
- * integer, but its reciprocal is, and we can just divide
- * by the reciprocal of the quotient. We've calculated
- * the reciprocal of that quotient already, so we must
- * divide by it.
- */
- frac /= ps->ifaces[interface_id].scale_factor;
- break;
- case SCALE_DOWN_BIN:
- /*
- * The interface resolution is greater than what the user
- * wants; convert the fractional part 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.
- *
- * The file-supplied resolution is a power of 2, so the
- * quotient is not an integer, and neither is its
- * reciprocal, so, in order to do this entirely with
- * integer arithmetic, we multiply by the user-requested
- * resolution and divide by the file-supplied resolution.
- *
- * XXX - Is there something clever we could do here,
- * given that we know that the file-supplied resolution
- * is a power of 2? Doing a multiplication followed by
- * a division runs the risk of overflowing, and involves
- * two non-simple arithmetic operations.
- */
- frac *= ps->user_tsresol;
- frac /= ps->ifaces[interface_id].tsresol;
- break;
- }
- #ifdef _WIN32
- /*
- * tv_sec and tv_used in the Windows struct timeval are both
- * longs.
- */
- hdr->ts.tv_sec = (long)sec;
- hdr->ts.tv_usec = (long)frac;
- #else
- /*
- * tv_sec in the UN*X struct timeval is a time_t; tv_usec is
- * suseconds_t in UN*Xes that work the way the current Single
- * UNIX Standard specify - but not all older UN*Xes necessarily
- * support that type, so just cast to int.
- */
- hdr->ts.tv_sec = (time_t)sec;
- hdr->ts.tv_usec = (int)frac;
- #endif
- /*
- * 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);
- }
|