mirror of
https://code.semirocket.science/wrapsix
synced 2024-11-27 00:20:59 +02:00
Expiration of connections and fragments
This commit is contained in:
parent
24b09b4d93
commit
95bfbe93e2
@ -21,7 +21,7 @@ AC_ARG_ENABLE([debug],
|
||||
[debug=no])
|
||||
|
||||
if test "x$debug" = "xyes"; then
|
||||
AM_CFLAGS="${AM_CFLAGS} -g -ggdb -O0 -pipe -pedantic -Wshadow -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wold-style-definition -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-enum -Wswitch-default -Winit-self -Wmissing-include-dirs -Wundef -Waggregate-return -Wnested-externs -Wunsafe-loop-optimizations"
|
||||
AM_CFLAGS="${AM_CFLAGS} -g -ggdb -O0 -pipe -pedantic -Wshadow -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wold-style-definition -Wdeclaration-after-statement -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs -Wundef -Waggregate-return -Wnested-externs -Wunsafe-loop-optimizations"
|
||||
AC_DEFINE([DEBUG])
|
||||
else
|
||||
AM_CFLAGS="${AM_CFLAGS} -O2"
|
||||
|
15
src/icmp.c
15
src/icmp.c
@ -24,6 +24,7 @@
|
||||
#include "checksum.h"
|
||||
#include "icmp.h"
|
||||
#include "ipv6.h"
|
||||
#include "linkedlist.h"
|
||||
#include "log.h"
|
||||
#include "nat.h"
|
||||
#include "transmitter.h"
|
||||
@ -86,6 +87,8 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
||||
return 1;
|
||||
}
|
||||
|
||||
linkedlist_move2end(timeout_icmp, connection->llnode);
|
||||
|
||||
echo->id = connection->ipv6_port_src;
|
||||
|
||||
/* override information in original ICMP header */
|
||||
@ -189,7 +192,7 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
connection = nat_out(nat6_icmp, nat4_icmp,
|
||||
eth6->src,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
echo->id, 0);
|
||||
echo->id, 0, 1);
|
||||
|
||||
if (connection == NULL) {
|
||||
log_warn("Outgoing connection wasn't "
|
||||
@ -197,6 +200,15 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (connection->llnode == NULL) {
|
||||
connection->llnode =
|
||||
linkedlist_append(timeout_icmp,
|
||||
connection);
|
||||
} else {
|
||||
linkedlist_move2end(timeout_icmp,
|
||||
connection->llnode);
|
||||
}
|
||||
|
||||
echo->id = connection->ipv4_port_src;
|
||||
|
||||
/* override information in original ICMP header */
|
||||
@ -280,7 +292,6 @@ int icmp_ndp(struct s_ethernet *ethq, struct s_ipv6 *ipq,
|
||||
|
||||
/* first check whether the request belongs to us */
|
||||
if (memcmp(&wrapsix_ipv6_prefix, &ndp_ns->target, 12) != 0) {
|
||||
log_debug("This is unfamiliar NDP packet");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
#include <time.h> /* time, time_t */
|
||||
|
||||
#include "linkedlist.h"
|
||||
#include "log.h"
|
||||
@ -65,27 +66,28 @@ void linkedlist_destroy(linkedlist_t *root)
|
||||
* @param root Root of the linked list
|
||||
* @param data Data to append to the list
|
||||
*
|
||||
* @return 0 for success
|
||||
* @return 1 for failure
|
||||
* @return pointer to created node if succeeded
|
||||
* @return NULL if failed
|
||||
*/
|
||||
int linkedlist_append(linkedlist_t *root, void *data)
|
||||
linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data)
|
||||
{
|
||||
linkedlist_node_t *node;
|
||||
|
||||
if ((node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t))) ==
|
||||
NULL) {
|
||||
log_error("Lack of free memory");
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->data = data;
|
||||
node->time = time(NULL);
|
||||
|
||||
node->prev = root->last.prev;
|
||||
node->next = &root->last;
|
||||
root->last.prev->next = node;
|
||||
root->last.prev = node;
|
||||
|
||||
return 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,3 +104,25 @@ void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node)
|
||||
free(node);
|
||||
node = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a node to the end of linked list. It's possible to even move it to
|
||||
* another linked list.
|
||||
*
|
||||
* @param root Root of the linked list
|
||||
* @param node Node to move to the end
|
||||
*/
|
||||
void linkedlist_move2end(linkedlist_t *root, linkedlist_node_t *node)
|
||||
{
|
||||
/* take the node out */
|
||||
node->next->prev = node->prev;
|
||||
node->prev->next = node->next;
|
||||
|
||||
/* put it to the end */
|
||||
node->prev = root->last.prev;
|
||||
node->next = &root->last;
|
||||
root->last.prev->next = node;
|
||||
root->last.prev = node;
|
||||
|
||||
node->time = time(NULL);
|
||||
}
|
||||
|
@ -19,11 +19,14 @@
|
||||
#ifndef LINKEDLIST_H
|
||||
#define LINKEDLIST_H
|
||||
|
||||
#include <time.h> /* time_t */
|
||||
|
||||
/* Linked list node structure */
|
||||
typedef struct s_linkedlist_node {
|
||||
struct s_linkedlist_node *prev;
|
||||
struct s_linkedlist_node *next;
|
||||
void *data;
|
||||
time_t time;
|
||||
} linkedlist_node_t;
|
||||
|
||||
/* Linked list root structure */
|
||||
@ -34,7 +37,8 @@ typedef struct s_linkedlist {
|
||||
|
||||
linkedlist_t *linkedlist_create(void);
|
||||
void linkedlist_destroy(linkedlist_t *root);
|
||||
int linkedlist_append(linkedlist_t *root, void *data);
|
||||
linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data);
|
||||
void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node);
|
||||
void linkedlist_move2end(linkedlist_t *root, linkedlist_node_t *node);
|
||||
|
||||
#endif /* LINKEDLIST_H */
|
||||
|
223
src/nat.c
223
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,7 +98,12 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,6 +116,7 @@ void nat_quit(void)
|
||||
* @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
|
||||
@ -104,7 +124,8 @@ void nat_quit(void)
|
||||
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,9 +140,11 @@ 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 (create > 0) {
|
||||
/* if no connection is found, let's create one */
|
||||
if ((connection =
|
||||
(struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) {
|
||||
(struct s_nat *) malloc(sizeof(struct s_nat))) ==
|
||||
NULL) {
|
||||
log_error("Lack of free memory");
|
||||
return NULL;
|
||||
}
|
||||
@ -131,7 +154,8 @@ 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;
|
||||
connection->last_packet = time(NULL);
|
||||
connection->state = 1;
|
||||
connection->llnode = NULL;
|
||||
|
||||
radixsearch4.addr = radixsearch6.ipv4;
|
||||
radixsearch4.port_src = port_dst;
|
||||
@ -142,19 +166,29 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||
/* returns port from range 1024 - 65535 */
|
||||
radixsearch4.port_dst = (rand() % 64511) + 1024;
|
||||
|
||||
result = radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4));
|
||||
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);
|
||||
/* 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);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* when connection is found, return it */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -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,39 +249,27 @@ 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;
|
||||
&radixsearch4, sizeof(radixsearch4))) != NULL) {
|
||||
return result;
|
||||
} else {
|
||||
/* nothing found and nothing to be added */
|
||||
/* 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));
|
||||
|
||||
result->id = id;
|
||||
result->connection = NULL;
|
||||
result->queue = NULL;
|
||||
|
||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||
&radixsearch4,
|
||||
sizeof(radixsearch4), data);
|
||||
return data;
|
||||
}
|
||||
} else {
|
||||
&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);
|
||||
}
|
||||
}
|
||||
|
29
src/nat.h
29
src/nat.h
@ -19,11 +19,10 @@
|
||||
#ifndef NAT_H
|
||||
#define NAT_H
|
||||
|
||||
#include <time.h> /* time_t */
|
||||
|
||||
#include "ethernet.h" /* s_mac_addr */
|
||||
#include "ipv4.h" /* s_ipv4_addr */
|
||||
#include "ipv6.h" /* s_ipv6_addr */
|
||||
#include "linkedlist.h" /* linkedlist_h */
|
||||
#include "radixtree.h" /* radixtree_t */
|
||||
|
||||
struct s_nat {
|
||||
@ -33,13 +32,23 @@ struct s_nat {
|
||||
unsigned short ipv6_port_src;
|
||||
unsigned short ipv4_port_src;
|
||||
unsigned short ipv4_port_dst;
|
||||
time_t last_packet; /* time of processing last
|
||||
packet of the connection */
|
||||
unsigned char state;
|
||||
linkedlist_node_t *llnode;
|
||||
};
|
||||
|
||||
struct s_nat_fragments {
|
||||
unsigned short id;
|
||||
struct s_nat *connection;
|
||||
linkedlist_t *queue;
|
||||
};
|
||||
|
||||
extern radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
|
||||
*nat4_tcp, *nat4_udp, *nat4_icmp,
|
||||
*nat4_tcp_fragments, *nat4_saved_fragments;
|
||||
*nat4_tcp_fragments;
|
||||
|
||||
extern linkedlist_t *timeout_icmp, *timeout_udp,
|
||||
*timeout_tcp_est, *timeout_tcp_trans,
|
||||
*timeout_tcp_fragments;
|
||||
|
||||
void nat_init(void);
|
||||
void nat_quit(void);
|
||||
@ -47,12 +56,16 @@ void nat_quit(void);
|
||||
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 *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||
unsigned short port_src, unsigned short port_dst);
|
||||
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,
|
||||
linkedlist_t *nat_timeout,
|
||||
struct s_ipv4_addr ipv4_src,
|
||||
unsigned short id);
|
||||
void nat_in_fragments_cleanup(radixtree_t *nat_proto4,
|
||||
struct s_ipv4_addr ipv4_src, unsigned short id);
|
||||
void nat_cleaning(void);
|
||||
|
||||
#endif /* NAT_H */
|
||||
|
@ -82,7 +82,6 @@ void radixtree_insert(radixtree_t *root,
|
||||
chunks = chunker(search_data, size, &chunk_count);
|
||||
|
||||
tmp = root;
|
||||
tmp->count++;
|
||||
|
||||
for (i = 0; i < chunk_count; i++) {
|
||||
unsigned char id;
|
||||
@ -91,15 +90,17 @@ void radixtree_insert(radixtree_t *root,
|
||||
|
||||
if (i == chunk_count - 1) {
|
||||
tmp->array[id] = data;
|
||||
tmp->count++;
|
||||
free(chunks);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tmp->array[id] == NULL) {
|
||||
tmp->array[id] = radixtree_create();
|
||||
tmp->count++;
|
||||
}
|
||||
|
||||
tmp = tmp->array[id];
|
||||
tmp->count++;
|
||||
}
|
||||
|
||||
free(chunks);
|
||||
|
153
src/tcp.c
153
src/tcp.c
@ -54,7 +54,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
unsigned char *packet;
|
||||
|
||||
unsigned char *saved_packet;
|
||||
linkedlist_t *queue;
|
||||
struct s_nat_fragments *frag_conn;
|
||||
linkedlist_node_t *llnode;
|
||||
|
||||
struct s_ethernet *eth6;
|
||||
@ -98,17 +98,74 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TCP state machine */
|
||||
switch (connection->state) {
|
||||
case TCP_STATE_EST:
|
||||
if (tcp->flags & TCP_FLAG_FIN) {
|
||||
connection->state = TCP_STATE_FIN4;
|
||||
break;
|
||||
} else if (tcp->flags & TCP_FLAG_RST) {
|
||||
connection->state = TCP_STATE_TRANS;
|
||||
linkedlist_move2end(timeout_tcp_trans, connection->llnode);
|
||||
break;
|
||||
} else {
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
|
||||
case TCP_STATE_INIT:
|
||||
if (tcp->flags & TCP_FLAG_SYN) {
|
||||
connection->state = TCP_STATE_EST;
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
}
|
||||
break;
|
||||
|
||||
case TCP_STATE_FIN4:
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
|
||||
case TCP_STATE_FIN6:
|
||||
if (tcp->flags & TCP_FLAG_FIN) {
|
||||
connection->state = TCP_STATE_FIN64;
|
||||
linkedlist_move2end(timeout_tcp_trans, connection->llnode);
|
||||
break;
|
||||
} else {
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
|
||||
case TCP_STATE_FIN64:
|
||||
break;
|
||||
|
||||
case TCP_STATE_TRANS:
|
||||
if (tcp->flags & TCP_FLAG_RST) {
|
||||
break;
|
||||
} else {
|
||||
connection->state = TCP_STATE_EST;
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if it's fragmented, save it to fragments table */
|
||||
if (ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
||||
nat_in_fragments(nat4_tcp_fragments, ip4->ip_src,
|
||||
ip4->id, connection);
|
||||
if ((frag_conn = nat_in_fragments(nat4_tcp_fragments,
|
||||
timeout_tcp_fragments, ip4->ip_src, ip4->id)) ==
|
||||
NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* what is probability that there is already some other
|
||||
* connection? if there is such connection then there is
|
||||
* just a little chance to fix something as normally all
|
||||
* our fragments are already processed at this moment */
|
||||
frag_conn->connection = connection;
|
||||
|
||||
/* check if there are any saved fragments */
|
||||
if ((queue = nat_in_fragments(nat4_saved_fragments,
|
||||
ip4->ip_src, ip4->id, NULL)) != NULL) {
|
||||
if (frag_conn->queue != NULL) {
|
||||
log_debug("Processing TCP fragments of %d",
|
||||
ip4->id);
|
||||
llnode = queue->first.next;
|
||||
llnode = frag_conn->queue->first.next;
|
||||
while (llnode->next != NULL) {
|
||||
llnode = llnode->next;
|
||||
memcpy(&tmp_short, llnode->prev->data,
|
||||
@ -127,7 +184,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
sizeof(struct s_ipv4)),
|
||||
tmp_short);
|
||||
free(llnode->prev->data);
|
||||
linkedlist_delete(queue, llnode->prev);
|
||||
linkedlist_delete(frag_conn->queue,
|
||||
llnode->prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -230,10 +288,12 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
}
|
||||
} else {
|
||||
/* find connection in fragments table */
|
||||
connection = nat_in_fragments(nat4_tcp_fragments, ip4->ip_src,
|
||||
ip4->id, NULL);
|
||||
if ((frag_conn = nat_in_fragments(nat4_tcp_fragments,
|
||||
timeout_tcp_fragments, ip4->ip_src, ip4->id)) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (connection == NULL) {
|
||||
if (frag_conn->connection == NULL) {
|
||||
log_debug("Incoming connection wasn't found in "
|
||||
"fragments table -- saving it");
|
||||
|
||||
@ -244,19 +304,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* first lookup */
|
||||
connection = nat_in_fragments(nat4_saved_fragments,
|
||||
ip4->ip_src, ip4->id,
|
||||
NULL);
|
||||
|
||||
/* if unsuccessful, create a queue and put into tree */
|
||||
if (connection == NULL) {
|
||||
if ((queue = linkedlist_create()) == NULL) {
|
||||
if (frag_conn->queue == NULL) {
|
||||
if ((frag_conn->queue = linkedlist_create()) ==
|
||||
NULL) {
|
||||
free(saved_packet);
|
||||
return 1;
|
||||
}
|
||||
nat_in_fragments(nat4_saved_fragments,
|
||||
ip4->ip_src, ip4->id, queue);
|
||||
}
|
||||
|
||||
/* save the packet and put it into the queue */
|
||||
@ -274,7 +328,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
sizeof(struct s_ethernet) +
|
||||
sizeof(struct s_ipv4)), payload, payload_size);
|
||||
|
||||
linkedlist_append(queue, saved_packet);
|
||||
linkedlist_append(frag_conn->queue, saved_packet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -295,7 +349,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
sizeof(struct s_ipv6));
|
||||
|
||||
/* build ethernet header */
|
||||
eth6->dest = connection->mac;
|
||||
eth6->dest = frag_conn->connection->mac;
|
||||
eth6->src = mac;
|
||||
eth6->type = htons(ETHERTYPE_IPV6);
|
||||
|
||||
@ -427,13 +481,68 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
/* find connection in NAT */
|
||||
connection = nat_out(nat6_tcp, nat4_tcp, eth6->src,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
tcp->port_src, tcp->port_dest);
|
||||
tcp->port_src, tcp->port_dest,
|
||||
tcp->flags & TCP_FLAG_SYN);
|
||||
|
||||
if (connection == NULL) {
|
||||
log_warn("Outgoing connection wasn't found/created in NAT");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TCP state machine */
|
||||
switch (connection->state) {
|
||||
case TCP_STATE_EST:
|
||||
if (tcp->flags & TCP_FLAG_FIN) {
|
||||
connection->state = TCP_STATE_FIN6;
|
||||
break;
|
||||
} else if (tcp->flags & TCP_FLAG_RST) {
|
||||
connection->state = TCP_STATE_TRANS;
|
||||
linkedlist_move2end(timeout_tcp_trans, connection->llnode);
|
||||
break;
|
||||
} else {
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
|
||||
case TCP_STATE_INIT:
|
||||
if (tcp->flags & TCP_FLAG_SYN) {
|
||||
if (connection->llnode == NULL) {
|
||||
connection->llnode = linkedlist_append(timeout_tcp_trans, connection);
|
||||
break;
|
||||
} else {
|
||||
linkedlist_move2end(timeout_tcp_trans, connection->llnode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TCP_STATE_FIN4:
|
||||
if (tcp->flags & TCP_FLAG_FIN) {
|
||||
connection->state = TCP_STATE_FIN64;
|
||||
linkedlist_move2end(timeout_tcp_trans, connection->llnode);
|
||||
break;
|
||||
} else {
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
|
||||
case TCP_STATE_FIN6:
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
|
||||
case TCP_STATE_FIN64:
|
||||
break;
|
||||
|
||||
case TCP_STATE_TRANS:
|
||||
if (tcp->flags & TCP_FLAG_RST) {
|
||||
break;
|
||||
} else {
|
||||
connection->state = TCP_STATE_EST;
|
||||
linkedlist_move2end(timeout_tcp_est, connection->llnode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate memory for translated packet */
|
||||
if ((packet = (unsigned char *) malloc(sizeof(struct s_ipv4) +
|
||||
htons(ip6->len))) == NULL) {
|
||||
|
11
src/tcp.h
11
src/tcp.h
@ -19,6 +19,17 @@
|
||||
#ifndef TCP_H
|
||||
#define TCP_H
|
||||
|
||||
#define TCP_FLAG_FIN 0x01
|
||||
#define TCP_FLAG_SYN 0x02
|
||||
#define TCP_FLAG_RST 0x04
|
||||
|
||||
#define TCP_STATE_INIT 1
|
||||
#define TCP_STATE_EST 2
|
||||
#define TCP_STATE_FIN4 3
|
||||
#define TCP_STATE_FIN6 4
|
||||
#define TCP_STATE_FIN64 5
|
||||
#define TCP_STATE_TRANS 6
|
||||
|
||||
/* TCP header structure */
|
||||
struct s_tcp {
|
||||
unsigned short port_src; /* 16 b; source port */
|
||||
|
15
src/udp.c
15
src/udp.c
@ -26,6 +26,7 @@
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "log.h"
|
||||
#include "linkedlist.h"
|
||||
#include "nat.h"
|
||||
#include "transmitter.h"
|
||||
#include "udp.h"
|
||||
@ -81,6 +82,8 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||
return 1;
|
||||
}
|
||||
|
||||
linkedlist_move2end(timeout_udp, connection->llnode);
|
||||
|
||||
/* allocate memory for translated packet */
|
||||
if ((packet = (unsigned char *) malloc(sizeof(struct s_ethernet) +
|
||||
sizeof(struct s_ipv6) +
|
||||
@ -175,13 +178,19 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
/* find connection in NAT */
|
||||
connection = nat_out(nat6_udp, nat4_udp, eth6->src,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
udp->port_src, udp->port_dest);
|
||||
udp->port_src, udp->port_dest, 1);
|
||||
|
||||
if (connection == NULL) {
|
||||
log_warn("Outgoing connection wasn't found/created in NAT!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (connection->llnode == NULL) {
|
||||
connection->llnode = linkedlist_append(timeout_udp, connection);
|
||||
} else {
|
||||
linkedlist_move2end(timeout_udp, connection->llnode);
|
||||
}
|
||||
|
||||
/* allocate memory for translated packet */
|
||||
packet_size = sizeof(struct s_ipv4) + htons(ip6->len);
|
||||
if ((packet = (unsigned char *) malloc(packet_size)) == NULL) {
|
||||
@ -194,7 +203,7 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
|
||||
ip4->tos = ((ip6->ver & 0x0f) << 4) |
|
||||
((ip6->traffic_class & 0xf0) >> 4);
|
||||
ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len));
|
||||
ip4->len = htons(packet_size);
|
||||
ip4->id = 0x0;
|
||||
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
||||
ip4->ttl = ip6->hop_limit;
|
||||
@ -220,7 +229,7 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
||||
ip4->checksum = checksum(ip4, sizeof(struct s_ipv4));
|
||||
|
||||
/* send translated packet */
|
||||
transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len));
|
||||
transmit_ipv4(&ip4->ip_dest, packet, packet_size);
|
||||
|
||||
/* clean-up */
|
||||
free(packet);
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <stdlib.h> /* srand */
|
||||
#include <string.h> /* strncpy */
|
||||
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
|
||||
#include <time.h> /* time */
|
||||
#include <time.h> /* time, time_t */
|
||||
#include <unistd.h> /* close */
|
||||
|
||||
#include "arp.h"
|
||||
@ -56,13 +56,13 @@ int main(int argc, char **argv)
|
||||
{
|
||||
struct packet_mreq pmr;
|
||||
|
||||
struct sockaddr_ll addr;
|
||||
size_t addr_size;
|
||||
|
||||
int sniff_sock;
|
||||
int length;
|
||||
char buffer[PACKET_BUFFER];
|
||||
|
||||
int i;
|
||||
time_t prevtime, curtime;
|
||||
|
||||
log_info(PACKAGE_STRING " is starting");
|
||||
|
||||
/* initialize the socket for sniffing */
|
||||
@ -123,15 +123,27 @@ int main(int argc, char **argv)
|
||||
/* initiate random numbers generator */
|
||||
srand((unsigned int) time(NULL));
|
||||
|
||||
/* initialize time */
|
||||
prevtime = time(NULL);
|
||||
|
||||
/* sniff! :c) */
|
||||
for (;;) {
|
||||
addr_size = sizeof(addr);
|
||||
for (i = 1;; i++) {
|
||||
if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) == -1) {
|
||||
log_error("Unable to retrieve data from socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
process((char *) &buffer);
|
||||
|
||||
if (i % 250000) {
|
||||
curtime = time(NULL);
|
||||
/* 2 seconds is minimum normal timeout */
|
||||
if ((curtime - prevtime) >= 2) {
|
||||
nat_cleaning();
|
||||
prevtime = curtime;
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* clean-up */
|
||||
|
Loading…
Reference in New Issue
Block a user