From 88882ea5ca2318a20be637a1a81cf03bd5d92cc9 Mon Sep 17 00:00:00 2001 From: Michal Zima Date: Sat, 7 Apr 2012 11:49:26 +0200 Subject: [PATCH] Processing of TCP packets --- src/Makefile.am | 1 + src/ipv4.c | 3 +- src/ipv6.c | 3 +- src/tcp.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tcp.h | 40 +++++++++ src/udp.c | 1 - 6 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 src/tcp.c create mode 100644 src/tcp.h diff --git a/src/Makefile.am b/src/Makefile.am index 64d2053..e1c8204 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,7 @@ wrapsix_wrapper_SOURCES = \ ipv6.c ipv6.h \ nat.c nat.h \ radixtree.c radixtree.h \ + tcp.c tcp.h \ transmitter.c transmitter.h \ udp.c udp.h \ wrapper.c wrapper.h diff --git a/src/ipv4.c b/src/ipv4.c index 812d4d7..e314ec0 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -22,6 +22,7 @@ #include "icmp.h" #include "ipv4.h" +#include "tcp.h" #include "udp.h" #include "wrapper.h" @@ -51,7 +52,7 @@ int ipv4(struct s_ethernet *eth, char *packet) switch (ip->proto) { case IPPROTO_TCP: printf("[Debug] IPv4 Protocol: TCP\n"); - /*ipv4_tcp(eth, ip, payload, data_size);*/ + tcp_ipv4(eth, ip, payload, data_size); break; case IPPROTO_UDP: printf("[Debug] IPv4 Protocol: UDP\n"); diff --git a/src/ipv6.c b/src/ipv6.c index 7e11a98..0d16ef9 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -22,6 +22,7 @@ #include "icmp.h" #include "ipv6.h" +#include "tcp.h" #include "udp.h" #include "wrapper.h" @@ -44,7 +45,7 @@ int ipv6(struct s_ethernet *eth, char *packet) switch (ip->next_header) { case IPPROTO_TCP: printf("[Debug] IPv6 Protocol: TCP\n"); - /*ipv6_tcp(eth, ip, payload);*/ + tcp_ipv6(eth, ip, payload); break; case IPPROTO_UDP: printf("[Debug] IPv6 Protocol: UDP\n"); diff --git a/src/tcp.c b/src/tcp.c new file mode 100644 index 0000000..3db4a8a --- /dev/null +++ b/src/tcp.c @@ -0,0 +1,220 @@ +/* + * WrapSix + * Copyright (C) 2008-2012 Michal Zima + * + * 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 . + */ + +#include /* ETHERTYPE_* */ +#include /* htons */ +#include +#include /* malloc */ +#include /* memcpy */ + +#include "checksum.h" +#include "ethernet.h" +#include "ipv4.h" +#include "ipv6.h" +#include "nat.h" +#include "tcp.h" +#include "transmitter.h" +#include "wrapper.h" + +/** + * Processing of incoming TCPv4 packets. Directly sends translated TCPv6 + * packets. + * + * @param eth4 Ethernet header + * @param ip4 IPv4 header + * @param payload TCPv4 data + * @param payload_size Size of payload; needed because IPv4 header has + * dynamic length + * + * @return 0 for success + * @return 1 for failure + */ +int tcp_ipv4(struct s_ethernet *eth, struct s_ipv4 *ip4, char *payload, + unsigned short payload_size) +{ + struct s_tcp *tcp; + struct s_nat *connection; + unsigned short orig_checksum; + unsigned char *packet; + + struct s_ethernet *eth6; + struct s_ipv6 *ip6; + + /* parse TCP header */ + tcp = (struct s_tcp *) payload; + + /* checksum recheck */ + if (tcp->checksum != 0x0000) { + orig_checksum = tcp->checksum; + tcp->checksum = 0; + tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest, + payload_size, IPPROTO_TCP, + (unsigned char *) tcp); + + if (tcp->checksum != orig_checksum) { + /* packet is corrupted and shouldn't be processed */ + printf("[Debug] Wrong checksum\n"); + return 1; + } + } + + /* find connection in NAT */ + connection = nat_in(nat4_tcp, ip4->ip_src, tcp->port_src, tcp->port_dest); + + if (connection == NULL) { + printf("[Debug] Incoming connection wasn't found in NAT\n"); + return 1; + } + + /* allocate memory for translated packet */ + if ((packet = (unsigned char *) malloc(sizeof(struct s_ethernet) + + sizeof(struct s_ipv6) + + payload_size)) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return 1; + } + eth6 = (struct s_ethernet *) packet; + ip6 = (struct s_ipv6 *) (packet + sizeof(struct s_ethernet)); + + /* build ethernet header */ + eth6->dest = connection->mac; + eth6->src = mac; + eth6->type = htons(ETHERTYPE_IPV6); + + /* build IPv6 packet */ + ip6->ver = 0x60; + ip6->traffic_class = 0x0; + ip6->flow_label = 0x0; + ip6->len = htons(payload_size); + ip6->next_header = IPPROTO_TCP; + ip6->hop_limit = ip4->ttl; + ipv4_to_ipv6(&ip4->ip_src, &ip6->ip_src); + memcpy(&ip6->ip_dest, &connection->ipv6, sizeof(struct s_ipv6_addr)); + + /* set incoming source port */ + tcp->port_dest = connection->ipv6_port_src; + + /* compute TCP checksum */ + tcp->checksum = 0x0; + tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size, + IPPROTO_TCP, (unsigned char *) tcp); + + /* copy the payload data (with new checksum) */ + memcpy(packet + sizeof(struct s_ethernet) + sizeof(struct s_ipv6), + payload, payload_size); + + /* send translated packet */ + transmit_raw(packet, sizeof(struct s_ethernet) + sizeof(struct s_ipv6) + + payload_size); + + /* clean-up */ + free(packet); + + return 0; +} + +/** + * Processing of outgoing TCPv6 packets. Directly sends translated TCPv4 + * packets. + * + * @param eth6 Ethernet header + * @param ip6 IPv6 header + * @param payload TCPv6 data + * + * @return 0 for success + * @return 1 for failure + */ +int tcp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload) +{ + struct s_tcp *tcp; + struct s_nat *connection; + unsigned short orig_checksum; + struct s_ipv4 *ip4; + unsigned char *packet; + unsigned int packet_size; + + /* parse TCP header */ + tcp = (struct s_tcp *) payload; + + /* checksum recheck */ + orig_checksum = tcp->checksum; + tcp->checksum = 0; + tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, + htons(ip6->len), IPPROTO_TCP, + (unsigned char *) payload); + + if (tcp->checksum != orig_checksum) { + /* packet is corrupted and shouldn't be processed */ + printf("[Debug] Wrong checksum\n"); + return 1; + } + + /* find connection in NAT */ + connection = nat_out(nat6_tcp, nat4_tcp, eth->src, + ip6->ip_src, ip6->ip_dest, + tcp->port_src, tcp->port_dest); + + if (connection == NULL) { + printf("[Debug] Error! Outgoing connection wasn't " + "found/created in NAT!\n"); + return 1; + } + + /* allocate memory for translated packet */ + packet_size = sizeof(struct s_ipv4) + ip6->len; + if ((packet = (unsigned char *) malloc(packet_size)) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return 1; + } + ip4 = (struct s_ipv4 *) packet; + + /* build IPv4 packet */ + ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */ + ip4->tos = 0x0; + ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len)); + ip4->id = 0x0; + ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT); + ip4->ttl = ip6->hop_limit; + ip4->proto = IPPROTO_TCP; + ipv6_to_ipv4(&ip6->ip_dest, &ip4->ip_dest); + memcpy(&ip4->ip_src, &wrapsix_ipv4_addr, sizeof(struct s_ipv4_addr)); + + /* set outgoing source port */ + tcp->port_src = connection->ipv4_port_src; + + /* compute TCP checksum */ + tcp->checksum = 0; + tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest, + htons(ip6->len), IPPROTO_TCP, + (unsigned char *) tcp); + + /* copy the payload data (with new checksum) */ + memcpy(packet + sizeof(struct s_ipv4), payload, htons(ip6->len)); + + /* compute IPv4 checksum */ + ip4->checksum = 0x0; + ip4->checksum = checksum(ip4, sizeof(struct s_ipv4)); + + /* send translated packet */ + transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len)); + + /* clean-up */ + free(packet); + + return 0; +} diff --git a/src/tcp.h b/src/tcp.h new file mode 100644 index 0000000..a5f51cd --- /dev/null +++ b/src/tcp.h @@ -0,0 +1,40 @@ +/* + * WrapSix + * Copyright (C) 2008-2012 Michal Zima + * + * 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 . + */ + +#ifndef TCP_H +#define TCP_H + +/* TCP header structure */ +struct s_tcp { + unsigned short port_src; /* 16 b; source port */ + unsigned short port_dest; /* 16 b; destination port */ + unsigned int seq; /* 32 b; sequence number */ + unsigned int ack; /* 32 b; acknowledgement number */ + unsigned char offset; /* 4 b; data offset + 6 b; reserved (zeros) */ + unsigned char flags; /* 6 b; flags */ + unsigned short window; /* 16 b; size of the receive window */ + unsigned short checksum; /* 16 b */ + unsigned short urgent_ptr; /* 16 b; ptr to last urgent data byte */ +} __attribute__ ((__packed__)); + +int tcp_ipv4(struct s_ethernet *eth, struct s_ipv4 *ip4, char *payload, + unsigned short payload_size); +int tcp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload); + +#endif /* TCP_H */ diff --git a/src/udp.c b/src/udp.c index 4d58889..04d4dad 100644 --- a/src/udp.c +++ b/src/udp.c @@ -211,7 +211,6 @@ int udp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload) ip4->checksum = checksum(ip4, sizeof(struct s_ipv4)); /* send translated packet */ - printf("[Debug] transmitting\n"); transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len)); /* clean-up */