mirror of
https://code.semirocket.science/wrapsix
synced 2024-11-23 13:19:22 +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])
|
[debug=no])
|
||||||
|
|
||||||
if test "x$debug" = "xyes"; then
|
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])
|
AC_DEFINE([DEBUG])
|
||||||
else
|
else
|
||||||
AM_CFLAGS="${AM_CFLAGS} -O2"
|
AM_CFLAGS="${AM_CFLAGS} -O2"
|
||||||
|
15
src/icmp.c
15
src/icmp.c
@ -24,6 +24,7 @@
|
|||||||
#include "checksum.h"
|
#include "checksum.h"
|
||||||
#include "icmp.h"
|
#include "icmp.h"
|
||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
|
#include "linkedlist.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nat.h"
|
#include "nat.h"
|
||||||
#include "transmitter.h"
|
#include "transmitter.h"
|
||||||
@ -86,6 +87,8 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkedlist_move2end(timeout_icmp, connection->llnode);
|
||||||
|
|
||||||
echo->id = connection->ipv6_port_src;
|
echo->id = connection->ipv6_port_src;
|
||||||
|
|
||||||
/* override information in original ICMP header */
|
/* 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,
|
connection = nat_out(nat6_icmp, nat4_icmp,
|
||||||
eth6->src,
|
eth6->src,
|
||||||
ip6->ip_src, ip6->ip_dest,
|
ip6->ip_src, ip6->ip_dest,
|
||||||
echo->id, 0);
|
echo->id, 0, 1);
|
||||||
|
|
||||||
if (connection == NULL) {
|
if (connection == NULL) {
|
||||||
log_warn("Outgoing connection wasn't "
|
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;
|
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;
|
echo->id = connection->ipv4_port_src;
|
||||||
|
|
||||||
/* override information in original ICMP header */
|
/* 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 */
|
/* first check whether the request belongs to us */
|
||||||
if (memcmp(&wrapsix_ipv6_prefix, &ndp_ns->target, 12) != 0) {
|
if (memcmp(&wrapsix_ipv6_prefix, &ndp_ns->target, 12) != 0) {
|
||||||
log_debug("This is unfamiliar NDP packet");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h> /* free, malloc */
|
#include <stdlib.h> /* free, malloc */
|
||||||
|
#include <time.h> /* time, time_t */
|
||||||
|
|
||||||
#include "linkedlist.h"
|
#include "linkedlist.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -65,27 +66,28 @@ void linkedlist_destroy(linkedlist_t *root)
|
|||||||
* @param root Root of the linked list
|
* @param root Root of the linked list
|
||||||
* @param data Data to append to the list
|
* @param data Data to append to the list
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return pointer to created node if succeeded
|
||||||
* @return 1 for failure
|
* @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;
|
linkedlist_node_t *node;
|
||||||
|
|
||||||
if ((node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t))) ==
|
if ((node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t))) ==
|
||||||
NULL) {
|
NULL) {
|
||||||
log_error("Lack of free memory");
|
log_error("Lack of free memory");
|
||||||
return 1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
|
node->time = time(NULL);
|
||||||
|
|
||||||
node->prev = root->last.prev;
|
node->prev = root->last.prev;
|
||||||
node->next = &root->last;
|
node->next = &root->last;
|
||||||
root->last.prev->next = node;
|
root->last.prev->next = node;
|
||||||
root->last.prev = 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);
|
free(node);
|
||||||
node = NULL;
|
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
|
#ifndef LINKEDLIST_H
|
||||||
#define LINKEDLIST_H
|
#define LINKEDLIST_H
|
||||||
|
|
||||||
|
#include <time.h> /* time_t */
|
||||||
|
|
||||||
/* Linked list node structure */
|
/* Linked list node structure */
|
||||||
typedef struct s_linkedlist_node {
|
typedef struct s_linkedlist_node {
|
||||||
struct s_linkedlist_node *prev;
|
struct s_linkedlist_node *prev;
|
||||||
struct s_linkedlist_node *next;
|
struct s_linkedlist_node *next;
|
||||||
void *data;
|
void *data;
|
||||||
|
time_t time;
|
||||||
} linkedlist_node_t;
|
} linkedlist_node_t;
|
||||||
|
|
||||||
/* Linked list root structure */
|
/* Linked list root structure */
|
||||||
@ -34,7 +37,8 @@ typedef struct s_linkedlist {
|
|||||||
|
|
||||||
linkedlist_t *linkedlist_create(void);
|
linkedlist_t *linkedlist_create(void);
|
||||||
void linkedlist_destroy(linkedlist_t *root);
|
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_delete(linkedlist_t *root, linkedlist_node_t *node);
|
||||||
|
void linkedlist_move2end(linkedlist_t *root, linkedlist_node_t *node);
|
||||||
|
|
||||||
#endif /* LINKEDLIST_H */
|
#endif /* LINKEDLIST_H */
|
||||||
|
309
src/nat.c
309
src/nat.c
@ -48,7 +48,16 @@ struct s_radixtree_fragments4 {
|
|||||||
|
|
||||||
radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
|
radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
|
||||||
*nat4_tcp, *nat4_udp, *nat4_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.
|
* Initialization of NAT tables.
|
||||||
@ -64,7 +73,12 @@ void nat_init(void)
|
|||||||
nat4_icmp = radixtree_create();
|
nat4_icmp = radixtree_create();
|
||||||
|
|
||||||
nat4_tcp_fragments = 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 */
|
/* 32 + 16 = 48 / 6 = 8 */
|
||||||
radixtree_destroy(nat4_tcp_fragments, 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.
|
* Lookup or create NAT connection for outgoing IPv6 packet.
|
||||||
*
|
*
|
||||||
* @param nat_proto6 IPv6 NAT table
|
* @param nat_proto6 IPv6 NAT table
|
||||||
* @param nat_proto4 IPv4 NAT table
|
* @param nat_proto4 IPv4 NAT table
|
||||||
* @param eth_src Source MAC address
|
* @param eth_src Source MAC address
|
||||||
* @param ipv6_src Source IPv6 address
|
* @param ipv6_src Source IPv6 address
|
||||||
* @param ipv6_dst Destination IPv6 address
|
* @param ipv6_dst Destination IPv6 address
|
||||||
* @param port_src Source port
|
* @param port_src Source port
|
||||||
* @param port_dst Destination 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 NULL when it wasn't possible to create connection
|
||||||
* @return pointer to connection structure otherwise
|
* @return pointer to connection structure otherwise
|
||||||
*/
|
*/
|
||||||
struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||||
struct s_mac_addr eth_src,
|
struct s_mac_addr eth_src,
|
||||||
struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst,
|
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;
|
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,
|
if ((result = (struct s_nat *) radixtree_lookup(nat_proto6,
|
||||||
radixtree_chunker, &radixsearch6, sizeof(radixsearch6))) == NULL) {
|
radixtree_chunker, &radixsearch6, sizeof(radixsearch6))) == NULL) {
|
||||||
/* if no connection is found, let's create one */
|
if (create > 0) {
|
||||||
if ((connection =
|
/* if no connection is found, let's create one */
|
||||||
(struct s_nat *) malloc(sizeof(struct s_nat))) == NULL) {
|
if ((connection =
|
||||||
log_error("Lack of free memory");
|
(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;
|
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 {
|
} else {
|
||||||
/* when connection is found, refresh it and return */
|
/* when connection is found, return it */
|
||||||
result->last_packet = time(NULL);
|
|
||||||
return result;
|
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.
|
* Lookup NAT connection for incoming IPv4 packet.
|
||||||
*
|
*
|
||||||
* @param nat_proto4 NAT table
|
* @param nat_proto4 NAT table
|
||||||
* @param ipv4_src Source IPv4 address
|
* @param ipv4_src Source IPv4 address
|
||||||
* @param port_src Source port
|
* @param port_src Source port
|
||||||
* @param port_dst Destination port
|
* @param port_dst Destination port
|
||||||
*
|
*
|
||||||
* @return NULL when no connection was found
|
* @return NULL when no connection was found
|
||||||
* @return pointer to connection structure otherwise
|
* @return pointer to connection structure otherwise
|
||||||
*/
|
*/
|
||||||
struct s_nat *nat_in(radixtree_t *nat_proto4, 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)
|
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.port_dst = port_dst;
|
||||||
radixsearch4.zeros = 0x0;
|
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 */
|
/* when connection is not found, drop the packet */
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
/* when connection is found, refresh it and return */
|
/* when connection is found, return it */
|
||||||
result->last_packet = time(NULL);
|
|
||||||
return result;
|
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 nat_proto4 Radix tree of fragments
|
||||||
* @param ipv4_src Source IPv4 address
|
* @param ipv4_src Source IPv4 address
|
||||||
* @param id Fragment identification
|
* @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,
|
struct s_nat_fragments *nat_in_fragments(radixtree_t *nat_proto4,
|
||||||
unsigned short id, void *data)
|
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 */
|
/* create structure to search in the tree */
|
||||||
struct s_radixtree_fragments4 radixsearch4;
|
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;
|
radixsearch4.id = id;
|
||||||
|
|
||||||
if ((result = radixtree_lookup(nat_proto4, radixtree_chunker,
|
if ((result = radixtree_lookup(nat_proto4, radixtree_chunker,
|
||||||
&radixsearch4, sizeof(radixsearch4))) == NULL) {
|
&radixsearch4, sizeof(radixsearch4))) != NULL) {
|
||||||
if (data != NULL) {
|
return result;
|
||||||
/* when fragmentation is not found, add one */
|
} else {
|
||||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
/* when fragmentation is not found, add one */
|
||||||
&radixsearch4, sizeof(radixsearch4),
|
if ((result = (struct s_nat_fragments *)
|
||||||
data);
|
malloc(sizeof(struct s_nat_fragments))) == NULL) {
|
||||||
return data;
|
log_error("Lack of free memory");
|
||||||
} else {
|
|
||||||
/* nothing found and nothing to be added */
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (data != NULL) {
|
result->id = id;
|
||||||
/* when fragmentation is found, is it the same? */
|
result->connection = NULL;
|
||||||
if (result == data) {
|
result->queue = NULL;
|
||||||
/* OK, return */
|
|
||||||
return result;
|
radixtree_insert(nat_proto4, radixtree_chunker,
|
||||||
} else {
|
&radixsearch4, sizeof(radixsearch4),
|
||||||
/* sender determines usage of IDs, so this one
|
result);
|
||||||
* shouldn't be used anymore for that
|
linkedlist_append(nat_timeout, result);
|
||||||
* connection */
|
|
||||||
radixtree_delete(nat_proto4, radixtree_chunker,
|
return result;
|
||||||
&radixsearch4,
|
|
||||||
sizeof(radixsearch4));
|
|
||||||
radixtree_insert(nat_proto4, radixtree_chunker,
|
|
||||||
&radixsearch4,
|
|
||||||
sizeof(radixsearch4), data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,3 +293,106 @@ void nat_in_fragments_cleanup(radixtree_t *nat_proto4,
|
|||||||
sizeof(radixsearch4));
|
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
|
#ifndef NAT_H
|
||||||
#define NAT_H
|
#define NAT_H
|
||||||
|
|
||||||
#include <time.h> /* time_t */
|
|
||||||
|
|
||||||
#include "ethernet.h" /* s_mac_addr */
|
#include "ethernet.h" /* s_mac_addr */
|
||||||
#include "ipv4.h" /* s_ipv4_addr */
|
#include "ipv4.h" /* s_ipv4_addr */
|
||||||
#include "ipv6.h" /* s_ipv6_addr */
|
#include "ipv6.h" /* s_ipv6_addr */
|
||||||
|
#include "linkedlist.h" /* linkedlist_h */
|
||||||
#include "radixtree.h" /* radixtree_t */
|
#include "radixtree.h" /* radixtree_t */
|
||||||
|
|
||||||
struct s_nat {
|
struct s_nat {
|
||||||
@ -33,13 +32,23 @@ struct s_nat {
|
|||||||
unsigned short ipv6_port_src;
|
unsigned short ipv6_port_src;
|
||||||
unsigned short ipv4_port_src;
|
unsigned short ipv4_port_src;
|
||||||
unsigned short ipv4_port_dst;
|
unsigned short ipv4_port_dst;
|
||||||
time_t last_packet; /* time of processing last
|
unsigned char state;
|
||||||
packet of the connection */
|
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,
|
extern radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
|
||||||
*nat4_tcp, *nat4_udp, *nat4_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_init(void);
|
||||||
void nat_quit(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_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
|
||||||
struct s_mac_addr eth_src,
|
struct s_mac_addr eth_src,
|
||||||
struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst,
|
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,
|
struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
||||||
unsigned short port_src, unsigned short port_dst);
|
unsigned short port_src, unsigned short port_dst);
|
||||||
void *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
|
struct s_nat_fragments *nat_in_fragments(radixtree_t *nat,
|
||||||
unsigned short id, void *data);
|
linkedlist_t *nat_timeout,
|
||||||
|
struct s_ipv4_addr ipv4_src,
|
||||||
|
unsigned short id);
|
||||||
void nat_in_fragments_cleanup(radixtree_t *nat_proto4,
|
void nat_in_fragments_cleanup(radixtree_t *nat_proto4,
|
||||||
struct s_ipv4_addr ipv4_src, unsigned short id);
|
struct s_ipv4_addr ipv4_src, unsigned short id);
|
||||||
|
void nat_cleaning(void);
|
||||||
|
|
||||||
#endif /* NAT_H */
|
#endif /* NAT_H */
|
||||||
|
@ -82,7 +82,6 @@ void radixtree_insert(radixtree_t *root,
|
|||||||
chunks = chunker(search_data, size, &chunk_count);
|
chunks = chunker(search_data, size, &chunk_count);
|
||||||
|
|
||||||
tmp = root;
|
tmp = root;
|
||||||
tmp->count++;
|
|
||||||
|
|
||||||
for (i = 0; i < chunk_count; i++) {
|
for (i = 0; i < chunk_count; i++) {
|
||||||
unsigned char id;
|
unsigned char id;
|
||||||
@ -91,15 +90,17 @@ void radixtree_insert(radixtree_t *root,
|
|||||||
|
|
||||||
if (i == chunk_count - 1) {
|
if (i == chunk_count - 1) {
|
||||||
tmp->array[id] = data;
|
tmp->array[id] = data;
|
||||||
|
tmp->count++;
|
||||||
|
free(chunks);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp->array[id] == NULL) {
|
if (tmp->array[id] == NULL) {
|
||||||
tmp->array[id] = radixtree_create();
|
tmp->array[id] = radixtree_create();
|
||||||
|
tmp->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = tmp->array[id];
|
tmp = tmp->array[id];
|
||||||
tmp->count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(chunks);
|
free(chunks);
|
||||||
|
157
src/tcp.c
157
src/tcp.c
@ -53,9 +53,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
unsigned short tmp_short;
|
unsigned short tmp_short;
|
||||||
unsigned char *packet;
|
unsigned char *packet;
|
||||||
|
|
||||||
unsigned char *saved_packet;
|
unsigned char *saved_packet;
|
||||||
linkedlist_t *queue;
|
struct s_nat_fragments *frag_conn;
|
||||||
linkedlist_node_t *llnode;
|
linkedlist_node_t *llnode;
|
||||||
|
|
||||||
struct s_ethernet *eth6;
|
struct s_ethernet *eth6;
|
||||||
struct s_ipv6 *ip6;
|
struct s_ipv6 *ip6;
|
||||||
@ -98,17 +98,74 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
return 1;
|
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 it's fragmented, save it to fragments table */
|
||||||
if (ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
if (ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
||||||
nat_in_fragments(nat4_tcp_fragments, ip4->ip_src,
|
if ((frag_conn = nat_in_fragments(nat4_tcp_fragments,
|
||||||
ip4->id, connection);
|
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 */
|
/* check if there are any saved fragments */
|
||||||
if ((queue = nat_in_fragments(nat4_saved_fragments,
|
if (frag_conn->queue != NULL) {
|
||||||
ip4->ip_src, ip4->id, NULL)) != NULL) {
|
|
||||||
log_debug("Processing TCP fragments of %d",
|
log_debug("Processing TCP fragments of %d",
|
||||||
ip4->id);
|
ip4->id);
|
||||||
llnode = queue->first.next;
|
llnode = frag_conn->queue->first.next;
|
||||||
while (llnode->next != NULL) {
|
while (llnode->next != NULL) {
|
||||||
llnode = llnode->next;
|
llnode = llnode->next;
|
||||||
memcpy(&tmp_short, llnode->prev->data,
|
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)),
|
sizeof(struct s_ipv4)),
|
||||||
tmp_short);
|
tmp_short);
|
||||||
free(llnode->prev->data);
|
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 {
|
} else {
|
||||||
/* find connection in fragments table */
|
/* find connection in fragments table */
|
||||||
connection = nat_in_fragments(nat4_tcp_fragments, ip4->ip_src,
|
if ((frag_conn = nat_in_fragments(nat4_tcp_fragments,
|
||||||
ip4->id, NULL);
|
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 "
|
log_debug("Incoming connection wasn't found in "
|
||||||
"fragments table -- saving it");
|
"fragments table -- saving it");
|
||||||
|
|
||||||
@ -244,19 +304,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
return 1;
|
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 unsuccessful, create a queue and put into tree */
|
||||||
if (connection == NULL) {
|
if (frag_conn->queue == NULL) {
|
||||||
if ((queue = linkedlist_create()) == NULL) {
|
if ((frag_conn->queue = linkedlist_create()) ==
|
||||||
|
NULL) {
|
||||||
free(saved_packet);
|
free(saved_packet);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
nat_in_fragments(nat4_saved_fragments,
|
|
||||||
ip4->ip_src, ip4->id, queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save the packet and put it into the 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_ethernet) +
|
||||||
sizeof(struct s_ipv4)), payload, payload_size);
|
sizeof(struct s_ipv4)), payload, payload_size);
|
||||||
|
|
||||||
linkedlist_append(queue, saved_packet);
|
linkedlist_append(frag_conn->queue, saved_packet);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -295,7 +349,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
sizeof(struct s_ipv6));
|
sizeof(struct s_ipv6));
|
||||||
|
|
||||||
/* build ethernet header */
|
/* build ethernet header */
|
||||||
eth6->dest = connection->mac;
|
eth6->dest = frag_conn->connection->mac;
|
||||||
eth6->src = mac;
|
eth6->src = mac;
|
||||||
eth6->type = htons(ETHERTYPE_IPV6);
|
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 */
|
/* find connection in NAT */
|
||||||
connection = nat_out(nat6_tcp, nat4_tcp, eth6->src,
|
connection = nat_out(nat6_tcp, nat4_tcp, eth6->src,
|
||||||
ip6->ip_src, ip6->ip_dest,
|
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) {
|
if (connection == NULL) {
|
||||||
log_warn("Outgoing connection wasn't found/created in NAT");
|
log_warn("Outgoing connection wasn't found/created in NAT");
|
||||||
return 1;
|
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 */
|
/* allocate memory for translated packet */
|
||||||
if ((packet = (unsigned char *) malloc(sizeof(struct s_ipv4) +
|
if ((packet = (unsigned char *) malloc(sizeof(struct s_ipv4) +
|
||||||
htons(ip6->len))) == NULL) {
|
htons(ip6->len))) == NULL) {
|
||||||
|
11
src/tcp.h
11
src/tcp.h
@ -19,6 +19,17 @@
|
|||||||
#ifndef TCP_H
|
#ifndef TCP_H
|
||||||
#define 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 */
|
/* TCP header structure */
|
||||||
struct s_tcp {
|
struct s_tcp {
|
||||||
unsigned short port_src; /* 16 b; source port */
|
unsigned short port_src; /* 16 b; source port */
|
||||||
|
15
src/udp.c
15
src/udp.c
@ -26,6 +26,7 @@
|
|||||||
#include "ipv4.h"
|
#include "ipv4.h"
|
||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "linkedlist.h"
|
||||||
#include "nat.h"
|
#include "nat.h"
|
||||||
#include "transmitter.h"
|
#include "transmitter.h"
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
@ -81,6 +82,8 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkedlist_move2end(timeout_udp, connection->llnode);
|
||||||
|
|
||||||
/* allocate memory for translated packet */
|
/* allocate memory for translated packet */
|
||||||
if ((packet = (unsigned char *) malloc(sizeof(struct s_ethernet) +
|
if ((packet = (unsigned char *) malloc(sizeof(struct s_ethernet) +
|
||||||
sizeof(struct s_ipv6) +
|
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 */
|
/* find connection in NAT */
|
||||||
connection = nat_out(nat6_udp, nat4_udp, eth6->src,
|
connection = nat_out(nat6_udp, nat4_udp, eth6->src,
|
||||||
ip6->ip_src, ip6->ip_dest,
|
ip6->ip_src, ip6->ip_dest,
|
||||||
udp->port_src, udp->port_dest);
|
udp->port_src, udp->port_dest, 1);
|
||||||
|
|
||||||
if (connection == NULL) {
|
if (connection == NULL) {
|
||||||
log_warn("Outgoing connection wasn't found/created in NAT!");
|
log_warn("Outgoing connection wasn't found/created in NAT!");
|
||||||
return 1;
|
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 */
|
/* allocate memory for translated packet */
|
||||||
packet_size = sizeof(struct s_ipv4) + htons(ip6->len);
|
packet_size = sizeof(struct s_ipv4) + htons(ip6->len);
|
||||||
if ((packet = (unsigned char *) malloc(packet_size)) == NULL) {
|
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->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
|
||||||
ip4->tos = ((ip6->ver & 0x0f) << 4) |
|
ip4->tos = ((ip6->ver & 0x0f) << 4) |
|
||||||
((ip6->traffic_class & 0xf0) >> 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->id = 0x0;
|
||||||
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
||||||
ip4->ttl = ip6->hop_limit;
|
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));
|
ip4->checksum = checksum(ip4, sizeof(struct s_ipv4));
|
||||||
|
|
||||||
/* send translated packet */
|
/* send translated packet */
|
||||||
transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len));
|
transmit_ipv4(&ip4->ip_dest, packet, packet_size);
|
||||||
|
|
||||||
/* clean-up */
|
/* clean-up */
|
||||||
free(packet);
|
free(packet);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include <stdlib.h> /* srand */
|
#include <stdlib.h> /* srand */
|
||||||
#include <string.h> /* strncpy */
|
#include <string.h> /* strncpy */
|
||||||
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
|
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
|
||||||
#include <time.h> /* time */
|
#include <time.h> /* time, time_t */
|
||||||
#include <unistd.h> /* close */
|
#include <unistd.h> /* close */
|
||||||
|
|
||||||
#include "arp.h"
|
#include "arp.h"
|
||||||
@ -56,13 +56,13 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
struct packet_mreq pmr;
|
struct packet_mreq pmr;
|
||||||
|
|
||||||
struct sockaddr_ll addr;
|
|
||||||
size_t addr_size;
|
|
||||||
|
|
||||||
int sniff_sock;
|
int sniff_sock;
|
||||||
int length;
|
int length;
|
||||||
char buffer[PACKET_BUFFER];
|
char buffer[PACKET_BUFFER];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
time_t prevtime, curtime;
|
||||||
|
|
||||||
log_info(PACKAGE_STRING " is starting");
|
log_info(PACKAGE_STRING " is starting");
|
||||||
|
|
||||||
/* initialize the socket for sniffing */
|
/* initialize the socket for sniffing */
|
||||||
@ -123,15 +123,27 @@ int main(int argc, char **argv)
|
|||||||
/* initiate random numbers generator */
|
/* initiate random numbers generator */
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
|
|
||||||
|
/* initialize time */
|
||||||
|
prevtime = time(NULL);
|
||||||
|
|
||||||
/* sniff! :c) */
|
/* sniff! :c) */
|
||||||
for (;;) {
|
for (i = 1;; i++) {
|
||||||
addr_size = sizeof(addr);
|
|
||||||
if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) == -1) {
|
if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) == -1) {
|
||||||
log_error("Unable to retrieve data from socket");
|
log_error("Unable to retrieve data from socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
process((char *) &buffer);
|
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 */
|
/* clean-up */
|
||||||
|
Loading…
Reference in New Issue
Block a user