From 409a258dbf7610c9f6989187608957fcf724e887 Mon Sep 17 00:00:00 2001 From: Siddharth Chandrasekaran Date: Thu, 15 Feb 2024 21:30:39 +0100 Subject: [PATCH] pcap: Add initial pcap builder 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 --- include/utils/pcap_gen.h | 31 +++++++++++ include/utils/utils.h | 5 ++ src/pcap_gen.c | 116 +++++++++++++++++++++++++++++++++++++++ src/utils.c | 9 +++ 4 files changed, 161 insertions(+) create mode 100644 include/utils/pcap_gen.h create mode 100644 src/pcap_gen.c diff --git a/include/utils/pcap_gen.h b/include/utils/pcap_gen.h new file mode 100644 index 0000000..7ae481d --- /dev/null +++ b/include/utils/pcap_gen.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Siddharth Chandrasekaran + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _UTILS_PCAP_GEN_H_ +#define _UTILS_PCAP_GEN_H_ + +#include +#include + +#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_ */ diff --git a/include/utils/utils.h b/include/utils/utils.h index f057db6..a97e525 100644 --- a/include/utils/utils.h +++ b/include/utils/utils.h @@ -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(). diff --git a/src/pcap_gen.c b/src/pcap_gen.c new file mode 100644 index 0000000..bd0abaa --- /dev/null +++ b/src/pcap_gen.c @@ -0,0 +1,116 @@ +#include +#include + +#include +#include + +/** + * 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); +} diff --git a/src/utils.c b/src/utils.c index cf586c4..c8f3a49 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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;