static int
process_idb_options(pcap_t *p, struct block_cursor *cursor, u_int *tsresol,
    u_int64_t *tsoffset, char *errbuf)
{
	struct option_header *opthdr;
	void *optvalue;
	int saw_tsresol, saw_tsoffset;
	u_char tsresol_opt;
	u_int i;

	saw_tsresol = 0;
	saw_tsoffset = 0;
	while (cursor->data_remaining != 0) {
		/*
		 * Get the option header.
		 */
		opthdr = get_opthdr_from_block_data(p, cursor, errbuf);
		if (opthdr == NULL) {
			/*
			 * Option header is cut short.
			 */
			return (-1);
		}

		/*
		 * Get option value.
		 */
		optvalue = get_optvalue_from_block_data(cursor, opthdr,
		    errbuf);
		if (optvalue == NULL) {
			/*
			 * Option value is cut short.
			 */
			return (-1);
		}

		switch (opthdr->option_code) {

		case OPT_ENDOFOPT:
			if (opthdr->option_length != 0) {
				snprintf(errbuf, PCAP_ERRBUF_SIZE,
				    "Interface Description Block has opt_endofopt option with length %u != 0",
				    opthdr->option_length);
				return (-1);
			}
			goto done;

		case IF_TSRESOL:
			if (opthdr->option_length != 1) {
				snprintf(errbuf, PCAP_ERRBUF_SIZE,
				    "Interface Description Block has if_tsresol option with length %u != 1",
				    opthdr->option_length);
				return (-1);
			}
			if (saw_tsresol) {
				snprintf(errbuf, PCAP_ERRBUF_SIZE,
				    "Interface Description Block has more than one if_tsresol option");
				return (-1);
			}
			saw_tsresol = 1;
			memcpy(&tsresol_opt, optvalue, sizeof(tsresol_opt));
			if (tsresol_opt & 0x80) {
				/*
				 * Resolution is negative power of 2.
				 */
				*tsresol = 1 << (tsresol_opt & 0x7F);
			} else {
				/*
				 * Resolution is negative power of 10.
				 */
				*tsresol = 1;
				for (i = 0; i < tsresol_opt; i++)
					*tsresol *= 10;
			}
			if (*tsresol == 0) {
				/*
				 * Resolution is too high.
				 */
				if (tsresol_opt & 0x80) {
					snprintf(errbuf, PCAP_ERRBUF_SIZE,
					    "Interface Description Block if_tsresol option resolution 2^-%u is too high",
					    tsresol_opt & 0x7F);
				} else {
					snprintf(errbuf, PCAP_ERRBUF_SIZE,
					    "Interface Description Block if_tsresol option resolution 10^-%u is too high",
					    tsresol_opt);
				}
				return (-1);
			}
			break;

		case IF_TSOFFSET:
			if (opthdr->option_length != 8) {
				snprintf(errbuf, PCAP_ERRBUF_SIZE,
				    "Interface Description Block has if_tsoffset option with length %u != 8",
				    opthdr->option_length);
				return (-1);
			}
			if (saw_tsoffset) {
				snprintf(errbuf, PCAP_ERRBUF_SIZE,
				    "Interface Description Block has more than one if_tsoffset option");
				return (-1);
			}
			saw_tsoffset = 1;
			memcpy(tsoffset, optvalue, sizeof(*tsoffset));
			if (p->swapped)
				*tsoffset = (uint64_t)SWAPLL(*tsoffset);
			break;

		default:
			break;
		}
	}

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