Reworked pcap format to make it more cross platform and make it more ideomatic C++

This commit is contained in:
Pavel Odintsov 2023-04-02 19:30:16 +01:00
parent a34c9b6c9f
commit e376abaeed
4 changed files with 162 additions and 57 deletions

View File

@ -1,5 +1,5 @@
#include "fastnetmon_pcap_format.hpp"
#include <errno.h>
#include <iostream>
#include <string.h>
int pcap_reader(const char* pcap_file_path, pcap_packet_parser_callback pcap_parse_packet_function_ptr) {
@ -10,10 +10,10 @@ int pcap_reader(const char* pcap_file_path, pcap_packet_parser_callback pcap_par
return -1;
}
struct fastnetmon_pcap_file_header pcap_header;
ssize_t file_header_readed_bytes = read(filedesc, &pcap_header, sizeof(struct fastnetmon_pcap_file_header));
fastnetmon_pcap_file_header_t pcap_header{};
ssize_t file_header_readed_bytes = read(filedesc, &pcap_header, sizeof(fastnetmon_pcap_file_header_t));
if (file_header_readed_bytes != sizeof(struct fastnetmon_pcap_file_header)) {
if (file_header_readed_bytes != sizeof(fastnetmon_pcap_file_header_t)) {
printf("Can't read pcap file header");
}
@ -31,16 +31,17 @@ int pcap_reader(const char* pcap_file_path, pcap_packet_parser_callback pcap_par
unsigned int read_packets = 0;
while (1) {
// printf("Start packet %d processing\n", read_packets);
struct fastnetmon_pcap_pkthdr pcap_packet_header;
ssize_t packet_header_readed_bytes = read(filedesc, &pcap_packet_header, sizeof(struct fastnetmon_pcap_pkthdr));
fastnetmon_pcap_pkthdr_t pcap_packet_header;
ssize_t packet_header_readed_bytes = read(filedesc, &pcap_packet_header, sizeof(fastnetmon_pcap_pkthdr_t));
if (packet_header_readed_bytes != sizeof(struct fastnetmon_pcap_pkthdr)) {
if (packet_header_readed_bytes != sizeof(fastnetmon_pcap_pkthdr_t)) {
// We haven't any packets
break;
}
if (pcap_packet_header.incl_len > pcap_header.snaplen) {
printf("Please enlarge packet buffer! We got packet with size: %d but our buffer is %d "
printf("Please enlarge packet buffer! We got packet with size: %d but "
"our buffer is %d "
"bytes\n",
pcap_packet_header.incl_len, pcap_header.snaplen);
return -4;
@ -65,13 +66,15 @@ int pcap_reader(const char* pcap_file_path, pcap_packet_parser_callback pcap_par
return 0;
}
bool fill_pcap_header(struct fastnetmon_pcap_file_header* pcap_header, bpf_u_int32 snap_length) {
// Move this code to constructor
bool fill_pcap_header(fastnetmon_pcap_file_header_t* pcap_header, uint32_t snap_length) {
pcap_header->magic = 0xa1b2c3d4;
pcap_header->version_major = 2;
pcap_header->version_minor = 4;
pcap_header->thiszone = 0;
pcap_header->sigfigs = 0;
// TODO: fix this!!!
// Maximum really captured (not original packet) length for this file
pcap_header->snaplen = snap_length;
// http://www.tcpdump.org/linktypes.html
// DLT_EN10MB = 1

View File

@ -1,68 +1,170 @@
#ifndef FASTNETMON_PCAP_FORMAT_H
#define FASTNETMON_PCAP_FORMAT_H
#pragma once
#include <stdint.h>
#include <cstdint>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <log4cpp/Appender.hh>
#include <log4cpp/BasicLayout.hh>
#include <log4cpp/Category.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/Layout.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/Priority.hh>
#include "fastnetmon_simple_packet.hpp"
/*
pcap dump format:
global header: struct pcap_file_header
packet header: struct fastnetmon_pcap_pkthdr
global header: pcap_file_header
packet header: fastnetmon_pcap_pkthdr_t
*/
/*
* Compatibility for systems that have a bpf.h that
* predates the bpf typedefs for 64-bit support.
*/
#if BPF_RELEASE - 0 < 199406
typedef int bpf_int32;
typedef u_int bpf_u_int32;
#endif
// We use copy and paste from pcap.h here because we do not want to link with pcap here
struct fastnetmon_pcap_file_header {
bpf_u_int32 magic;
u_short version_major;
u_short version_minor;
bpf_int32 thiszone; /* gmt to local correction */
bpf_u_int32 sigfigs; /* accuracy of timestamps */
bpf_u_int32 snaplen; /* max length saved portion of each pkt */
bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
// We use copy and paste from pcap.h here because we do not want to link with
// pcap here
class __attribute__((__packed__)) fastnetmon_pcap_file_header_t {
public:
uint32_t magic = 0;
uint16_t version_major = 0;
uint16_t version_minor = 0;
int32_t thiszone = 0; /* gmt to local correction */
uint32_t sigfigs = 0; /* accuracy of timestamps */
uint32_t snaplen = 0; /* max length saved portion of each pkt */
uint32_t linktype = 0; /* data link type (LINKTYPE_*) */
};
/*
TODO: move to this code, get rid any bpf* custom types
struct fastnetmon_pcap_file_header {
uint32_t magic;
uint16_t version_major;
uint16_t version_minor;
int32_t thiszone;
uint32_t sigfigs;
uint32_t snaplen;
uint32_t linktype;
};
*/
static_assert(sizeof(fastnetmon_pcap_file_header_t) == 24, "Bad size for fastnetmon_pcap_file_header_t");
// Link types for PCAP which we use in FastNetMon
#define FASTNETMON_PCAP_LINKTYPE_ETHERNET 1
#define FASTNETMON_PCAP_LINKTYPE_LINUX_SLL 113
// We can't use pcap_pkthdr from upstream because it uses 16 bytes timeval instead of 8 byte and
// We can't use pcap_pkthdr from upstream because it uses 16 bytes timeval
// instead of 8 byte and
// broke everything
struct fastnetmon_pcap_pkthdr {
uint32_t ts_sec; /* timestamp seconds */
uint32_t ts_usec; /* timestamp microseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
class __attribute__((__packed__)) fastnetmon_pcap_pkthdr_t {
public:
uint32_t ts_sec = 0; /* timestamp seconds */
uint32_t ts_usec = 0; /* timestamp microseconds */
uint32_t incl_len = 0; /* number of octets of packet saved in file */
uint32_t orig_len = 0; /* actual length of packet */
};
static_assert(sizeof(fastnetmon_pcap_pkthdr_t) == 16, "Bad size for fastnetmon_pcap_pkthdr_t");
// This class consist of pcap header and payload in same place
class pcap_packet_information_t {
public:
uint32_t ts_sec = 0; /* timestamp seconds */
uint32_t ts_usec = 0; /* timestamp microseconds */
uint32_t incl_len = 0;
uint32_t orig_len = 0;
char* data_pointer = nullptr;
};
typedef void (*pcap_packet_parser_callback)(char* buffer, uint32_t len, uint32_t snaplen);
int pcap_reader(const char* pcap_file_path, pcap_packet_parser_callback pcap_parse_packet_function_ptr);
bool fill_pcap_header(struct fastnetmon_pcap_file_header* pcap_header, bpf_u_int32 snap_length);
bool fill_pcap_header(fastnetmon_pcap_file_header_t* pcap_header, uint32_t snap_length);
#endif
// Class for very convenient pcap file reading
class pcap_roller_t {
public:
pcap_roller_t(const std::string& pcap_file_path) {
this->pcap_file_path = pcap_file_path;
}
~pcap_roller_t() {
if (filedesc > 0) {
close(filedesc);
}
if (packet_buffer) {
free(packet_buffer);
packet_buffer = nullptr;
}
}
bool open() {
extern log4cpp::Category& logger;
filedesc = ::open(pcap_file_path.c_str(), O_RDONLY);
if (filedesc <= 0) {
logger << log4cpp::Priority::ERROR << "Can't open dump file, error: " << strerror(errno);
return false;
}
ssize_t file_header_readed_bytes = read(filedesc, &pcap_header, sizeof(fastnetmon_pcap_file_header_t));
if (file_header_readed_bytes != sizeof(fastnetmon_pcap_file_header_t)) {
logger << log4cpp::Priority::ERROR << "Can't read pcap file header";
return false;
}
// http://www.tcpdump.org/manpages/pcap-savefile.5.html
if (!(pcap_header.magic == 0xa1b2c3d4 or pcap_header.magic == 0xd4c3b2a1)) {
logger << log4cpp::Priority::ERROR << "Magic in file header broken";
return false;
}
// Allocate read buffer
packet_buffer = (char*)malloc(pcap_header.snaplen);
return true;
}
// Read on more packet from stream and returns false if we run out of packets
bool read_next(pcap_packet_information_t& pcap_packet_information) {
extern log4cpp::Category& logger;
fastnetmon_pcap_pkthdr_t pcap_packet_header;
ssize_t packet_header_readed_bytes = read(filedesc, &pcap_packet_header, sizeof(fastnetmon_pcap_pkthdr_t));
if (packet_header_readed_bytes != sizeof(fastnetmon_pcap_pkthdr_t)) {
// We have no more packets to read
return false;
}
if (pcap_packet_header.incl_len > pcap_header.snaplen) {
logger << log4cpp::Priority::ERROR << "Captured packet size for this dump exceed limit for pcap file";
return false;
}
// Read included part of raw packet from file
ssize_t packet_payload_readed_bytes = read(filedesc, packet_buffer, pcap_packet_header.incl_len);
if (pcap_packet_header.incl_len != packet_payload_readed_bytes) {
logger << log4cpp::Priority::ERROR << "We successfully read packet header but can't read packet payload";
return false;
}
pcap_packet_information.incl_len = pcap_packet_header.incl_len;
pcap_packet_information.orig_len = pcap_packet_header.orig_len;
pcap_packet_information.ts_sec = pcap_packet_header.ts_sec;
pcap_packet_information.ts_usec = pcap_packet_header.ts_usec;
pcap_packet_information.data_pointer = packet_buffer;
return true;
}
public:
fastnetmon_pcap_file_header_t pcap_header{};
private:
std::string pcap_file_path = "";
int filedesc = 0;
char* packet_buffer = nullptr;
};

View File

@ -37,7 +37,7 @@ class fixed_size_packet_storage_t {
}
// Some useful information about this packet
fastnetmon_pcap_pkthdr packet_metadata;
fastnetmon_pcap_pkthdr_t packet_metadata;
// Packet itself. Let's zeroify packet payload
uint8_t packet_payload[2048] = {};

View File

@ -22,7 +22,7 @@ class packet_storage_t {
bool allocate_buffer(unsigned int buffer_size_in_packets) {
unsigned int memory_size_in_bytes =
buffer_size_in_packets * (max_captured_packet_size + sizeof(fastnetmon_pcap_pkthdr)) + sizeof(fastnetmon_pcap_file_header);
buffer_size_in_packets * (max_captured_packet_size + sizeof(fastnetmon_pcap_pkthdr_t)) + sizeof(fastnetmon_pcap_file_header_t);
// std::cout << "We will allocate " << memory_size_in_bytes << std::endl;
@ -62,7 +62,7 @@ class packet_storage_t {
gettimeofday(&current_time, NULL);
}
fastnetmon_pcap_pkthdr pcap_packet_header;
fastnetmon_pcap_pkthdr_t pcap_packet_header;
pcap_packet_header.ts_sec = current_time.tv_sec;
pcap_packet_header.ts_usec = current_time.tv_usec;
@ -93,7 +93,7 @@ class packet_storage_t {
}
bool write_header() {
struct fastnetmon_pcap_file_header pcap_header;
fastnetmon_pcap_file_header_t pcap_header;
fill_pcap_header(&pcap_header, max_captured_packet_size);