Skip to content

Commit

Permalink
pcap: Add initial pcap builder
Browse files Browse the repository at this point in the history
Since pcap is trivial enough a protocol, and we only want to produce a
capture file, it didn't make sense to pull in libpcal-dev as an external
dependency.

Signed-off-by: Siddharth Chandrasekaran <[email protected]>
  • Loading branch information
sidcha committed Feb 15, 2024
1 parent 79dd8bd commit 409a258
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
31 changes: 31 additions & 0 deletions include/utils/pcap_gen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Siddharth Chandrasekaran <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef _UTILS_PCAP_GEN_H_
#define _UTILS_PCAP_GEN_H_

#include <stdint.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
FILE *file;
size_t offset;
void *cache;
} pcap_t;

pcap_t *pcap_create(char *path, uint32_t max_packet_size, uint32_t link_type);
int pcap_add_record(pcap_t *cap, uint8_t *capture_data, uint32_t length);
void pcap_dump(pcap_t *cap);

#ifdef __cplusplus
}
#endif

#endif /* _UTILS_PCAP_GEN_H_ */
5 changes: 5 additions & 0 deletions include/utils/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ int64_t usec_since(int64_t last);
*/
int64_t millis_now();

/**
* @brief Get time in seconds and micro_seconds
*/
void get_time(uint32_t *seconds, uint32_t *micro_seconds);

/**
* @brief Get time elapsed in milli seconds since `last`. Used along with
* millis_now().
Expand Down
116 changes: 116 additions & 0 deletions src/pcap_gen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include <string.h>
#include <stdlib.h>

#include <utils/pcap_gen.h>
#include <utils/utils.h>

/**
* See https://wiki.wireshark.org/Development/LibpcapFileFormat for packet
* strcture documentation.
*/

#define PCAP_MAGIC_NUM 0xa1b2c3d4
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
#define PCAP_CACHE_SIZE (1 << 12)

struct pcap_header {
uint32_t magic_number;
uint16_t version_major;
uint16_t version_minor;
uint32_t this_zone;
int32_t sigfigs;
uint32_t snap_len;
uint32_t link_type;
} __packed;

struct pcap_record_header {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
} __packed;

pcap_t *pcap_create(char *path, uint32_t max_packet_size, uint32_t link_type)
{
pcap_t *cap;
struct pcap_header header;
int ret = 0;

cap = malloc(sizeof(*cap));
if (cap == NULL)
return NULL;
cap->cache = calloc(1, PCAP_CACHE_SIZE);
if (cap->cache == NULL) {
free(cap);
return NULL;
}

header.magic_number = PCAP_MAGIC_NUM;
header.version_major = PCAP_VERSION_MAJOR;
header.version_minor = PCAP_VERSION_MINOR;
header.this_zone = 0;
header.sigfigs = 0;
header.snap_len = max_packet_size;
header.link_type = link_type;

cap->offset = 0;
cap->file = fopen(path, "wb");
if(cap->file == NULL) {
free(cap->cache);
free(cap);
return NULL;
}

ret = fwrite(&header , sizeof(header), 1, cap->file);
if (!ret) {
free(cap->cache);
free(cap);
return NULL;
}
return cap;
}

static int pcap_flush(pcap_t *cap)
{
int ret;

ret = fwrite(cap->cache, cap->offset, 1, cap->file);
if (!ret)
return -1;
fflush(cap->file);
cap->offset = 0;
return 0;
}

int pcap_add_record(pcap_t *cap, uint8_t *capture_data, uint32_t length)
{
struct pcap_record_header header;
uint32_t sec, usec;

if (sizeof(header) + length > PCAP_CACHE_SIZE) {
if (pcap_flush(cap))
return -1;
}

get_time(&sec, &usec);
header.ts_sec = sec;
header.ts_usec = usec;
header.orig_len = header.incl_len = length;

memcpy((char *)cap->cache + cap->offset, &header, sizeof(header));
cap->offset += sizeof(header);

memcpy((char *)cap->cache + cap->offset, capture_data, length);
cap->offset += length;

return 0;
}

void pcap_dump(pcap_t *cap)
{
pcap_flush(cap);
fclose(cap->file);
free(cap->cache);
free(cap);
}
9 changes: 9 additions & 0 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ int64_t usec_now()
return usec;
}

void get_time(uint32_t *seconds, uint32_t *micro_seconds)
{
struct timeval tv;

gettimeofday(&tv, NULL);
*seconds = tv.tv_sec;
*micro_seconds = tv.tv_usec;
}

int64_t usec_since(int64_t last)
{
return usec_now() - last;
Expand Down

0 comments on commit 409a258

Please sign in to comment.