1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-11-23 12:28:06 +02:00

Expiration of connections and fragments

This commit is contained in:
Michal Zima 2012-07-21 21:13:15 +02:00
parent 24b09b4d93
commit 95bfbe93e2
11 changed files with 464 additions and 143 deletions

View File

@ -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"

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 */

309
src/nat.c
View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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);

157
src/tcp.c
View File

@ -53,9 +53,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
unsigned short tmp_short;
unsigned char *packet;
unsigned char *saved_packet;
linkedlist_t *queue;
linkedlist_node_t *llnode;
unsigned char *saved_packet;
struct s_nat_fragments *frag_conn;
linkedlist_node_t *llnode;
struct s_ethernet *eth6;
struct s_ipv6 *ip6;
@ -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) {

View File

@ -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 */

View File

@ -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);

View File

@ -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 */