mirror of
https://code.semirocket.science/wrapsix
synced 2025-12-15 02:05:13 +02:00
Expiration of connections and fragments
This commit is contained in:
309
src/nat.c
309
src/nat.c
@@ -48,7 +48,16 @@ struct s_radixtree_fragments4 {
|
||||
|
||||
radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
|
||||
*nat4_tcp, *nat4_udp, *nat4_icmp,
|
||||
*nat4_tcp_fragments, *nat4_saved_fragments;
|
||||
*nat4_tcp_fragments;
|
||||
|
||||
/* Linked lists for handling timeouts of connections */
|
||||
linkedlist_t *timeout_icmp, *timeout_udp,
|
||||
*timeout_tcp_est, *timeout_tcp_trans,
|
||||
*timeout_tcp_fragments;
|
||||
|
||||
/* Declarations */
|
||||
void nat_delete_connection(radixtree_t *nat_proto4, radixtree_t *nat_proto6,
|
||||
struct s_nat *connection);
|
||||
|
||||
/**
|
||||
* Initialization of NAT tables.
|
||||
@@ -64,7 +73,12 @@ void nat_init(void)
|
||||
nat4_icmp = radixtree_create();
|
||||
|
||||
nat4_tcp_fragments = radixtree_create();
|
||||
nat4_saved_fragments = radixtree_create();
|
||||
|
||||
timeout_icmp = linkedlist_create();
|
||||
timeout_udp = linkedlist_create();
|
||||
timeout_tcp_est = linkedlist_create();
|
||||
timeout_tcp_trans = linkedlist_create();
|
||||
timeout_tcp_fragments = linkedlist_create();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,27 +98,34 @@ void nat_quit(void)
|
||||
|
||||
/* 32 + 16 = 48 / 6 = 8 */
|
||||
radixtree_destroy(nat4_tcp_fragments, 8);
|
||||
radixtree_destroy(nat4_saved_fragments, 8);
|
||||
|
||||
linkedlist_destroy(timeout_icmp);
|
||||
linkedlist_destroy(timeout_udp);
|
||||
linkedlist_destroy(timeout_tcp_est);
|
||||
linkedlist_destroy(timeout_tcp_trans);
|
||||
linkedlist_destroy(timeout_tcp_fragments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup or create NAT connection for outgoing IPv6 packet.
|
||||
*
|
||||
* @param nat_proto6 IPv6 NAT table
|
||||
* @param nat_proto4 IPv4 NAT table
|
||||
* @param eth_src Source MAC address
|
||||
* @param ipv6_src Source IPv6 address
|
||||
* @param ipv6_dst Destination IPv6 address
|
||||
* @param port_src Source port
|
||||
* @param port_dst Destination port
|
||||
* @param nat_proto6 IPv6 NAT table
|
||||
* @param nat_proto4 IPv4 NAT table
|
||||
* @param eth_src Source MAC address
|
||||
* @param ipv6_src Source IPv6 address
|
||||
* @param ipv6_dst Destination IPv6 address
|
||||
* @param port_src Source port
|
||||
* @param port_dst Destination port
|
||||
* @param create Whether or not to create new NAT entry
|
||||
*
|
||||
* @return NULL when it wasn't possible to create connection
|
||||
* @return pointer to connection structure otherwise
|
||||
* @return NULL when it wasn't possible to create connection
|
||||
* @return pointer to connection structure otherwise
|
||||
*/
|
||||
struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||
struct s_mac_addr eth_src,
|
||||
struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst,
|
||||
unsigned short port_src, unsigned short port_dst)
|
||||
unsigned short port_src, unsigned short port_dst,
|
||||
unsigned char create)
|
||||
{
|
||||
struct s_nat *result, *connection;
|
||||
|
||||
@@ -119,42 +140,55 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||
|
||||
if ((result = (struct s_nat *) radixtree_lookup(nat_proto6,
|
||||
radixtree_chunker, &radixsearch6, sizeof(radixsearch6))) == NULL) {
|
||||
/* if no connection is found, let's create one */
|
||||
if ((connection =
|
||||
(struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) {
|
||||
log_error("Lack of free memory");
|
||||
if (create > 0) {
|
||||
/* if no connection is found, let's create one */
|
||||
if ((connection =
|
||||
(struct s_nat *) malloc(sizeof(struct s_nat))) ==
|
||||
NULL) {
|
||||
log_error("Lack of free memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connection->mac = eth_src;
|
||||
connection->ipv6 = ipv6_src;
|
||||
connection->ipv4 = radixsearch6.ipv4;
|
||||
connection->ipv6_port_src = port_src;
|
||||
connection->ipv4_port_dst = port_dst;
|
||||
connection->state = 1;
|
||||
connection->llnode = NULL;
|
||||
|
||||
radixsearch4.addr = radixsearch6.ipv4;
|
||||
radixsearch4.port_src = port_dst;
|
||||
radixsearch4.zeros = 0x0;
|
||||
|
||||
/* generate some outgoing port */
|
||||
do {
|
||||
/* returns port from range 1024 - 65535 */
|
||||
radixsearch4.port_dst = (rand() % 64511) + 1024;
|
||||
|
||||
result = radixtree_lookup(nat_proto4,
|
||||
radixtree_chunker,
|
||||
&radixsearch4,
|
||||
sizeof(radixsearch4));
|
||||
} while (result != NULL);
|
||||
|
||||
connection->ipv4_port_src = radixsearch4.port_dst;
|
||||
|
||||
/* save this connection to the NAT table (to *both* of
|
||||
* them) */
|
||||
radixtree_insert(nat_proto6, radixtree_chunker,
|
||||
&radixsearch6, sizeof(radixsearch6),
|
||||
connection);
|
||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4, sizeof(radixsearch4),
|
||||
connection);
|
||||
|
||||
return connection;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connection->mac = eth_src;
|
||||
connection->ipv6 = ipv6_src;
|
||||
connection->ipv4 = radixsearch6.ipv4;
|
||||
connection->ipv6_port_src = port_src;
|
||||
connection->ipv4_port_dst = port_dst;
|
||||
connection->last_packet = time(NULL);
|
||||
|
||||
radixsearch4.addr = radixsearch6.ipv4;
|
||||
radixsearch4.port_src = port_dst;
|
||||
radixsearch4.zeros = 0x0;
|
||||
|
||||
/* generate some outgoing port */
|
||||
do {
|
||||
/* returns port from range 1024 - 65535 */
|
||||
radixsearch4.port_dst = (rand() % 64511) + 1024;
|
||||
|
||||
result = radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4));
|
||||
} while (result != NULL);
|
||||
|
||||
connection->ipv4_port_src = radixsearch4.port_dst;
|
||||
|
||||
/* save this connection to the NAT table (to *both* of them) */
|
||||
radixtree_insert(nat_proto6, radixtree_chunker, &radixsearch6, sizeof(radixsearch6), connection);
|
||||
radixtree_insert(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4), connection);
|
||||
|
||||
return connection;
|
||||
} else {
|
||||
/* when connection is found, refresh it and return */
|
||||
result->last_packet = time(NULL);
|
||||
/* when connection is found, return it */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -162,13 +196,13 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||
/**
|
||||
* Lookup NAT connection for incoming IPv4 packet.
|
||||
*
|
||||
* @param nat_proto4 NAT table
|
||||
* @param ipv4_src Source IPv4 address
|
||||
* @param port_src Source port
|
||||
* @param port_dst Destination port
|
||||
* @param nat_proto4 NAT table
|
||||
* @param ipv4_src Source IPv4 address
|
||||
* @param port_src Source port
|
||||
* @param port_dst Destination port
|
||||
*
|
||||
* @return NULL when no connection was found
|
||||
* @return pointer to connection structure otherwise
|
||||
* @return NULL when no connection was found
|
||||
* @return pointer to connection structure otherwise
|
||||
*/
|
||||
struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||
unsigned short port_src, unsigned short port_dst)
|
||||
@@ -182,30 +216,32 @@ struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||
radixsearch4.port_dst = port_dst;
|
||||
radixsearch4.zeros = 0x0;
|
||||
|
||||
if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4))) == NULL) {
|
||||
if ((result = (struct s_nat *) radixtree_lookup(nat_proto4,
|
||||
radixtree_chunker, &radixsearch4, sizeof(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);
|
||||
/* when connection is found, return it */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save and retrieve data (e.g. NATted connections) via fragment identification.
|
||||
* Retrieve or create data structure via fragment identification.
|
||||
*
|
||||
* @param nat_proto4 Radix tree of fragments
|
||||
* @param ipv4_src Source IPv4 address
|
||||
* @param id Fragment identification
|
||||
* @param data Data to save
|
||||
*
|
||||
* @return Data (or NULL when nothing found)
|
||||
* @return Structure for fragments (either retrieved or created)
|
||||
* @return NULL when structure for fragments couldn't be created
|
||||
*/
|
||||
void *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||
unsigned short id, void *data)
|
||||
struct s_nat_fragments *nat_in_fragments(radixtree_t *nat_proto4,
|
||||
linkedlist_t *nat_timeout,
|
||||
struct s_ipv4_addr ipv4_src,
|
||||
unsigned short id)
|
||||
{
|
||||
void *result;
|
||||
struct s_nat_fragments *result;
|
||||
|
||||
/* create structure to search in the tree */
|
||||
struct s_radixtree_fragments4 radixsearch4;
|
||||
@@ -213,38 +249,26 @@ void *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||
radixsearch4.id = id;
|
||||
|
||||
if ((result = radixtree_lookup(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4, sizeof(radixsearch4))) == NULL) {
|
||||
if (data != NULL) {
|
||||
/* when fragmentation is not found, add one */
|
||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4, sizeof(radixsearch4),
|
||||
data);
|
||||
return data;
|
||||
} else {
|
||||
/* nothing found and nothing to be added */
|
||||
&radixsearch4, sizeof(radixsearch4))) != NULL) {
|
||||
return result;
|
||||
} else {
|
||||
/* when fragmentation is not found, add one */
|
||||
if ((result = (struct s_nat_fragments *)
|
||||
malloc(sizeof(struct s_nat_fragments))) == NULL) {
|
||||
log_error("Lack of free memory");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (data != NULL) {
|
||||
/* when fragmentation is found, is it the same? */
|
||||
if (result == data) {
|
||||
/* OK, return */
|
||||
return result;
|
||||
} else {
|
||||
/* sender determines usage of IDs, so this one
|
||||
* shouldn't be used anymore for that
|
||||
* connection */
|
||||
radixtree_delete(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4,
|
||||
sizeof(radixsearch4));
|
||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4,
|
||||
sizeof(radixsearch4), data);
|
||||
return data;
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
result->id = id;
|
||||
result->connection = NULL;
|
||||
result->queue = NULL;
|
||||
|
||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4, sizeof(radixsearch4),
|
||||
result);
|
||||
linkedlist_append(nat_timeout, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,3 +293,106 @@ void nat_in_fragments_cleanup(radixtree_t *nat_proto4,
|
||||
sizeof(radixsearch4));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a NAT connection.
|
||||
*
|
||||
* @param nat_proto4 Relevant NAT4 table
|
||||
* @param nat_proto6 Relevant NAT6 table
|
||||
* @param connection Connection to be deleted
|
||||
*/
|
||||
void nat_delete_connection(radixtree_t *nat_proto4, radixtree_t *nat_proto6,
|
||||
struct s_nat *connection)
|
||||
{
|
||||
/* create structure to search in the tree */
|
||||
struct s_radixtree_nat4 radixsearch4;
|
||||
struct s_radixtree_nat6 radixsearch6;
|
||||
|
||||
radixsearch6.ipv6 = connection->ipv6;
|
||||
radixsearch6.ipv4 = connection->ipv4;
|
||||
radixsearch6.port_src = connection->ipv6_port_src;
|
||||
radixsearch6.port_dst = connection->ipv4_port_dst;
|
||||
|
||||
radixsearch4.addr = connection->ipv4;
|
||||
radixsearch4.port_src = connection->ipv4_port_dst;
|
||||
radixsearch4.port_dst = connection->ipv4_port_src;
|
||||
radixsearch4.zeros = 0x0;
|
||||
|
||||
if (radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4,
|
||||
sizeof(radixsearch4)) != NULL) {
|
||||
radixtree_delete(nat_proto4, radixtree_chunker, &radixsearch4,
|
||||
sizeof(radixsearch4));
|
||||
}
|
||||
|
||||
if (radixtree_lookup(nat_proto6, radixtree_chunker, &radixsearch6,
|
||||
sizeof(radixsearch6)) != NULL) {
|
||||
radixtree_delete(nat_proto6, radixtree_chunker, &radixsearch6,
|
||||
sizeof(radixsearch6));
|
||||
}
|
||||
|
||||
free(connection);
|
||||
connection = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove expired connections from NAT.
|
||||
*/
|
||||
void nat_cleaning(void)
|
||||
{
|
||||
linkedlist_node_t *tmp;
|
||||
time_t curtime = time(NULL);
|
||||
|
||||
/* TCP FRAGMENTS [2 secs] */
|
||||
tmp = timeout_tcp_fragments->first.next;
|
||||
while (tmp->next != NULL && curtime - tmp->time >= 2) {
|
||||
tmp = tmp->next;
|
||||
|
||||
/* destroy queue */
|
||||
linkedlist_destroy(((struct s_nat_fragments *)
|
||||
tmp->prev->data)->queue);
|
||||
|
||||
/* remove connection */
|
||||
nat_in_fragments_cleanup(nat4_tcp_fragments,
|
||||
((struct s_nat_fragments *)
|
||||
tmp->prev->data)->connection->ipv4,
|
||||
((struct s_nat_fragments *)
|
||||
tmp->prev->data)->id);
|
||||
|
||||
free(((struct s_nat_fragments *) tmp->prev->data)->connection);
|
||||
free(tmp->prev->data);
|
||||
|
||||
linkedlist_delete(timeout_tcp_fragments, tmp->prev);
|
||||
}
|
||||
|
||||
/* ICMP [60 secs] */
|
||||
tmp = timeout_icmp->first.next;
|
||||
while (tmp->next != NULL && curtime - tmp->time >= 60) {
|
||||
tmp = tmp->next;
|
||||
nat_delete_connection(nat4_icmp, nat6_icmp, tmp->prev->data);
|
||||
linkedlist_delete(timeout_icmp, tmp->prev);
|
||||
}
|
||||
|
||||
/* TCP -- TRANS [4 mins] */
|
||||
tmp = timeout_tcp_trans->first.next;
|
||||
while (tmp->next != NULL && curtime - tmp->time >= 4 * 60) {
|
||||
tmp = tmp->next;
|
||||
nat_delete_connection(nat4_tcp, nat6_tcp, tmp->prev->data);
|
||||
linkedlist_delete(timeout_tcp_trans, tmp->prev);
|
||||
}
|
||||
|
||||
/* UDP [5 mins (minimum is 2 mins)] */
|
||||
tmp = timeout_udp->first.next;
|
||||
while (tmp->next != NULL && curtime - tmp->time >= 5 * 60) {
|
||||
tmp = tmp->next;
|
||||
nat_delete_connection(nat4_udp, nat6_udp, tmp->prev->data);
|
||||
linkedlist_delete(timeout_udp, tmp->prev);
|
||||
}
|
||||
|
||||
/* TCP -- EST [2 hrs and 4 mins] */
|
||||
tmp = timeout_tcp_est->first.next;
|
||||
while (tmp->next != NULL && curtime - tmp->time >= 124 * 60) {
|
||||
tmp = tmp->next;
|
||||
nat_delete_connection(nat4_tcp, nat6_tcp, tmp->prev->data);
|
||||
linkedlist_delete(timeout_tcp_est, tmp->prev);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user