#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libpcapng/blocks.h>
#include <libpcapng/io.h>
#define PCAP_MAGIC_NATIVE 0xa1b2c3d4u
#define PCAP_MAGIC_SWAPPED 0xd4c3b2a1u
#define PCAP_MAGIC_NS_NAT 0xa1b23c4du
#define PCAP_MAGIC_NS_SWP 0x4d3cb2a1u
static uint16_t _pcap_swap16(uint16_t v) {
return (uint16_t)((v >> 8) | (v << 8));
}
static uint32_t _pcap_swap32(uint32_t v) {
return ((v & 0x000000FFu) << 24) | ((v & 0x0000FF00u) << 8) |
((v & 0x00FF0000u) >> 8) | ((v & 0xFF000000u) >> 24);
}
static uint32_t _pcap_u32(const unsigned char *p, int swap) {
uint32_t v; memcpy(&v, p, 4); return swap ? _pcap_swap32(v) : v;
}
static uint16_t _pcap_u16(const unsigned char *p, int swap) {
uint16_t v; memcpy(&v, p, 2); return swap ? _pcap_swap16(v) : v;
}
static int _pcap_classic_magic(const unsigned char *buf, size_t buf_len, int *need_swap)
{
uint32_t magic;
if (buf_len < 4) return 0;
memcpy(&magic, buf, 4);
if (magic == PCAP_MAGIC_NATIVE || magic == PCAP_MAGIC_NS_NAT) { *need_swap = 0; return 1; }
if (magic == PCAP_MAGIC_SWAPPED || magic == PCAP_MAGIC_NS_SWP) { *need_swap = 1; return 1; }
return 0;
}
static void _pcap_emit_idb(uint32_t linktype, uint32_t snaplen,
foreach_pcapng_block_cb cb, void *userdata)
{
unsigned char idb[12];
uint16_t lt16 = (uint16_t)(linktype & 0xffffu), rsv = 0;
uint32_t idb_btl = 20;
memcpy(idb + 0, <16, 2);
memcpy(idb + 2, &rsv, 2);
memcpy(idb + 4, &snaplen, 4);
memcpy(idb + 8, &idb_btl, 4);
cb(0, PCAPNG_INTERFACE_DESCRIPTION_BLOCK, idb_btl, idb, userdata);
}
static int _pcap_emit_epb(uint32_t ts_sec, uint32_t ts_usec,
const unsigned char *pkt, uint32_t incl_len, uint32_t orig_len,
uint64_t counter, foreach_pcapng_block_cb cb, void *userdata)
{
uint32_t pad = (4 - (incl_len % 4)) % 4;
uint32_t epb_btl = 8 + 20 + incl_len + pad + 4;
uint32_t data_sz = epb_btl - 8;
unsigned char *epb = (unsigned char *)malloc(data_sz);
if (!epb) return -1;
uint32_t iface = 0;
memcpy(epb + 0, &iface, 4);
memcpy(epb + 4, &ts_sec, 4);
memcpy(epb + 8, &ts_usec, 4);
memcpy(epb + 12, &incl_len, 4);
memcpy(epb + 16, &orig_len, 4);
memcpy(epb + 20, pkt, incl_len);
memset(epb + 20 + incl_len, 0, pad);
memcpy(epb + 20 + incl_len + pad, &epb_btl, 4);
cb((uint32_t)counter, PCAPNG_ENHANCED_PACKET_BLOCK, epb_btl, epb, userdata);
free(epb);
return 0;
}
static int _mem_read_classic_pcap(const unsigned char *buf, size_t buf_len,
foreach_pcapng_block_cb cb, void *userdata)
{
if (buf_len < 24) return -1;
int swap;
if (!_pcap_classic_magic(buf, buf_len, &swap)) return -1;
uint32_t snaplen = _pcap_u32(buf + 16, swap);
uint32_t linktype = _pcap_u32(buf + 20, swap);
_pcap_emit_idb(linktype, snaplen, cb, userdata);
size_t off = 24;
uint64_t ctr = 1;
while (off + 16 <= buf_len) {
uint32_t ts_sec = _pcap_u32(buf + off + 0, swap);
uint32_t ts_usec = _pcap_u32(buf + off + 4, swap);
uint32_t incl_len = _pcap_u32(buf + off + 8, swap);
uint32_t orig_len = _pcap_u32(buf + off + 12, swap);
off += 16;
if (incl_len > 65535 || off + incl_len > buf_len) break;
_pcap_emit_epb(ts_sec, ts_usec, buf + off, incl_len, orig_len, ctr, cb, userdata);
off += incl_len;
ctr++;
}
return 0;
}
static int _mem_read_pcapng(const unsigned char *buf, size_t buf_len,
foreach_pcapng_block_cb cb, void *userdata)
{
size_t off = 0;
uint64_t ctr = 1;
while (off + 8 <= buf_len) {
uint32_t block_type, block_total_length;
memcpy(&block_type, buf + off, 4);
memcpy(&block_total_length, buf + off + 4, 4);
if (block_total_length < 12 || off + block_total_length > buf_len) break;
cb((uint32_t)ctr, block_type, block_total_length,
(unsigned char *)(buf + off + 8), userdata);
off += block_total_length;
ctr++;
}
return 0;
}
static int _fp_read_classic_pcap(FILE *fp, foreach_pcapng_block_cb cb, void *userdata)
{
unsigned char global_hdr[24];
if (fread(global_hdr, 1, 24, fp) != 24) return -1;
int swap;
if (!_pcap_classic_magic(global_hdr, 24, &swap)) return -1;
uint32_t snaplen = _pcap_u32(global_hdr + 16, swap);
uint32_t linktype = _pcap_u32(global_hdr + 20, swap);
_pcap_emit_idb(linktype, snaplen, cb, userdata);
uint8_t pkt_hdr[16];
uint64_t ctr = 1;
unsigned char *pkt_buf = NULL;
uint32_t pkt_buf_cap = 0;
while (fread(pkt_hdr, 1, 16, fp) == 16) {
uint32_t ts_sec = _pcap_u32(pkt_hdr + 0, swap);
uint32_t ts_usec = _pcap_u32(pkt_hdr + 4, swap);
uint32_t incl_len = _pcap_u32(pkt_hdr + 8, swap);
uint32_t orig_len = _pcap_u32(pkt_hdr + 12, swap);
if (incl_len > 65535) break;
if (incl_len > pkt_buf_cap) {
free(pkt_buf);
pkt_buf = (unsigned char *)malloc(incl_len);
if (!pkt_buf) return -1;
pkt_buf_cap = incl_len;
}
if (fread(pkt_buf, 1, incl_len, fp) != incl_len) break;
_pcap_emit_epb(ts_sec, ts_usec, pkt_buf, incl_len, orig_len, ctr, cb, userdata);
ctr++;
}
free(pkt_buf);
return 0;
}
int foreach_pcapng_block(uint32_t block_counter, uint32_t block_type, uint32_t block_total_length, unsigned char *data, void *userdata)
{
switch (block_type) {
case PCAPNG_SECTION_HEADER_BLOCK: {
pcapng_section_header_block_light_t *shb;
shb = libpcapng_section_header_block_read(data, block_total_length);
}
break;
case PCAPNG_CUSTOM_DATA_BLOCK: {
pcapng_custom_data_block_light_t *cb;
cb = libpcapng_custom_data_block_read(data, block_total_length);
}
break;
case PCAPNG_ENHANCED_PACKET_BLOCK: {
pcapng_enhanced_packet_block_light_t *epb;
epb = libpcapng_enhanced_packet_block_read(data, block_total_length);
}
break;
case PCAPNG_INTERFACE_DESCRIPTION_BLOCK:
printf("Interface Description Block\n");
break;
default:
fprintf(stderr, "Block type %x not handled yet!\n", block_type);
break;
}
return 0;
}
int libpcapng_mem_read(unsigned char *buf, size_t buf_len,
foreach_pcapng_block_cb pcapng_block_cb, void *userdata)
{
int swap;
if (!pcapng_block_cb) { fprintf(stderr, "No Block Callback set!\n"); return -1; }
if (_pcap_classic_magic(buf, buf_len, &swap))
return _mem_read_classic_pcap(buf, buf_len, pcapng_block_cb, userdata);
return _mem_read_pcapng(buf, buf_len, pcapng_block_cb, userdata);
}
int libpcapng_fp_read(FILE *fp, foreach_pcapng_block_cb pcapng_block_cb, void *userdata)
{
uint64_t block_counter = 1;
uint32_t block_info[2]; size_t read_length;
unsigned char data[65535]; uint32_t block_total_length = 0;
if (!pcapng_block_cb) {
fprintf(stderr, "No Block Callback set!\n");
return -1;
}
{
unsigned char magic_buf[4];
if (fread(magic_buf, 1, 4, fp) != 4) return -1;
int swap;
if (_pcap_classic_magic(magic_buf, 4, &swap)) {
fseek(fp, 0, SEEK_SET);
return _fp_read_classic_pcap(fp, pcapng_block_cb, userdata);
}
fseek(fp, 0, SEEK_SET);
}
read_length = fread(&block_info, 1, PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH, fp);
if (read_length != PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH) {
fprintf(stderr, "Could not read expected data: got %lu expected %u. Stopping.\n", read_length, PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH);
return -1;
}
block_total_length = block_info[1];
while (read_length > 0) {
if (block_total_length - PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH > sizeof(data)) {
fprintf(stderr, "Block size %u exceeds buffer. Stopping.\n", block_total_length);
return -1;
}
read_length = fread(&data, 1, block_total_length - PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH, fp);
if (read_length != block_info[1] - PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH) {
fprintf(stderr, "Could not read expected (%u) block_size; Got %lu. Stopping.\n", block_info[1], read_length);
return -1;
}
pcapng_block_cb(block_counter, block_info[0], block_info[1], (unsigned char *)data, (void *)userdata);
read_length = fread(&block_info, 1, PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH, fp);
if (read_length == 0) {
break;
}
if (read_length != PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH) {
fprintf(stderr, "Could not read expected (%d) data; Got %lu. Stopping.\n", PCAPNG_BLOCK_TYPE_AND_SIZE_LENGTH, read_length);
return -1;
}
block_total_length = block_info[1];
block_counter++;
}
return 0;
}
int libpcapng_file_read(char *filename, foreach_pcapng_block_cb pcapng_block_cb, void *userdata)
{
FILE *fp;
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Cannot read file '%s'\n", filename);
return -1;
}
libpcapng_fp_read(fp, pcapng_block_cb, userdata);
fclose(fp);
return 0;
}
int libpcapng_file_read_debug(char *filename)
{
return libpcapng_file_read(filename, foreach_pcapng_block, NULL);
}
int libpcapng_padded_count(unsigned char *data, uint32_t data_len)
{
int retpad = 0;
int i;
for (i = (int)data_len - 1; i >= 0 && retpad < 3; i--) {
if (data[i] == 0)
retpad++;
else
break;
}
return retpad;
}