This commit is contained in:
2026-06-05 14:03:02 +02:00
commit e7bf726adb
17 changed files with 2714 additions and 0 deletions

63
include/dynarr.h Normal file
View File

@@ -0,0 +1,63 @@
#ifndef DYNARR_H
#define DYNARR_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DYNARR_MAX_CAPACITY ((size_t)0x7FFFFFFF)
typedef struct {
size_t size;
size_t elemSize;
size_t capacity;
void* data;
} DynArr;
// Do not use; Use DYNARR_CREATE macro instead.
DynArr* DynArr_create(size_t elemSize, size_t capacity);
// Reserve n blocks in arary; New size will be n, NOT size + n; Reserving less memory that current will fail, use prune instead.
void DynArr_reserve(DynArr* p, size_t n);
// Push data into a new block at the end of the array
void* DynArr_push_back(DynArr* p, void* value);
// Remove the last block in the array.
void DynArr_pop_back(DynArr* p);
// Remove first block from array.
void DynArr_pop_front(DynArr* p);
// Remove index from array. This moves all blocks after the index block.
void DynArr_remove(DynArr* p, size_t index);
// Erase the array. This will not free unused blocks.
void DynArr_erase(DynArr* p);
// Prune and free unused blocks. If pruning to zero, ensure to reserve after.
void DynArr_prune(DynArr* p);
// Get a pointer to a block by index
void* DynArr_at(DynArr* p, size_t index);
// Get the index by block pointer
size_t DynArr_at_ptr(DynArr* p, void* ptr);
// Get size
size_t DynArr_size(DynArr* p);
// Get element size
size_t DynArr_elemSize(DynArr* p);
// Get capacity
size_t DynArr_capacity(DynArr* p);
void DynArr_destroy(DynArr* p);
// Note: Make sure to not overread or overwrite
void* DynArr_c_arr(DynArr* p);
#define DYNARR_CREATE(T, initialCapacity) DynArr_create(sizeof(T), initialCapacity)
#endif

20
include/dynset.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef DYNSET_H
#define DYNSET_H
#include <dynarr.h>
// Dynamic Set structure - basically DynArr with uniqueness enforced
typedef struct {
DynArr* arr;
} DynSet;
// Function prototypes
DynSet* DynSet_Create(size_t elemSize);
void DynSet_Destroy(DynSet* set);
int DynSet_Insert(DynSet* set, const void* element);
int DynSet_Contains(DynSet* set, const void* element);
size_t DynSet_Size(DynSet* set);
void* DynSet_Get(DynSet* set, size_t index);
void DynSet_Remove(DynSet* set, const void* element);
#endif

View File

@@ -0,0 +1,42 @@
#ifndef INTERFACE_H
#define INTERFACE_H
#include <arpa/inet.h>
#include <stddef.h>
#include <stdint.h>
typedef struct interface_v4 interface_v4_t;
typedef struct interface_v6 interface_v6_t;
typedef struct interface_packet {
sa_family_t family;
const uint8_t* data;
size_t length;
struct sockaddr_storage source;
struct sockaddr_storage destination;
} interface_packet_t;
typedef void (*interface_packet_callback_t)(const interface_packet_t* packet, void* userData);
int Interface_Init(void);
void Interface_Cleanup(void);
interface_v4_t* Interface_Create_v4(const char* localAddress, interface_packet_callback_t callback, void* userData);
interface_v6_t* Interface_Create_v6(const char* localAddress, interface_packet_callback_t callback, void* userData);
int Interface_Listen_v4(interface_v4_t* iface);
int Interface_Listen_v6(interface_v6_t* iface);
void Interface_Stop_v4(interface_v4_t* iface);
void Interface_Stop_v6(interface_v6_t* iface);
void Interface_Destroy_v4(interface_v4_t* iface);
void Interface_Destroy_v6(interface_v6_t* iface);
int Interface_SendRaw_v4(interface_v4_t* iface, const struct in_addr* destination, const void* packet, size_t packetLength);
int Interface_SendRaw_v6(interface_v6_t* iface, const struct in6_addr* destination, const void* packet, size_t packetLength);
int Interface_SendFrame_v4(interface_v4_t* iface, const void* frame, size_t frameLength);
int Interface_SendFrame_v6(interface_v6_t* iface, const void* frame, size_t frameLength);
#endif

View File

@@ -0,0 +1,30 @@
#ifndef ROUTETABLE_H
#define ROUTETABLE_H
#include <stdint.h>
#include <libart/art.h>
typedef struct {
uint32_t destination;
uint32_t mask;
uint32_t nextHop;
} route_table_v4_entry_t;
typedef struct {
__uint128_t destination;
__uint128_t mask;
__uint128_t nextHop;
} route_table_v6_entry_t;
// General rule: 0 = success, -1 = failure (Note: per-function return values may vary, will be documented in the .c file)
int RouteTable_Init(void);
void RouteTable_Cleanup(void);
int RouteTable_AddRoute_v4(uint32_t destination, uint32_t mask, uint32_t nextHop);
int RouteTable_AddRoute_v6(__uint128_t destination, __uint128_t mask, __uint128_t nextHop);
// GetNextHop performs longest prefix match; writes best matching next hop into *nextHop
int RouteTable_GetNextHop_v4(uint32_t destination, uint32_t* nextHop);
int RouteTable_GetNextHop_v6(__uint128_t destination, __uint128_t* nextHop);
#endif

21
include/iputils.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef IPUTILS_H
#define IPUTILS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
uint32_t IPUtils_CIDRToMaskv4(uint8_t cidr);
uint8_t IPUtils_MaskToCIDRv4(uint32_t mask);
bool IPUtils_MatchPrefixv4(uint32_t ip, uint32_t prefix, uint8_t cidr);
// If buf is NULL, -> stdout; if NOT NULL, -> buf (must be at least 16 bytes)
void IPUtils_PrintIPv4(uint32_t ip, char* buf);
__uint128_t IPUtils_CIDRToMaskv6(uint8_t cidr);
uint8_t IPUtils_MaskToCIDRv6(__uint128_t mask);
bool IPUtils_MatchPrefixv6(__uint128_t ip, __uint128_t prefix, uint8_t cidr);
// If buf is NULL, -> stdout; if NOT NULL, -> buf (must be at least 40 bytes)
void IPUtils_PrintIPv6(__uint128_t ip, char* buf);
#endif

215
include/libart/art.h Normal file
View File

@@ -0,0 +1,215 @@
#include <stdint.h>
#ifndef ART_H
#define ART_H
#ifdef __cplusplus
extern "C" {
#endif
#define NODE4 1
#define NODE16 2
#define NODE48 3
#define NODE256 4
#define MAX_PREFIX_LEN 10
#if defined(__GNUC__) && !defined(__clang__)
# if __STDC_VERSION__ >= 199901L && 402 == (__GNUC__ * 100 + __GNUC_MINOR__)
/*
* GCC 4.2.2's C99 inline keyword support is pretty broken; avoid. Introduced in
* GCC 4.2.something, fixed in 4.3.0. So checking for specific major.minor of
* 4.2 is fine.
*/
# define BROKEN_GCC_C99_INLINE
# endif
#endif
typedef int(*art_callback)(void *data, const unsigned char *key, uint32_t key_len, void *value);
/**
* This struct is included as part
* of all the various node sizes
*/
typedef struct {
uint32_t partial_len;
uint8_t type;
uint8_t num_children;
unsigned char partial[MAX_PREFIX_LEN];
} art_node;
/**
* Small node with only 4 children
*/
typedef struct {
art_node n;
unsigned char keys[4];
art_node *children[4];
} art_node4;
/**
* Node with 16 children
*/
typedef struct {
art_node n;
unsigned char keys[16];
art_node *children[16];
} art_node16;
/**
* Node with 48 children, but
* a full 256 byte field.
*/
typedef struct {
art_node n;
unsigned char keys[256];
art_node *children[48];
} art_node48;
/**
* Full node with 256 children
*/
typedef struct {
art_node n;
art_node *children[256];
} art_node256;
/**
* Represents a leaf. These are
* of arbitrary size, as they include the key.
*/
typedef struct {
void *value;
uint32_t key_len;
unsigned char key[];
} art_leaf;
/**
* Main struct, points to root.
*/
typedef struct {
art_node *root;
uint64_t size;
} art_tree;
/**
* Initializes an ART tree
* @return 0 on success.
*/
int art_tree_init(art_tree *t);
/**
* DEPRECATED
* Initializes an ART tree
* @return 0 on success.
*/
#define init_art_tree(...) art_tree_init(__VA_ARGS__)
/**
* Destroys an ART tree
* @return 0 on success.
*/
int art_tree_destroy(art_tree *t);
/**
* DEPRECATED
* Initializes an ART tree
* @return 0 on success.
*/
#define destroy_art_tree(...) art_tree_destroy(__VA_ARGS__)
/**
* Returns the size of the ART tree.
*/
#ifdef BROKEN_GCC_C99_INLINE
# define art_size(t) ((t)->size)
#else
inline uint64_t art_size(art_tree *t) {
return t->size;
}
#endif
/**
* inserts a new value into the art tree
* @arg t the tree
* @arg key the key
* @arg key_len the length of the key
* @arg value opaque value.
* @return null if the item was newly inserted, otherwise
* the old value pointer is returned.
*/
void* art_insert(art_tree *t, const unsigned char *key, int key_len, void *value);
/**
* inserts a new value into the art tree (not replacing)
* @arg t the tree
* @arg key the key
* @arg key_len the length of the key
* @arg value opaque value.
* @return null if the item was newly inserted, otherwise
* the old value pointer is returned.
*/
void* art_insert_no_replace(art_tree *t, const unsigned char *key, int key_len, void *value);
/**
* Deletes a value from the ART tree
* @arg t The tree
* @arg key The key
* @arg key_len The length of the key
* @return NULL if the item was not found, otherwise
* the value pointer is returned.
*/
void* art_delete(art_tree *t, const unsigned char *key, int key_len);
/**
* Searches for a value in the ART tree
* @arg t The tree
* @arg key The key
* @arg key_len The length of the key
* @return NULL if the item was not found, otherwise
* the value pointer is returned.
*/
void* art_search(const art_tree *t, const unsigned char *key, int key_len);
/**
* Returns the minimum valued leaf
* @return The minimum leaf or NULL
*/
art_leaf* art_minimum(art_tree *t);
/**
* Returns the maximum valued leaf
* @return The maximum leaf or NULL
*/
art_leaf* art_maximum(art_tree *t);
/**
* Iterates through the entries pairs in the map,
* invoking a callback for each. The call back gets a
* key, value for each and returns an integer stop value.
* If the callback returns non-zero, then the iteration stops.
* @arg t The tree to iterate over
* @arg cb The callback function to invoke
* @arg data Opaque handle passed to the callback
* @return 0 on success, or the return of the callback.
*/
int art_iter(art_tree *t, art_callback cb, void *data);
/**
* Iterates through the entries pairs in the map,
* invoking a callback for each that matches a given prefix.
* The call back gets a key, value for each and returns an integer stop value.
* If the callback returns non-zero, then the iteration stops.
* @arg t The tree to iterate over
* @arg prefix The prefix of keys to read
* @arg prefix_len The length of the prefix
* @arg cb The callback function to invoke
* @arg data Opaque handle passed to the callback
* @return 0 on success, or the return of the callback.
*/
int art_iter_prefix(art_tree *t, const unsigned char *prefix, int prefix_len, art_callback cb, void *data);
#ifdef __cplusplus
}
#endif
#endif