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

Fragmenting of too big TCPv4 packets

This commit is contained in:
Michal Zima 2012-04-26 13:50:13 +02:00
parent 32deb4f0ee
commit b28566bc64
3 changed files with 148 additions and 62 deletions

View File

@ -21,6 +21,8 @@
#include "ethernet.h" /* s_ethernet */ #include "ethernet.h" /* s_ethernet */
#define IPV6_FLAG_MORE_FRAGMENTS 0x0001
/* IPv6 address structure */ /* IPv6 address structure */
struct s_ipv6_addr { struct s_ipv6_addr {
unsigned char addr[16]; unsigned char addr[16];
@ -38,6 +40,17 @@ struct s_ipv6 {
struct s_ipv6_addr ip_dest; /* 128 b; destination address */ struct s_ipv6_addr ip_dest; /* 128 b; destination address */
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
/* IPv6 fragment header structure */
struct s_ipv6_fragment {
unsigned char next_header; /* 8 b; next header */
unsigned char zeros; /* 8 b; reserved */
unsigned short offset_flag; /* 13 b; fragment offset in B,
2 b; reserved,
1 b; flag */
unsigned int id; /* 32 b; id of the packet
(for fragmentation) */
} __attribute__ ((__packed__));
/* IPv6 pseudoheader structure for checksum */ /* IPv6 pseudoheader structure for checksum */
struct s_ipv6_pseudo { struct s_ipv6_pseudo {
struct s_ipv6_addr ip_src; /* 128 b; source address */ struct s_ipv6_addr ip_src; /* 128 b; source address */

195
src/tcp.c
View File

@ -52,78 +52,149 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
unsigned short orig_checksum; unsigned short orig_checksum;
unsigned char *packet; unsigned char *packet;
struct s_ethernet *eth6; struct s_ethernet *eth6;
struct s_ipv6 *ip6; struct s_ipv6 *ip6;
struct s_ipv6_fragment *frag;
/* parse TCP header */ /* full processing of unfragmented packet or the first fragment with
tcp = (struct s_tcp *) payload; * TCP header with checksum field (this is safe)
*/
if ((ip4->flags_offset & htons(IPV4_FLAG_DONT_FRAGMENT)) ||
((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) &&
(ip4->flags_offset & 0xff1f) == 0x0000 &&
payload_size >= sizeof(struct s_tcp) - 2)) {
/* parse TCP header */
tcp = (struct s_tcp *) payload;
/* checksum recheck */ /* checksum recheck -- only if the packet is unfragmented */
if (tcp->checksum != 0x0000) { if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) ==
orig_checksum = tcp->checksum; htons(IPV4_FLAG_DONT_FRAGMENT)) {
tcp->checksum = 0; orig_checksum = tcp->checksum;
tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest, tcp->checksum = 0;
payload_size, IPPROTO_TCP, tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
(unsigned char *) tcp); payload_size, IPPROTO_TCP,
(unsigned char *) tcp);
if (tcp->checksum != orig_checksum) { if (tcp->checksum != orig_checksum) {
/* packet is corrupted and shouldn't be processed */ /* packet is corrupted and shouldn't be
printf("[Debug] Wrong checksum\n"); * 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; return 1;
} }
}
/* find connection in NAT */ /* allocate enough memory for translated packet */
connection = nat_in(nat4_tcp, ip4->ip_src, tcp->port_src, tcp->port_dest); if ((packet = (unsigned char *) malloc(
payload_size > MTU - sizeof(struct s_ipv6) ?
MTU + sizeof(struct s_ethernet) :
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));
if (connection == NULL) { /* build ethernet header */
printf("[Debug] Incoming connection wasn't found in NAT\n"); eth6->dest = connection->mac;
eth6->src = mac;
eth6->type = htons(ETHERTYPE_IPV6);
/* build IPv6 header */
ip6->ver = 0x60 | (ip4->tos >> 4);
ip6->traffic_class = ip4->tos << 4;
ip6->flow_label = 0x0;
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 = checksum_ipv6_update(tcp->checksum,
ip4->ip_src, ip4->ip_dest,
connection->ipv4_port_src,
ip6->ip_src, ip6->ip_dest,
connection->ipv6_port_src);
/* fragment it or not? */
if (payload_size > MTU - sizeof(struct s_ipv6)) {
/* 1st fragments' payload size must be 8-byte aligned */
#define FRAGMENT_LEN (((MTU - sizeof(struct s_ipv6) - \
sizeof(struct s_ipv6_fragment)) / 8) * 8)
/* fill in missing IPv6 header fields */
ip6->len = htons(FRAGMENT_LEN +
sizeof(struct s_ipv6_fragment));
ip6->next_header = IPPROTO_FRAGMENT;
/* create IPv6 fragment header */
frag = (struct s_ipv6_fragment *) ((unsigned char *) ip6
+ sizeof(struct s_ipv6));
frag->next_header = IPPROTO_TCP;
frag->zeros = 0x0;
frag->offset_flag = htons(IPV6_FLAG_MORE_FRAGMENTS);
frag->id = ip4->id ? htonl(htons(ip4->id)) :
(unsigned int) rand();
/* copy the payload data */
memcpy((unsigned char *) frag +
sizeof(struct s_ipv6_fragment),
payload, FRAGMENT_LEN);
/* send translated packet */
transmit_raw(packet, sizeof(struct s_ethernet) +
sizeof(struct s_ipv6) +
sizeof(struct s_ipv6_fragment) +
FRAGMENT_LEN);
/* create the second fragment */
ip6->len = htons(payload_size +
sizeof(struct s_ipv6_fragment) -
FRAGMENT_LEN);
frag->offset_flag = htons((FRAGMENT_LEN / 8) << 3);
/* copy the payload data */
memcpy((unsigned char *) frag +
sizeof(struct s_ipv6_fragment),
payload + FRAGMENT_LEN,
payload_size - FRAGMENT_LEN);
/* send translated packet */
transmit_raw(packet, sizeof(struct s_ethernet) +
sizeof(struct s_ipv6) +
sizeof(struct s_ipv6_fragment) -
FRAGMENT_LEN + payload_size);
} else {
ip6->len = htons(payload_size);
ip6->next_header = IPPROTO_TCP;
/* copy the payload data */
memcpy((unsigned char *) ip6 + sizeof(struct s_ipv6),
payload, payload_size);
/* send translated packet */
transmit_raw(packet, sizeof(struct s_ethernet) +
sizeof(struct s_ipv6) + payload_size);
}
} else {
/* TODO: handle all fragments */
printf("[Debug] Can't handle fragments :c(\n");
return 1; 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 = checksum_ipv6_update(tcp->checksum,
ip4->ip_src, ip4->ip_dest,
connection->ipv4_port_src,
ip6->ip_src, ip6->ip_dest,
connection->ipv6_port_src);
/* 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 */ /* clean-up */
free(packet); free(packet);

View File

@ -22,6 +22,8 @@
#include "ipv4.h" #include "ipv4.h"
#include "ipv6.h" #include "ipv6.h"
#define MTU 1280
extern struct ifreq interface; extern struct ifreq interface;
extern struct s_mac_addr mac; extern struct s_mac_addr mac;
extern struct s_ipv6_addr ndp_multicast_addr; extern struct s_ipv6_addr ndp_multicast_addr;