reject invalid routes

This commit is contained in:
2026-06-05 15:13:39 +02:00
parent e76d58d106
commit 85e77c9dc1
5 changed files with 31 additions and 4 deletions

View File

@@ -11,11 +11,13 @@ uint8_t IPUtils_MaskToCIDRv4(uint32_t mask);
bool IPUtils_MatchPrefixv4(uint32_t ip, uint32_t prefix, uint8_t cidr); 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) // If buf is NULL, -> stdout; if NOT NULL, -> buf (must be at least 16 bytes)
void IPUtils_PrintIPv4(uint32_t ip, char* buf); void IPUtils_PrintIPv4(uint32_t ip, char* buf);
bool IPUtils_IsInSubnetv4(uint32_t ip, uint32_t subnet, uint32_t mask);
__uint128_t IPUtils_CIDRToMaskv6(uint8_t cidr); __uint128_t IPUtils_CIDRToMaskv6(uint8_t cidr);
uint8_t IPUtils_MaskToCIDRv6(__uint128_t mask); uint8_t IPUtils_MaskToCIDRv6(__uint128_t mask);
bool IPUtils_MatchPrefixv6(__uint128_t ip, __uint128_t prefix, uint8_t cidr); 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) // If buf is NULL, -> stdout; if NOT NULL, -> buf (must be at least 40 bytes)
void IPUtils_PrintIPv6(__uint128_t ip, char* buf); void IPUtils_PrintIPv6(__uint128_t ip, char* buf);
bool IPUtils_IsInSubnetv6(__uint128_t ip, __uint128_t subnet, __uint128_t mask);
#endif #endif

View File

@@ -31,6 +31,7 @@ static int free_value_cb(void *data, const unsigned char *key, uint32_t key_len,
} }
int RouteTable_Init(void) { int RouteTable_Init(void) {
// Create the ART trees for the IPv4 and the IPv6 route tables
if (art_tree_init(&route_table_v4) != 0) return -1; if (art_tree_init(&route_table_v4) != 0) return -1;
if (art_tree_init(&route_table_v6) != 0) { if (art_tree_init(&route_table_v6) != 0) {
art_tree_destroy(&route_table_v4); art_tree_destroy(&route_table_v4);
@@ -40,6 +41,7 @@ int RouteTable_Init(void) {
} }
void RouteTable_Cleanup(void) { void RouteTable_Cleanup(void) {
// Iterate clean the tables and destroy them
art_iter(&route_table_v4, free_value_cb, NULL); art_iter(&route_table_v4, free_value_cb, NULL);
art_tree_destroy(&route_table_v4); art_tree_destroy(&route_table_v4);
art_iter(&route_table_v6, free_value_cb, NULL); art_iter(&route_table_v6, free_value_cb, NULL);
@@ -47,9 +49,12 @@ void RouteTable_Cleanup(void) {
} }
int RouteTable_AddRoute_v4(uint32_t destination, uint32_t mask, uint32_t nextHop) { int RouteTable_AddRoute_v4(uint32_t destination, uint32_t mask, uint32_t nextHop) {
if (destination == 0 || nextHop == 0 || mask == 0) return -1; if (destination == 0 || nextHop == 0 || mask == 0) return -1; // Reject invalid routes (e.g., zero next hop or mask)
if (destination == 0x7F000001) return -1; // Common subnet checks
if (IPUtils_IsInSubnetv4(destination, 0x7F000000, 0xFF000000)) return -1; // Reject loopback
if (IPUtils_IsInSubnetv4(destination, 0xF0000000, 0xF0000000)) return -1; // Reject class E
// Note: Private IPs are allowed because those have legitimate use cases
uint8_t prefix_len = IPUtils_MaskToCIDRv4(mask); uint8_t prefix_len = IPUtils_MaskToCIDRv4(mask);
uint32_t network = destination & mask; uint32_t network = destination & mask;
@@ -70,7 +75,7 @@ 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) { int RouteTable_AddRoute_v6(__uint128_t destination, __uint128_t mask, __uint128_t nextHop) {
if (destination == 0 || nextHop == 0 || mask == 0) return -1; if (destination == 0 || nextHop == 0 || mask == 0) return -1;
if (destination == (__uint128_t)1) return -1; if (destination == (__uint128_t)1) return -1; // Reject loopback (::1)
uint8_t prefix_len = IPUtils_MaskToCIDRv6(mask); uint8_t prefix_len = IPUtils_MaskToCIDRv6(mask);
__uint128_t network = destination & mask; __uint128_t network = destination & mask;

View File

@@ -38,6 +38,10 @@ void IPUtils_PrintIPv4(uint32_t ip, char* buf) {
} }
} }
bool IPUtils_IsInSubnetv4(uint32_t ip, uint32_t subnet, uint32_t mask) {
return (ip & mask) == (subnet & mask);
}
__uint128_t IPUtils_CIDRToMaskv6(uint8_t cidr) { __uint128_t IPUtils_CIDRToMaskv6(uint8_t cidr) {
if (cidr > 128) { return 0x00; } if (cidr > 128) { return 0x00; }
__uint128_t mask = 0; __uint128_t mask = 0;
@@ -87,3 +91,7 @@ void IPUtils_PrintIPv6(__uint128_t ip, char* buf) {
(unsigned int)(ip & 0xFFFF)); (unsigned int)(ip & 0xFFFF));
} }
} }
bool IPUtils_IsInSubnetv6(__uint128_t ip, __uint128_t subnet, __uint128_t mask) {
return (ip & mask) == (subnet & mask);
}

View File

@@ -24,11 +24,16 @@ void Log_Cleanup() {
} }
static void log_emit(FILE* stream, const char* level, const char* fmt, va_list ap) { static void log_emit(FILE* stream, const char* level, const char* fmt, va_list ap) {
// Get UNIX millis
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
unsigned long timestamp = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
char msg[1024]; char msg[1024];
vsnprintf(msg, sizeof(msg), fmt, ap); vsnprintf(msg, sizeof(msg), fmt, ap);
char buf[1024]; char buf[1024];
int len = snprintf(buf, sizeof(buf), "[%s] %s\n", level, msg); int len = snprintf(buf, sizeof(buf), "[%lu] [%s] %s\n", timestamp, level, msg);
fputs(buf, stream); fputs(buf, stream);
if (log_socket_fd >= 0) if (log_socket_fd >= 0)
sendto(log_socket_fd, buf, len, 0, (struct sockaddr*)&log_dest, sizeof(log_dest)); sendto(log_socket_fd, buf, len, 0, (struct sockaddr*)&log_dest, sizeof(log_dest));

View File

@@ -64,6 +64,13 @@ int main(void) {
Log_Err("Failed to get next hop for destination %s", destStr); Log_Err("Failed to get next hop for destination %s", destStr);
} }
// Attempt to add class E route (should be rejected)
if (RouteTable_AddRoute_v4(0xF0000001, 0xF0000000, 0xC0A80101) < 0) {
Log_Info("Correctly rejected invalid class E route");
} else {
Log_Err("Incorrectly accepted invalid class E route");
}
// Some IPv6 routes // Some IPv6 routes
__uint128_t dest6 = (((__uint128_t)0x20010DB8 << 96) | ((__uint128_t)0x00000000 << 64) | ((__uint128_t)0x00000000 << 32) | (__uint128_t)0x00000001); // 2001:0db8::1 __uint128_t dest6 = (((__uint128_t)0x20010DB8 << 96) | ((__uint128_t)0x00000000 << 64) | ((__uint128_t)0x00000000 << 32) | (__uint128_t)0x00000001); // 2001:0db8::1
__uint128_t mask6 = IPUtils_CIDRToMaskv6(64); __uint128_t mask6 = IPUtils_CIDRToMaskv6(64);