1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-09-19 23:11:04 +03:00

Saving and processing unknown incoming fragments

New data structure -- linked list
Reduced few useless debug outputs
This commit is contained in:
Michal Zima 2012-07-14 11:38:13 +02:00
parent b9c6d5c46a
commit 24b09b4d93
9 changed files with 246 additions and 40 deletions

View File

@ -7,6 +7,7 @@ wrapsix_wrapper_SOURCES = \
icmp.c icmp.h \ icmp.c icmp.h \
ipv4.c ipv4.h \ ipv4.c ipv4.h \
ipv6.c ipv6.h \ ipv6.c ipv6.h \
linkedlist.c linkedlist.h \
log.c log.h \ log.c log.h \
nat.c nat.h \ nat.c nat.h \
radixtree.c radixtree.h \ radixtree.c radixtree.h \

View File

@ -47,7 +47,6 @@ int ipv4(struct s_ethernet *eth, char *packet)
/* test if this packet belongs to us */ /* test if this packet belongs to us */
if (memcmp(&wrapsix_ipv4_addr, &ip->ip_dest, 4) != 0) { if (memcmp(&wrapsix_ipv4_addr, &ip->ip_dest, 4) != 0) {
log_debug("This is unfamiliar IPv4 packet");
return 1; return 1;
} }

View File

@ -47,7 +47,6 @@ int ipv6(struct s_ethernet *eth, char *packet)
/* test if this packet belongs to us */ /* test if this packet belongs to us */
if (memcmp(&wrapsix_ipv6_prefix, &ip->ip_dest, 12) != 0 && if (memcmp(&wrapsix_ipv6_prefix, &ip->ip_dest, 12) != 0 &&
memcmp(&ndp_multicast_addr, &ip->ip_dest, 13) != 0) { memcmp(&ndp_multicast_addr, &ip->ip_dest, 13) != 0) {
log_debug("This is unfamiliar IPv6 packet");
return 1; return 1;
} }

104
src/linkedlist.c Normal file
View File

@ -0,0 +1,104 @@
/*
* WrapSix
* Copyright (C) 2008-2012 Michal Zima <xhire@mujmalysvet.cz>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h> /* free, malloc */
#include "linkedlist.h"
#include "log.h"
/**
* Creates root of a linked list.
*
* @return Root of new linked list
*/
linkedlist_t *linkedlist_create(void)
{
linkedlist_t *linkedlist;
if ((linkedlist = (linkedlist_t *) malloc(sizeof(linkedlist_t))) ==
NULL) {
log_error("Lack of free memory");
return NULL;
}
linkedlist->first.prev = NULL;
linkedlist->first.next = &linkedlist->last;
linkedlist->last.prev = &linkedlist->first;
linkedlist->last.next = NULL;
return linkedlist;
}
/**
* Destroys a linked list.
*
* @param root Root of the linked list to destroy
*/
void linkedlist_destroy(linkedlist_t *root)
{
linkedlist_node_t *tmp;
tmp = root->first.next;
while (tmp->next != NULL) {
tmp = tmp->next;
free(tmp->prev);
}
}
/**
* Append new node at the end of the linked list.
*
* @param root Root of the linked list
* @param data Data to append to the list
*
* @return 0 for success
* @return 1 for failure
*/
int 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;
}
node->data = data;
node->prev = root->last.prev;
node->next = &root->last;
root->last.prev->next = node;
root->last.prev = node;
return 0;
}
/**
* Delete node from beginning of linked list.
*
* @param root Root of the linked list
* @param node Node to delete from the list
*/
void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node)
{
root->first.next = node->next;
node->next->prev = node->prev;
free(node);
node = NULL;
}

40
src/linkedlist.h Normal file
View File

@ -0,0 +1,40 @@
/*
* WrapSix
* Copyright (C) 2008-2012 Michal Zima <xhire@mujmalysvet.cz>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
/* Linked list node structure */
typedef struct s_linkedlist_node {
struct s_linkedlist_node *prev;
struct s_linkedlist_node *next;
void *data;
} linkedlist_node_t;
/* Linked list root structure */
typedef struct s_linkedlist {
linkedlist_node_t first;
linkedlist_node_t last;
} linkedlist_t;
linkedlist_t *linkedlist_create(void);
void linkedlist_destroy(linkedlist_t *root);
int linkedlist_append(linkedlist_t *root, void *data);
void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node);
#endif /* LINKEDLIST_H */

View File

@ -48,7 +48,7 @@ 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_tcp_fragments, *nat4_saved_fragments;
/** /**
* Initialization of NAT tables. * Initialization of NAT tables.
@ -64,6 +64,7 @@ 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();
} }
/** /**
@ -83,6 +84,7 @@ 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);
} }
/** /**
@ -191,42 +193,41 @@ struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
} }
/** /**
* Save and retrieve NATted connections via fragment identification. * Save and retrieve data (e.g. NATted connections) 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 nat Connection to save * @param data Data to save
* *
* @return Connection * @return Data (or NULL when nothing found)
*/ */
struct s_nat *nat_in_fragments(radixtree_t *nat_proto4, void *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
struct s_ipv4_addr ipv4_src, unsigned short id, void *data)
unsigned short id, struct s_nat *nat)
{ {
struct s_nat *result; void *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;
radixsearch4.addr = ipv4_src; radixsearch4.addr = ipv4_src;
radixsearch4.id = id; radixsearch4.id = id;
if ((result = (struct s_nat *) radixtree_lookup(nat_proto4, if ((result = radixtree_lookup(nat_proto4, radixtree_chunker,
radixtree_chunker, &radixsearch4, sizeof(radixsearch4))) == NULL) { &radixsearch4, sizeof(radixsearch4))) == NULL) {
if (nat != NULL) { if (data != NULL) {
/* when fragmentation is not found, add one */ /* when fragmentation is not found, add one */
radixtree_insert(nat_proto4, radixtree_chunker, radixtree_insert(nat_proto4, radixtree_chunker,
&radixsearch4, sizeof(radixsearch4), &radixsearch4, sizeof(radixsearch4),
nat); data);
return nat; return data;
} else { } else {
/* nothing found and nothing to be added */ /* nothing found and nothing to be added */
return NULL; return NULL;
} }
} else { } else {
if (nat != NULL) { if (data != NULL) {
/* when fragmentation is found, is it the same? */ /* when fragmentation is found, is it the same? */
if (result == nat) { if (result == data) {
/* OK, return */ /* OK, return */
return result; return result;
} else { } else {
@ -238,12 +239,10 @@ struct s_nat *nat_in_fragments(radixtree_t *nat_proto4,
sizeof(radixsearch4)); sizeof(radixsearch4));
radixtree_insert(nat_proto4, radixtree_chunker, radixtree_insert(nat_proto4, radixtree_chunker,
&radixsearch4, &radixsearch4,
sizeof(radixsearch4), nat); sizeof(radixsearch4), data);
return nat; return data;
} }
} else { } else {
/* refresh it's connection and return */
result->last_packet = time(NULL);
return result; return result;
} }
} }

View File

@ -39,7 +39,7 @@ struct s_nat {
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_tcp_fragments, *nat4_saved_fragments;
void nat_init(void); void nat_init(void);
void nat_quit(void); void nat_quit(void);
@ -50,9 +50,8 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4,
unsigned short port_src, unsigned short port_dst); unsigned short port_src, unsigned short port_dst);
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);
struct s_nat *nat_in_fragments(radixtree_t *nat_proto4, void *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src,
struct s_ipv4_addr ipv4_src, unsigned short id, void *data);
unsigned short id, struct s_nat *nat);
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);

View File

@ -25,6 +25,7 @@
#include "ethernet.h" #include "ethernet.h"
#include "ipv4.h" #include "ipv4.h"
#include "ipv6.h" #include "ipv6.h"
#include "linkedlist.h"
#include "log.h" #include "log.h"
#include "nat.h" #include "nat.h"
#include "tcp.h" #include "tcp.h"
@ -49,9 +50,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
{ {
struct s_tcp *tcp; struct s_tcp *tcp;
struct s_nat *connection; struct s_nat *connection;
unsigned short orig_checksum; unsigned short tmp_short;
unsigned char *packet; unsigned char *packet;
unsigned char *saved_packet;
linkedlist_t *queue;
linkedlist_node_t *llnode;
struct s_ethernet *eth6; struct s_ethernet *eth6;
struct s_ipv6 *ip6; struct s_ipv6 *ip6;
struct s_ipv6_fragment *frag; struct s_ipv6_fragment *frag;
@ -59,7 +64,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
/* full processing of unfragmented packet or the first fragment with /* full processing of unfragmented packet or the first fragment with
* TCP header * TCP header
*/ */
if ((ip4->flags_offset & htons(IPV4_FLAG_DONT_FRAGMENT)) || if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) ==
htons(IPV4_FLAG_DONT_FRAGMENT) ||
((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) && ((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) &&
(ip4->flags_offset & 0xff1f) == 0x0000 && (ip4->flags_offset & 0xff1f) == 0x0000 &&
payload_size >= sizeof(struct s_tcp))) { payload_size >= sizeof(struct s_tcp))) {
@ -69,13 +75,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
/* checksum recheck -- only if the packet is unfragmented */ /* checksum recheck -- only if the packet is unfragmented */
if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) == if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) ==
htons(IPV4_FLAG_DONT_FRAGMENT)) { htons(IPV4_FLAG_DONT_FRAGMENT)) {
orig_checksum = tcp->checksum; tmp_short = tcp->checksum;
tcp->checksum = 0; tcp->checksum = 0;
tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest, tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
payload_size, IPPROTO_TCP, payload_size, IPPROTO_TCP,
(unsigned char *) tcp); (unsigned char *) tcp);
if (tcp->checksum != orig_checksum) { if (tcp->checksum != tmp_short) {
/* packet is corrupted and shouldn't be /* packet is corrupted and shouldn't be
* processed */ * processed */
log_debug("Wrong checksum"); log_debug("Wrong checksum");
@ -96,6 +102,34 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
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, nat_in_fragments(nat4_tcp_fragments, ip4->ip_src,
ip4->id, connection); ip4->id, connection);
/* check if there are any saved fragments */
if ((queue = nat_in_fragments(nat4_saved_fragments,
ip4->ip_src, ip4->id, NULL)) != NULL) {
log_debug("Processing TCP fragments of %d",
ip4->id);
llnode = queue->first.next;
while (llnode->next != NULL) {
llnode = llnode->next;
memcpy(&tmp_short, llnode->prev->data,
sizeof(unsigned short));
tcp_ipv4((struct s_ethernet *) (
(char *) llnode->prev->data +
sizeof(unsigned short)),
(struct s_ipv4 *) (
(char *) llnode->prev->data +
sizeof(unsigned short) +
sizeof(struct s_ethernet)),
(char *) (
(char *) llnode->prev->data +
sizeof(unsigned short) +
sizeof(struct s_ethernet) +
sizeof(struct s_ipv4)),
tmp_short);
free(llnode->prev->data);
linkedlist_delete(queue, llnode->prev);
}
}
} }
/* allocate enough memory for translated packet */ /* allocate enough memory for translated packet */
@ -201,8 +235,48 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
if (connection == NULL) { if (connection == NULL) {
log_debug("Incoming connection wasn't found in " log_debug("Incoming connection wasn't found in "
"fragments table"); "fragments table -- saving it");
return 1;
if ((saved_packet = (unsigned char *) malloc(
sizeof(unsigned short) + sizeof(struct s_ethernet) +
sizeof(struct s_ipv4) + payload_size)) == NULL) {
log_error("Lack of free memory");
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) {
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 */
memcpy(saved_packet, &payload_size,
sizeof(unsigned short));
memcpy((unsigned char *) (saved_packet +
sizeof(unsigned short)), eth4,
sizeof(struct s_ethernet));
memcpy((unsigned char *) (saved_packet +
sizeof(unsigned short) +
sizeof(struct s_ethernet)), ip4,
sizeof(struct s_ipv4));
memcpy((unsigned char *) (saved_packet +
sizeof(unsigned short) +
sizeof(struct s_ethernet) +
sizeof(struct s_ipv4)), payload, payload_size);
linkedlist_append(queue, saved_packet);
return 0;
} }
/* allocate enough memory for translated packet */ /* allocate enough memory for translated packet */
@ -307,13 +381,6 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
sizeof(struct s_ipv6_fragment) + sizeof(struct s_ipv6_fragment) +
payload_size); payload_size);
} }
/* if this is the last fragment, remove the entry from table */
if (!(ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS))) {
log_debug("Removing fragment entry");
nat_in_fragments_cleanup(nat4_tcp_fragments,
ip4->ip_src, ip4->id);
}
} }
/* clean-up */ /* clean-up */

View File

@ -164,10 +164,8 @@ int process(char *packet)
switch (htons(eth->type)) { switch (htons(eth->type)) {
case ETHERTYPE_IP: case ETHERTYPE_IP:
log_debug("HW Protocol: IPv4");
return ipv4(eth, payload); return ipv4(eth, payload);
case ETHERTYPE_IPV6: case ETHERTYPE_IPV6:
log_debug("HW Protocol: IPv6");
return ipv6(eth, payload); return ipv6(eth, payload);
case ETHERTYPE_ARP: case ETHERTYPE_ARP:
log_debug("HW Protocol: ARP"); log_debug("HW Protocol: ARP");