Esempio n. 1
0
void
swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
{
	/*
	 * Convert pseudo-headers from the byte order of
	 * the host on which the file was saved to our
	 * byte order, as necessary.
	 */
	switch (linktype) {

	case DLT_LINUX_SLL:
		swap_linux_sll_header(hdr, data);
		break;

	case DLT_USB_LINUX:
		swap_linux_usb_header(hdr, data, 0);
		break;

	case DLT_USB_LINUX_MMAPPED:
		swap_linux_usb_header(hdr, data, 1);
		break;

	case DLT_NFLOG:
		swap_nflog_header(hdr, data);
		break;
	}
}
Esempio n. 2
0
/*
 * Read and return the next packet from the savefile.  Return the header
 * in hdr and a pointer to the contents in data.  Return 0 on success, 1
 * if there were no more packets, and -1 on an error.
 */
static int
pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
{
	struct pcap_sf_patched_pkthdr sf_hdr;
	FILE *fp = p->sf.rfile;
	size_t amt_read;
	bpf_u_int32 t;

	/*
	 * Read the packet header; the structure we use as a buffer
	 * is the longer structure for files generated by the patched
	 * libpcap, but if the file has the magic number for an
	 * unpatched libpcap we only read as many bytes as the regular
	 * header has.
	 */
	amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp);
	if (amt_read != p->sf.hdrsize) {
		if (ferror(fp)) {
			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
			    "error reading dump file: %s",
			    pcap_strerror(errno));
			return (-1);
		} else {
			if (amt_read != 0) {
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "truncated dump file; tried to read %lu header bytes, only got %lu",
				    (unsigned long)p->sf.hdrsize,
				    (unsigned long)amt_read);
				return (-1);
			}
			/* EOF */
			return (1);
		}
	}

	if (p->sf.swapped) {
		/* these were written in opposite byte order */
		hdr->caplen = SWAPLONG(sf_hdr.caplen);
		hdr->len = SWAPLONG(sf_hdr.len);
		hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
		hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
	} else {
		hdr->caplen = sf_hdr.caplen;
		hdr->len = sf_hdr.len;
		hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
		hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
	}
	/* Swap the caplen and len fields, if necessary. */
	switch (p->sf.lengths_swapped) {

	case NOT_SWAPPED:
		break;

	case MAYBE_SWAPPED:
		if (hdr->caplen <= hdr->len) {
			/*
			 * The captured length is <= the actual length,
			 * so presumably they weren't swapped.
			 */
			break;
		}
		/* FALLTHROUGH */

	case SWAPPED:
		t = hdr->caplen;
		hdr->caplen = hdr->len;
		hdr->len = t;
		break;
	}

	if (hdr->caplen > p->bufsize) {
		/*
		 * This can happen due to Solaris 2.3 systems tripping
		 * over the BUFMOD problem and not setting the snapshot
		 * correctly in the savefile header.  If the caplen isn't
		 * grossly wrong, try to salvage.
		 */
		static u_char *tp = NULL;
		static size_t tsize = 0;

		if (hdr->caplen > 65535) {
			snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
			    "bogus savefile header");
			return (-1);
		}

		if (tsize < hdr->caplen) {
			tsize = ((hdr->caplen + 1023) / 1024) * 1024;
			if (tp != NULL)
				free((u_char *)tp);
			tp = (u_char *)malloc(tsize);
			if (tp == NULL) {
				tsize = 0;
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "BUFMOD hack malloc");
				return (-1);
			}
		}
		amt_read = fread((char *)tp, 1, hdr->caplen, fp);
		if (amt_read != hdr->caplen) {
			if (ferror(fp)) {
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "error reading dump file: %s",
				    pcap_strerror(errno));
			} else {
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "truncated dump file; tried to read %u captured bytes, only got %lu",
				    hdr->caplen, (unsigned long)amt_read);
			}
			return (-1);
		}
		/*
		 * We can only keep up to p->bufsize bytes.  Since
		 * caplen > p->bufsize is exactly how we got here,
		 * we know we can only keep the first p->bufsize bytes
		 * and must drop the remainder.  Adjust caplen accordingly,
		 * so we don't get confused later as to how many bytes we
		 * have to play with.
		 */
		hdr->caplen = p->bufsize;
		memcpy(p->buffer, (char *)tp, p->bufsize);
	} else {
		/* read the packet itself */
		amt_read = fread(p->buffer, 1, hdr->caplen, fp);
		if (amt_read != hdr->caplen) {
			if (ferror(fp)) {
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "error reading dump file: %s",
				    pcap_strerror(errno));
			} else {
				snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				    "truncated dump file; tried to read %u captured bytes, only got %lu",
				    hdr->caplen, (unsigned long)amt_read);
			}
			return (-1);
		}
	}
	*data = p->buffer;

	if (p->sf.swapped) {
		/*
		 * Convert pseudo-headers from the byte order of
		 * the host on which the file was saved to our
		 * byte order, as necessary.
		 */
		switch (p->linktype) {

		case DLT_USB_LINUX:
			swap_linux_usb_header(hdr, *data, 0);
			break;

		case DLT_USB_LINUX_MMAPPED:
			swap_linux_usb_header(hdr, *data, 1);
			break;
		}
	}

	return (0);
}
Esempio n. 3
0
/*
 * Read and return the next packet from the savefile.  Return the header
 * in hdr and a pointer to the contents in data.  Return 0 on success, 1
 * if there were no more packets, and -1 on an error.
 */
static int
pcap_ng_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data)
{
	struct block_cursor cursor;
	int status;
	struct pcapng_enhanced_packet_fields *epbp;
	struct pcapng_simple_packet_fields *spbp;
	struct pcapng_packet_fields *pbp;
	struct pcapng_option_header opthdr;
	bpf_u_int32 interface_id = 0xFFFFFFFF;
	struct pcapng_interface_description_fields *idbp;
	struct pcapng_section_header_fields *shbp;
	FILE *fp = p->sf.rfile;
	u_int tsresol;
	u_int64_t tsoffset;
	u_int64_t t, sec, frac;
	unsigned char packetpad;
	
	/*
	 * Look for an Enhanced Packet Block, a Simple Packet Block,
	 * or a Packet Block.
	 */
	for (;;) {
		/*
		 * Read the block type and length; those are common
		 * to all blocks.
		 */
		status = read_block(fp, p, &cursor, p->errbuf);
		if (status == 0)
			return (1);	/* EOF */
		if (status == -1)
			return (-1);	/* error */
		switch (cursor.block_type) {
				
			case PCAPNG_BT_EPB:
				/*
				 * Get a pointer to the fixed-length portion of the
				 * EPB.
				 */
				epbp = get_from_block_data(&cursor, sizeof(*epbp),
										   p->errbuf);
				if (epbp == NULL)
					return (-1);	/* error */
				
				/*
				 * Byte-swap it if necessary.
				 */
				if (p->sf.swapped) {
					/* these were written in opposite byte order */
					interface_id = SWAPLONG(epbp->interface_id);
					hdr->caplen = SWAPLONG(epbp->caplen);
					hdr->len = SWAPLONG(epbp->len);
					t = ((u_int64_t)SWAPLONG(epbp->timestamp_high)) << 32 |
					SWAPLONG(epbp->timestamp_low);
				} else {
					interface_id = epbp->interface_id;
					hdr->caplen = epbp->caplen;
					hdr->len = epbp->len;
					t = ((u_int64_t)epbp->timestamp_high) << 32 |
					epbp->timestamp_low;
				}
				goto found;
				
			case PCAPNG_BT_SPB:
				/*
				 * Get a pointer to the fixed-length portion of the
				 * SPB.
				 */
				spbp = get_from_block_data(&cursor, sizeof(*spbp),
										   p->errbuf);
				if (spbp == NULL)
					return (-1);	/* error */
				
				/*
				 * SPB packets are assumed to have arrived on
				 * the first interface.
				 */
				interface_id = 0;
				
				/*
				 * Byte-swap it if necessary.
				 */
				if (p->sf.swapped) {
					/* these were written in opposite byte order */
					hdr->len = SWAPLONG(spbp->len);
				} else
					hdr->len = spbp->len;
				
				/*
				 * The SPB doesn't give the captured length;
				 * it's the minimum of the snapshot length
				 * and the packet length.
				 */
				hdr->caplen = hdr->len;
				if (hdr->caplen > p->snapshot)
					hdr->caplen = p->snapshot;
				t = 0;	/* no time stamps */
				goto found;
				
			case PCAPNG_BT_PB:
				/*
				 * Get a pointer to the fixed-length portion of the
				 * PB.
				 */
				pbp = get_from_block_data(&cursor, sizeof(*pbp),
										  p->errbuf);
				if (pbp == NULL)
					return (-1);	/* error */
				
				/*
				 * Byte-swap it if necessary.
				 */
				if (p->sf.swapped) {
					/* these were written in opposite byte order */
					interface_id = SWAPSHORT(pbp->interface_id);
					hdr->caplen = SWAPLONG(pbp->caplen);
					hdr->len = SWAPLONG(pbp->len);
					t = ((u_int64_t)SWAPLONG(pbp->timestamp_high)) << 32 |
					SWAPLONG(pbp->timestamp_low);
				} else {
					interface_id = pbp->interface_id;
					hdr->caplen = pbp->caplen;
					hdr->len = pbp->len;
					t = ((u_int64_t)pbp->timestamp_high) << 32 |
					pbp->timestamp_low;
				}
				goto found;
				
			case PCAPNG_BT_IDB:
				/*
				 * Interface Description Block.  Get a pointer
				 * to its fixed-length portion.
				 */
				idbp = get_from_block_data(&cursor, sizeof(*idbp),
										   p->errbuf);
				if (idbp == NULL)
					return (-1);	/* error */
				
				/*
				 * Byte-swap it if necessary.
				 */
				if (p->sf.swapped) {
					idbp->linktype = SWAPSHORT(idbp->linktype);
					idbp->snaplen = SWAPLONG(idbp->snaplen);
				}
				
				/*
				 * If the link-layer type or snapshot length
				 * differ from the ones for the first IDB we
				 * saw, quit.
				 *
				 * XXX - just discard packets from those
				 * interfaces?
				 */
				if (p->linktype != idbp->linktype) {
					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
							 "an interface has a type %u different from the type of the first interface",
							 idbp->linktype);
					return (-1);
				}
				if (p->snapshot != idbp->snaplen) {
					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
							 "an interface has a snapshot length %u different from the type of the first interface",
							 idbp->snaplen);
					return (-1);
				}
				
				/*
				 * Set the default time stamp resolution and offset.
				 */
				tsresol = 1000000;	/* microsecond resolution */
				tsoffset = 0;		/* absolute timestamps */
				
				/*
				 * Now look for various time stamp options, to
				 * make sure they're the same.
				 *
				 * XXX - we could, in theory, handle multiple
				 * different resolutions and offsets, but we
				 * don't do so for now.
				 */
				if (process_idb_options(p, idbp, &cursor, &tsresol, &tsoffset,
										p->errbuf) == -1)
					return (-1);
				if (tsresol != p->sf.tsresol) {
					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
							 "an interface has a time stamp resolution different from the time stamp resolution of the first interface");
					return (-1);
				}
				if (tsoffset != p->sf.tsoffset) {
					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
							 "an interface has a time stamp offset different from the time stamp offset of the first interface");
					return (-1);
				}
				break;
				
			case PCAPNG_BT_SHB:
				/*
				 * Section Header Block.  Get a pointer
				 * to its fixed-length portion.
				 */
				shbp = get_from_block_data(&cursor, sizeof(*shbp),
										   p->errbuf);
				if (shbp == NULL)
					return (-1);	/* error */
				
				/*
				 * Assume the byte order of this section is
				 * the same as that of the previous section.
				 * We'll check for that later.
				 */
				if (p->sf.swapped) {
					shbp->byte_order_magic =
					SWAPLONG(shbp->byte_order_magic);
					shbp->major_version =
					SWAPSHORT(shbp->major_version);
				}
				
				/*
				 * Make sure the byte order doesn't change;
				 * pcap_is_swapped() shouldn't change its
				 * return value in the middle of reading a capture.
				 */
				switch (shbp->byte_order_magic) {
						
					case PCAPNG_BYTE_ORDER_MAGIC:
						/*
						 * OK.
						 */
						break;
						
					case SWAPLONG(PCAPNG_BYTE_ORDER_MAGIC):
						/*
						 * Byte order changes.
						 */
						snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
								 "the file has sections with different byte orders");
						return (-1);
						
					default:
						/*
						 * Not a valid SHB.
						 */
						snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
								 "the file has a section with a bad byte order magic field");
						return (-1);
				}
				
				/*
				 * Make sure the major version is the version
				 * we handle.
				 */
				if (shbp->major_version != PCAPNG_VERSION_MAJOR) {
					snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
							 "unknown pcap-ng savefile major version number %u",
							 shbp->major_version);
					return (-1);
				}
				
				/*
				 * Reset the interface count; this section should
				 * have its own set of IDBs.  If any of them
				 * don't have the same interface type, snapshot
				 * length, or resolution as the first interface
				 * we saw, we'll fail.  (And if we don't see
				 * any IDBs, we'll fail when we see a packet
				 * block.)
				 */
				p->ifcount = 0;
				break;
				
			default:
				/*
				 * Not a packet block, IDB, or SHB; ignore it.
				 */
				break;
		}
	}
	
found:
	/*
	 * Is the interface ID an interface we know?
	 */
	if (interface_id >= p->ifcount) {
		/*
		 * Yes.  Fail.
		 */
		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
				 "a packet arrived on interface %u, but there's no Interface Description Block for that interface",
				 interface_id);
		return (-1);
	}
	
	/*
	 * Convert the time stamp to a struct timeval.
	 */
	sec = t / p->sf.tsresol + p->sf.tsoffset;
	frac = t % p->sf.tsresol;
	if (p->sf.tsresol > 1000000) {
		/*
		 * Higher than microsecond resolution; scale down to
		 * microseconds.
		 */
		frac /= p->sf.tsscale;
	} else {
		/*
		 * Lower than microsecond resolution; scale up to
		 * microseconds.
		 */
		frac *= p->sf.tsscale;
	}
	hdr->ts.tv_sec = sec;
	hdr->ts.tv_usec = frac;
	
	/*
	 * Get a pointer to the packet data.
	 */
	*data = get_from_block_data(&cursor, hdr->caplen, p->errbuf);
	if (*data == NULL)
		return (-1);
	
	/*
	 * Skip padding.
	 */
	packetpad = 4 - (hdr->caplen % 4);
	if (hdr->caplen % 4 != 0 &&
		get_from_block_data(&cursor, packetpad, NULL) == NULL)
		return (-1);
	
	memset(hdr->comment, 0, sizeof(hdr->comment));

	if (get_opthdr_from_block_data(&opthdr, p->sf.swapped, &cursor, NULL) != NULL &&
		opthdr.option_code == PCAPNG_OPT_COMMENT && opthdr.option_length > 0) {
		char *optvalue;
		optvalue = get_optvalue_from_block_data(&cursor, &opthdr, NULL);
		if (optvalue == NULL)
			return (-1);
		memcpy(hdr->comment, optvalue, sizeof(hdr->comment));
	}
	
	if (p->sf.swapped) {
		/*
		 * Convert pseudo-headers from the byte order of
		 * the host on which the file was saved to our
		 * byte order, as necessary.
		 */
		switch (p->linktype) {
				
			case DLT_USB_LINUX:
				swap_linux_usb_header(hdr, *data, 0);
				break;
				
			case DLT_USB_LINUX_MMAPPED:
				swap_linux_usb_header(hdr, *data, 1);
				break;
		}
	}
	
	return (0);
}