1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-11-08 23:31:00 +02:00
wrapsix/src/nat.c

150 lines
4.5 KiB
C
Raw Normal View History

2010-02-22 15:55:18 +02:00
/*
* WrapSix
* Copyright (C) 2008-2011 Michal Zima <xhire@mujmalysvet.cz>
2010-02-22 15:55:18 +02:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h> /* malloc */
#include <time.h> /* time */
#include "ethernet.h"
#include "ipv4.h"
#include "ipv6.h"
#include "nat.h"
2010-02-22 15:55:18 +02:00
#include "radixtree.h"
#include "wrapper.h"
2010-02-22 15:55:18 +02:00
struct s_radixtree_nat6 {
struct s_ipv6_addr ipv6;
struct s_ipv4_addr ipv4;
unsigned short port_src;
unsigned short port_dst;
} __attribute__ ((__packed__));
struct s_radixtree_nat4 {
struct s_ipv4_addr addr;
unsigned short port_src;
unsigned short port_dst;
unsigned char zeros; /* unused space */
} __attribute__ ((__packed__));
radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp,
*nat4_tcp, *nat4_udp, *nat4_icmp;
void nat_init(void)
2010-02-22 15:55:18 +02:00
{
nat6_tcp = radixtree_create();
nat6_udp = radixtree_create();
nat6_icmp = radixtree_create();
nat4_tcp = radixtree_create();
nat4_udp = radixtree_create();
nat4_icmp = radixtree_create();
}
void nat_quit(void)
2010-02-22 15:55:18 +02:00
{
/* 128 + 16 + 32 + 16 = 192 / 6 = 32 */
radixtree_destroy(nat6_tcp, 32);
radixtree_destroy(nat6_udp, 32);
radixtree_destroy(nat6_icmp, 32);
2010-02-22 15:55:18 +02:00
/* 32 + 16 + 16 + 8 = 72 / 6 = 12 */
radixtree_destroy(nat4_tcp, 12);
radixtree_destroy(nat4_udp, 12);
radixtree_destroy(nat4_icmp, 12);
2010-02-22 15:55:18 +02:00
}
struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
struct s_mac_addr eth_src,
2010-02-22 15:55:18 +02:00
struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst,
unsigned short port_src, unsigned short port_dst)
{
struct s_nat *result, *connection;
2010-02-22 15:55:18 +02:00
struct s_radixtree_nat4 radixsearch4;
2010-02-22 15:55:18 +02:00
struct s_radixtree_nat6 radixsearch6;
/* create structure to search in the tree */
2010-02-22 15:55:18 +02:00
radixsearch6.ipv6 = ipv6_src;
ipv6_to_ipv4(&ipv6_dst, &radixsearch6.ipv4);
2010-02-22 15:55:18 +02:00
radixsearch6.port_src = port_src;
radixsearch6.port_dst = port_dst;
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) {
2010-02-22 15:55:18 +02:00
fprintf(stderr, "[Error] Lack of free memory\n");
return NULL;
}
connection->mac = eth_src;
2010-02-22 15:55:18 +02:00
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);
2010-02-22 15:55:18 +02:00
radixsearch4.addr = radixsearch6.ipv4;
radixsearch4.port_src = port_dst;
radixsearch4.zeros = 0x0;
2010-02-22 15:55:18 +02:00
/* generate some outgoing port */
do {
/* returns port from range 1024 - 65535 */
radixsearch4.port_dst = (rand() % 64511) + 1024;
2010-02-22 15:55:18 +02:00
result = radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4));
2010-02-22 15:55:18 +02:00
} while (result != NULL);
connection->ipv4_port_src = radixsearch4.port_dst;
2010-02-22 15:55:18 +02:00
/* 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);
2010-02-22 15:55:18 +02:00
return connection;
} else {
/* when connection is found, refresh it and return */
2010-02-22 15:55:18 +02:00
result->last_packet = time(NULL);
return result;
}
}
struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
2010-02-22 15:55:18 +02:00
unsigned short port_src, unsigned short port_dst)
{
struct s_nat *result;
2010-02-22 15:55:18 +02:00
/* create structure to search in the tree */
struct s_radixtree_nat4 radixsearch4;
radixsearch4.addr = ipv4_src;
radixsearch4.port_src = port_src;
radixsearch4.port_dst = port_dst;
radixsearch4.zeros = 0x0;
if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, radixtree_chunker, &radixsearch4, sizeof(radixsearch4))) == NULL) {
/* when connection is not found, drop the packet */
2010-02-22 15:55:18 +02:00
return NULL;
} else {
/* when connection is found, refresh it and return */
2010-02-22 15:55:18 +02:00
result->last_packet = time(NULL);
return result;
}
}