From d7a570b857c46589243bdcdec6f52d564feafc77 Mon Sep 17 00:00:00 2001 From: Michal Zima Date: Sat, 24 Mar 2012 08:26:13 +0100 Subject: [PATCH] A lot of changes and fixes in NAT and radix tree Included MAC address into the NAT data structure New chunking algorithms Fixed memory leaks in RT code (and more) --- src/nat.c | 61 +++++++++++++++++++-------------- src/nat.h | 10 +++--- src/radixtree.c | 90 ++++++++++++++++++++++++++++++++++++------------- src/radixtree.h | 15 ++++++--- 4 files changed, 118 insertions(+), 58 deletions(-) diff --git a/src/nat.c b/src/nat.c index 9370602..91f8c47 100644 --- a/src/nat.c +++ b/src/nat.c @@ -20,7 +20,11 @@ #include /* malloc */ #include /* time */ +#include "ipv4.h" +#include "ipv6.h" +#include "nat.h" #include "radixtree.h" +#include "wrapper.h" struct s_radixtree_nat6 { struct s_ipv6_addr ipv6; @@ -39,7 +43,7 @@ struct s_radixtree_nat4 { radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp, *nat4_tcp, *nat4_udp, *nat4_icmp; -void nat_init() +void nat_init(void) { nat6_tcp = radixtree_create(); nat6_udp = radixtree_create(); @@ -50,33 +54,36 @@ void nat_init() nat4_icmp = radixtree_create(); } -void nat_quit() +void nat_quit(void) { - /* 128 + 16 + 32 + 16 = 198 / 6 = 33 */ - radixtree_destroy(&nat6_tcp, 33); - radixtree_destroy(&nat6_udp, 33); - radixtree_destroy(&nat6_icmp, 33); + /* 128 + 16 + 32 + 16 = 192 / 6 = 32 */ + radixtree_destroy(nat6_tcp, 32); + radixtree_destroy(nat6_udp, 32); + radixtree_destroy(nat6_icmp, 32); /* 32 + 16 + 16 + 8 = 72 / 6 = 12 */ - radixtree_destroy(&nat4_tcp, 12); - radixtree_destroy(&nat4_udp, 12); - radixtree_destroy(&nat4_icmp, 12); + radixtree_destroy(nat4_tcp, 12); + radixtree_destroy(nat4_udp, 12); + radixtree_destroy(nat4_icmp, 12); } struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4, struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst, unsigned short port_src, unsigned short port_dst) { - radixtree_t *result, *connection; + struct s_nat *result, *connection; + + struct s_radixtree_nat4 radixsearch4; + struct s_radixtree_nat6 radixsearch6; /* create structure to search in the tree */ - struct s_radixtree_nat6 radixsearch6; radixsearch6.ipv6 = ipv6_src; - radixsearch6.ipv4 = ipv6_to_ipv4(&ipv6_dst); + ipv6_to_ipv4(&ipv6_dst, &radixsearch6.ipv4); radixsearch6.port_src = port_src; radixsearch6.port_dst = port_dst; - if ((result = radixtree_lookup(nat_proto6, radixtree_outgoing_chunker, &radixsearch6)) == NULL) { + if ((result = (struct s_nat *) radixtree_lookup(nat_proto6, radixtree_ipv6_chunker, &radixsearch6)) == NULL) { + /* if no connection is found, let's create one */ if ((connection = (struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) { fprintf(stderr, "[Error] Lack of free memory\n"); return NULL; @@ -86,48 +93,50 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4, connection->ipv4 = radixsearch6.ipv4; connection->ipv6_port_src = port_src; connection->ipv4_port_dst = port_dst; - result->last_packet = time(NULL); + connection->last_packet = time(NULL); /* generate some outgoing port */ do { /* return port from range 1024 - 65535 */ connection->ipv4_port_src = (rand() % 64511) + 1024; - result = radixtree_lookup(nat_proto6, radixtree_outgoing_chunker, &radixsearch6); + result = radixtree_lookup(nat_proto6, radixtree_ipv6_chunker, &radixsearch6); } while (result != NULL); /* save this connection to the NAT table (to *both* of them) */ - struct s_radixtree_nat4 radixsearch4; radixsearch4.addr = radixsearch6.ipv4; radixsearch4.port_src = port_dst; radixsearch4.port_dst = connection->ipv4_port_src; radixsearch4.zeros = 0x0; - radixtree_insert(nat_proto6, radixtree_outgoing_chunker, &radixsearch6, connection); - radixtree_insert(nat_proto4, radixtree_incoming_chunker, &radixsearch4, connection); + radixtree_insert(nat_proto6, radixtree_ipv6_chunker, &radixsearch6, connection); + radixtree_insert(nat_proto4, radixtree_ipv4_chunker, &radixsearch4, connection); return connection; } else { + /* when connection is found, refresh it and return */ result->last_packet = time(NULL); return result; } } -struct s_nat *nat_in(radixtree_t *nat_proto, struct s_ipv4_addr ipv4_src, +struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src, unsigned short port_src, unsigned short port_dst) { - radixtree_t *result; + struct s_nat *result; /* create structure to search in the tree */ - struct s_radixtree_nat4 radixsearch; - radixsearch.addr = ipv4_src; - radixsearch.port_src = port_src; - radixsearch.port_dst = port_dst; - radixsearch.zeros = 0x0; + struct s_radixtree_nat4 radixsearch4; + radixsearch4.addr = ipv4_src; + radixsearch4.port_src = port_src; + radixsearch4.port_dst = port_dst; + radixsearch4.zeros = 0x0; - if ((result = radixtree_lookup(nat_proto, radixtree_outgoing_chunker, &radixsearch)) == NULL) { + if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, radixtree_ipv4_chunker, &radixsearch4)) == NULL) { + /* when connection is not found, drop the packet */ return NULL; } else { + /* when connection is found, refresh it and return */ result->last_packet = time(NULL); return result; } diff --git a/src/nat.h b/src/nat.h index 78c6fc0..9dc4b08 100644 --- a/src/nat.h +++ b/src/nat.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2010 Michal Zima + * Copyright (C) 2008-2011 Michal Zima * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -21,11 +21,13 @@ #include /* time_t */ +#include "ethernet.h" /* s_mac_addr */ #include "ipv4.h" /* s_ipv4_addr */ #include "ipv6.h" /* s_ipv6_addr */ #include "radixtree.h" /* radixtree_t */ struct s_nat { + struct s_mac_addr mac; struct s_ipv6_addr ipv6; struct s_ipv4_addr ipv4; unsigned short ipv6_port_src; @@ -37,13 +39,13 @@ struct s_nat { extern radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp, *nat4_tcp, *nat4_udp, *nat4_icmp; -void nat_init(); -void nat_quit(); +void nat_init(void); +void nat_quit(void); struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4, struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst, unsigned short port_src, unsigned short port_dst); -struct s_nat *nat_in(radixtree_t *nat_proto, struct s_ipv4_addr ipv4_src, +struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src, unsigned short port_src, unsigned short port_dst); #endif /* NAT_H */ diff --git a/src/radixtree.c b/src/radixtree.c index 9476a2f..96b617a 100644 --- a/src/radixtree.c +++ b/src/radixtree.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2010 Michal Zima + * Copyright (C) 2008-2012 Michal Zima * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -16,7 +16,13 @@ * along with this program. If not, see . */ -radixtree_t *radixtree_create() +#include /* fprintf */ +#include /* free, malloc */ +#include /* memcpy */ + +#include "radixtree.h" + +radixtree_t *radixtree_create(void) { radixtree_t *radixtree; @@ -61,7 +67,7 @@ void radixtree_insert(radixtree_t *root, for (i = 0; i < chunk_count; i++) { unsigned char id; - id = chunk[i]; + id = chunks[i]; if (i == chunk_count - 1) { tmp->array[id] = data; @@ -75,6 +81,8 @@ void radixtree_insert(radixtree_t *root, tmp = tmp->array[id]; tmp->count++; } + + free(chunks); } void radixtree_delete(radixtree_t *root, @@ -94,7 +102,7 @@ void radixtree_delete(radixtree_t *root, for (i = 0; i < chunk_count; i++) { unsigned char id; - id = chunk[i]; + id = chunks[i]; /* already deleted? may cause data inconsistency! */ if (tmp->array[id] == NULL) { @@ -130,68 +138,104 @@ void radixtree_delete(radixtree_t *root, tmp = next; tmp->count--; } + + free(chunks); } -radixtree_t *radixtree_lookup(radixtree_t *root, - unsigned char *(chunker)(void *data, unsigned char *count), - void *data) +void *radixtree_lookup(radixtree_t *root, + unsigned char *(chunker)(void *data, unsigned char *count), + void *data) { radixtree_t *tmp; - unsigned char i, chunk_count; + unsigned char i, chunk_count, id; unsigned char *chunks; chunks = chunker(data, &chunk_count); tmp = root; - for (i = 0; i < chunk_count; i++) { - unsigned char id; - - id = chunk[i]; + for (i = 0;; i++) { + id = chunks[i]; + /* leave the for cycle before tmp gets overwritten, + * if the final result was found */ if (i == chunk_count - 1) { + free(chunks); return tmp->array[id]; } + /* leave if there is no result */ if (tmp->array[id] == NULL) { + free(chunks); return NULL; } + /* go deeper */ tmp = tmp->array[id]; } + + /* we never get here ;c) */ } -unsigned char *radixtree_outgoing_chunker(void *data, unsigned char *count) +unsigned char *radixtree_ipv6_chunker(void *data, unsigned char *count) { short i; unsigned char counter; + unsigned char *chunks; + unsigned char *cdata = (unsigned char *) data; - counter = 198 / 6; + counter = 192 / 6; memcpy(count, &counter, sizeof(unsigned char)); - unsigned char chunks[counter]; + if ((chunks = (unsigned char *) malloc(counter * sizeof(unsigned char))) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return NULL; + } - /* 128 + 16 + 32 + 16 - 6 = 192 */ - for (i = 192, counter = 0; i >= 0; i -= 6, counter++) { - chunks[counter] = (*data >> i) & 63; /* 63 == 0011 1111 */ + /* + * 3 == 0000 0011 == 0x03 + * 15 == 0000 1111 == 0x0f + * 48 == 0011 0000 == 0x30 + * 60 == 0011 1100 == 0x3c + * 63 == 0011 1111 == 0x3f + * 192 == 1100 0000 == 0xc0 + * 240 == 1111 0000 == 0xf0 + * 252 == 1111 1100 == 0xfc + */ + for (i = 0, counter = 0; counter < *count; i++) { + chunks[counter++] = cdata[i] & 0x3f; + chunks[counter++] = ((cdata[i] & 0xc0) >> 6) | ((cdata[i + 1] & 0x0f) << 2); + i++; + chunks[counter++] = ((cdata[i] & 0xf0) >> 4) | ((cdata[i + 1] & 0x03) << 4); + i++; + chunks[counter++] = ((cdata[i] & 0xfc) >> 2); } return chunks; } -unsigned char *radixtree_incoming_chunker(void *data, unsigned char *count) +unsigned char *radixtree_ipv4_chunker(void *data, unsigned char *count) { short i; unsigned char counter; + unsigned char *chunks; + unsigned char *cdata = (unsigned char *) data; counter = 72 / 6; memcpy(count, &counter, sizeof(unsigned char)); - unsigned char chunks[counter]; + if ((chunks = (unsigned char *) malloc(counter * sizeof(unsigned char))) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return NULL; + } - /* 32 + 16 + 16 + 8 - 6 = 66 */ - for (i = 66, counter = 0; i >= 0; i -= 6, counter++) { - chunks[counter] = (*data >> i) & 63; /* 63 == 0011 1111 */ + for (i = 0, counter = 0; counter < *count; i++) { + chunks[counter++] = cdata[i] & 0x3f; + chunks[counter++] = ((cdata[i] & 0xc0) >> 6) | ((cdata[i + 1] & 0x0f) << 2); + i++; + chunks[counter++] = ((cdata[i] & 0xf0) >> 4) | ((cdata[i + 1] & 0x03) << 4); + i++; + chunks[counter++] = ((cdata[i] & 0xfc) >> 2); } return chunks; diff --git a/src/radixtree.h b/src/radixtree.h index 3911e33..03b16ae 100644 --- a/src/radixtree.h +++ b/src/radixtree.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2010 Michal Zima + * Copyright (C) 2008-2011 Michal Zima * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -16,6 +16,9 @@ * along with this program. If not, see . */ +#ifndef RADIXTREE_H +#define RADIXTREE_H + #define CHUNK_SIZE 6 #define ARRAY_SIZE 64 /* 2 ^ CHUNK_SIZE */ @@ -24,7 +27,7 @@ typedef struct radixtree { unsigned int count; } radixtree_t; -radixtree_t *radixtree_create(); +radixtree_t *radixtree_create(void); void radixtree_destroy(radixtree_t *t, unsigned char depth); void radixtree_insert(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char *count), @@ -32,8 +35,10 @@ void radixtree_insert(radixtree_t *root, void radixtree_delete(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char *count), void *data); -radixtree_t *radixtree_lookup(radixtree_t *root, +void *radixtree_lookup(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char *count), void *data); -unsigned char *radixtree_outgoing_chunker(void *data, unsigned char *count); -unsigned char *radixtree_incoming_chunker(void *data, unsigned char *count); +unsigned char *radixtree_ipv6_chunker(void *data, unsigned char *count); +unsigned char *radixtree_ipv4_chunker(void *data, unsigned char *count); + +#endif /* RADIXTREE_H */