1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-11-10 00:01:01 +02:00

Completed TCP with fragmenting in IPv6 packets

Modified TCP in 6to4 way to use special IP address
This commit is contained in:
xHire 2009-01-10 19:15:49 +01:00
parent 32e7d6459b
commit e7d8a4c1dd
5 changed files with 210 additions and 80 deletions

View File

@ -39,10 +39,47 @@ void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, u
close(sock);
}
void send_raw_ipv4(struct in_addr ip4_addr, unsigned char *packet, int packet_size)
{
struct sockaddr_in socket_address;
unsigned char on = 1;
int sock;
/* prepare data for RAW socket */
socket_address.sin_family = AF_INET;
socket_address.sin_port = htons(0);
memcpy(&socket_address.sin_addr.s_addr, &ip4_addr, sizeof(struct in_addr));
/* initialize raw socket */
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
fprintf(stderr, "Couldn't open RAW socket.\n");
perror("socket()");
exit(EXIT_FAILURE);
}
/* we will provide our own IPv4 header */
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
fprintf(stderr, "Couldn't apply the socket settings.\n");
perror("setsockopt()");
exit(EXIT_FAILURE);
}
/* send the packet */
if (sendto(sock, packet, packet_size, 0, (struct sockaddr *) &socket_address, sizeof(struct sockaddr)) != packet_size) {
fprintf(stderr, "Couldn't send a RAW packet.\n");
perror("sendto()");
exit(EXIT_FAILURE);
}
/* close the socket */
close(sock);
}
void send_raw(unsigned char *packet, int packet_size)
{
struct sockaddr_ll socket_address; /* target address */
struct ifreq ifr; /* interface */
struct sockaddr_ll socket_address;
struct ifreq ifr;
int sock;
@ -72,9 +109,9 @@ void send_raw(unsigned char *packet, int packet_size)
exit(EXIT_FAILURE);
}
/* send the NDP packet */
/* send the packet */
if (sendto(sock, packet, packet_size, 0, (struct sockaddr *) &socket_address, sizeof(struct sockaddr_ll)) != packet_size) {
fprintf(stderr, " Error: Couldn't send an IPv6 packet.\n");
fprintf(stderr, "Couldn't send a RAW packet.\n");
perror("sendto()");
exit(EXIT_FAILURE);
}

View File

@ -5,8 +5,6 @@
#include "translate_ip.h"
#include "storage.h"
struct in6_addr ip6addr_wrapsix;
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
const struct s_ethernet *eth; /* the ethernet header */
@ -30,7 +28,7 @@ void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char
process_arp(eth, payload);
break;
default:
printf("\n IP: unknown (%d/0x%x)\n", htons(eth->type), htons(eth->type));
printf("\n Proto: unknown (%d/0x%x)\n", htons(eth->type), htons(eth->type));
break;
}
}
@ -55,7 +53,7 @@ void process_packet4(const struct s_ethernet *eth, const unsigned char *packet)
printf(" To: %s\n", inet_ntoa(ip->ip_dest));
/* check if this packet is ours */
if (memcmp(dev_ip, &ip->ip_dest, 4)) {
if (memcmp(&ip4addr_wrapsix, &ip->ip_dest, 4)) {
printf("==> This packet is not ours! <==\n");
return;
}
@ -82,12 +80,19 @@ void process_packet4(const struct s_ethernet *eth, const unsigned char *packet)
void process_tcp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const unsigned char *payload, unsigned short data_size)
{
struct s_tcp *tcp;
struct ip6_hdr *ip;
struct s_ethernet *eth;
struct ip6_hdr *ip;
struct s_ip6_fragment *ip_frag;
struct s_tcp *tcp;
unsigned char *packet;
unsigned int packet_size;
unsigned short packet_size;
unsigned char do_frag = 0;
unsigned char last_frag = 0;
unsigned short frag_size = 1514 - SIZE_ETHERNET - SIZE_IP6 - 8 - 4; /* 4 for alignment */
unsigned short data_frag_size;
unsigned char *data_offset;
unsigned short data_frag_offset = 0;
struct stg_conn_tup *ent = NULL;
struct stg_conn_tup *ent_tmp;
@ -121,11 +126,42 @@ void process_tcp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
printf(" IP-from: %s\n", inet_ntoa(ip_hdr->ip_src));
return;
}
ent->packet_num++;
/* set the checksum to zero */
tcp->checksum = 0x0;
/* compute the TCP checksum */
tcp->checksum = checksum_ipv6(ipaddr_4to6(ent->addr_to), ent->addr_from, data_size, IPPROTO_TCP, (unsigned char *) payload);
printf(" Checksum: 0x%x\n", tcp->checksum);
/* handle fragmentation */
packet_size = data_size + SIZE_ETHERNET + SIZE_IP6;
packet = (unsigned char *) malloc(packet_size);
if (packet == NULL) {
/* check if the packet is not too big => fragment */
if (packet_size > 1514) {
do_frag = 1;
printf("...fragmenting: %d B\n", packet_size);
}
/* send so many packets how many is needed */
while (data_size) {
if (do_frag && data_size > frag_size) {
packet_size = 1514 - 4;
data_frag_size = frag_size;
}
else if (do_frag) {
packet_size = SIZE_ETHERNET + SIZE_IP6 + 8 + data_size;
data_frag_size = data_size;
last_frag = 1;
printf("...last fragment\n");
}
else {
data_frag_size = data_size;
printf("...not fragmenting: %d B\n", packet_size);
}
if ((packet = (unsigned char *) malloc(packet_size)) == NULL) {
fprintf(stderr, "Fatal error! Lack of free memory!\n");
exit(EXIT_FAILURE);
}
@ -136,6 +172,29 @@ void process_tcp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
/* parse the packet into structures */
eth = (struct s_ethernet *) packet;
ip = (struct ip6_hdr *) (packet + SIZE_ETHERNET);
if (do_frag) {
if ((ip_frag = (struct s_ip6_fragment *) malloc(sizeof(struct s_ip6_fragment))) == NULL) {
fprintf(stderr, "Fatal error! Lack of free memory!\n");
exit(EXIT_FAILURE);
}
data_offset = (unsigned char *) (packet + SIZE_ETHERNET + SIZE_IP6 + sizeof(struct s_ip6_fragment));
memset(ip_frag, 0x0, sizeof(struct s_ip6_fragment));
ip_frag->next_header = IPPROTO_TCP;
ip_frag->zeros = 0x0;
ip_frag->id = htonl(ent->port + ent->packet_num);
ip_frag->offset_flag = (htons((data_frag_offset / 8) << 3));
if (!last_frag) {
ip_frag->offset_flag |= htons(0x1);
}
// copy it & free it
memcpy(packet + SIZE_ETHERNET + SIZE_IP6, ip_frag, sizeof(struct s_ip6_fragment));
free(ip_frag);
}
else {
data_offset = (unsigned char *) (ip + SIZE_IP6);
}
/* assemble the ethernet header */
memcpy(&eth->src, mac, sizeof(struct s_mac_addr));
@ -143,34 +202,47 @@ void process_tcp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
eth->type = htons(ETHERTYPE_IPV6);
/* assemble the IPv6 header */
if (do_frag) {
build_ip6_hdr(ip, /* ip6_hdr structure */
ipaddr_4to6(ent->addr_to), /* source address */
ent->addr_from, /* destination address */
data_size, /* payload length */
data_frag_size + 8, /* payload length + fragment header */
IPPROTO_FRAGMENT, /* protocol */
ip_hdr->ttl); /* ttl */
}
else {
build_ip6_hdr(ip, /* ip6_hdr structure */
ipaddr_4to6(ent->addr_to), /* source address */
ent->addr_from, /* destination address */
data_frag_size, /* payload length */
IPPROTO_TCP, /* protocol */
ip_hdr->ttl); /* ttl */
}
char ip6addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ent->addr_from, ip6addr, sizeof(ip6addr));
printf(" Send to: %s\n", ip6addr);
/* set the checksum to zero */
tcp->checksum = 0x0;
/* copy data into the packet */
memcpy(packet + SIZE_ETHERNET + SIZE_IP6, payload, data_size);
/* compute the TCP checksum */
tcp->checksum = checksum_ipv6(ip->ip6_src, ip->ip6_dst, data_size, ip->ip6_nxt, (unsigned char *) (packet + SIZE_ETHERNET + SIZE_IP6));
/* return the checksum into the packet */
memcpy(packet + SIZE_ETHERNET + SIZE_IP6, tcp, sizeof(struct s_tcp));
if (!do_frag) {
memcpy(packet + SIZE_ETHERNET + SIZE_IP6, payload, data_frag_size);
}
else {
memcpy(packet + SIZE_ETHERNET + SIZE_IP6 + sizeof(struct s_ip6_fragment), (unsigned char *) (payload + data_frag_offset), data_frag_size);
}
/* send the wrapped packet back */
send_raw(packet, packet_size);
/* free allocated memory */
free(packet);
packet = NULL;
eth = NULL;
ip = NULL;
data_size -= data_frag_size;
data_frag_offset += data_frag_size;
}
}
void process_udp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const unsigned char *payload, unsigned short data_size)
@ -471,8 +543,7 @@ void process_packet6(const struct s_ethernet *eth, const unsigned char *packet)
inet_ntop(AF_INET6, &ip->ip_dest, ip6addr, sizeof(ip6addr));
printf(" To: %s\n", ip6addr);
/* check if this packet is ours - partially hardcoded for now */
inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix);
/* check if this packet is ours */
inet_pton(AF_INET6, "ff02::1:ff00:0", &ip6addr_ndp_multicast);
/* check for our prefix || NDP */
if (memcmp(&ip6addr_wrapsix, &ip->ip_dest, 12) != 0
@ -501,18 +572,20 @@ void process_packet6(const struct s_ethernet *eth, const unsigned char *packet)
}
}
void process_tcp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload)
void process_tcp6(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, const unsigned char *payload)
{
struct s_ip4 *ip;
struct s_tcp *tcp;
struct in_addr ip4_addr_src, ip4_addr_dest;
struct in_addr ip4_addr;
unsigned char *tcp_packet;
unsigned char *packet;
unsigned char ent_save = 0;
struct stg_conn_tup *ent;
struct stg_conn_tup *ent_tmp;
unsigned short packet_size = htons(ip->len);
unsigned short data_size = htons(ip_hdr->len);
unsigned short packet_size = sizeof(struct s_ip4) + data_size;
/* define TCP header */
tcp = (struct s_tcp *) payload;
@ -539,9 +612,10 @@ void process_tcp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned
/* save the connection */
ent = (struct stg_conn_tup *) malloc(sizeof(struct stg_conn_tup));
ent->port = htons(tcp->port_src);
ent->addr_from = ip->ip_src;
ent->mac = eth->src;
ent->addr_from = ip_hdr->ip_src;
ent->mac = eth_hdr->src;
time(&ent->time);
ent->packet_num = 0;
memset(&ent->addr_to, 0x0, sizeof(struct in_addr));
ent_save = 1;
}
@ -553,36 +627,43 @@ void process_tcp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned
}
/* decide where to send this TCP */
ip4_addr_dest = ipaddr_6to4(ip->ip_dest);
printf(" Send to: %s\n", inet_ntoa(ip4_addr_dest));
ip4_addr = ipaddr_6to4(ip_hdr->ip_dest);
printf(" Send to: %s\n", inet_ntoa(ip4_addr));
/* create one big TCP packet */
tcp_packet = (unsigned char *) malloc(packet_size);
packet = (unsigned char *) malloc(packet_size);
if (tcp_packet == NULL) {
if (packet == NULL) {
fprintf(stderr, "Fatal error! Lack of free memory!\n");
exit(EXIT_FAILURE);
}
/* first set the checksum to zero */
tcp->checksum = 0x0;
/* copy data into the packet */
memcpy(tcp_packet, payload, packet_size);
/* assemble IPv4 header */
ip = (struct s_ip4 *) packet;
ip->ver_ihl = 0x45;
ip->tos = 0x0;
ip->pckt_len = htons(packet_size);
ip->flags_offset = htons(0x4000);
ip->id = 0x0;
ip->ttl = ip_hdr->hop_limit;
ip->proto = IPPROTO_TCP;
ip->checksum = 0x0; /* it is computed automatically */
ip->ip_src = ip4addr_wrapsix;
ip->ip_dest = ip4_addr;
/* compute the checksum */
memcpy(&ip4_addr_src, dev_ip, sizeof(struct in_addr));
tcp->checksum = checksum_ipv4(ip4_addr_src, ip4_addr_dest, packet_size, IPPROTO_TCP, tcp_packet);
tcp->checksum = 0x0;
tcp->checksum = checksum_ipv4(ip4addr_wrapsix, ip4_addr, data_size, IPPROTO_TCP, (unsigned char *) payload);
/* copy this structure again - because of the checksum */
memcpy(tcp_packet, tcp, sizeof(struct s_tcp));
/* copy data into the packet */
memcpy(packet + sizeof(struct s_ip4), payload, data_size);
/* send */
send_there(ip4_addr_dest, ip->hop_limit, IPPROTO_TCP, tcp_packet, packet_size);
send_raw_ipv4(ip->ip_dest, packet, packet_size);
/* save the connection */
if (ent_save == 1) {
ent->addr_to = ip4_addr_dest;
ent->addr_to = ip4_addr;
jsw_rbinsert(stg_conn_tcp, ent);
printf(" Conn #: %d\n", jsw_rbsize(stg_conn_tcp));
/* the entry is not needed now and should be freed */
@ -590,8 +671,8 @@ void process_tcp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned
}
/* free allocated memory */
free(tcp_packet);
tcp_packet = NULL;
free(packet);
packet = NULL;
}
void process_udp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload)

View File

@ -16,6 +16,7 @@ struct stg_conn_tup {
struct in6_addr addr_from;
struct s_mac_addr mac;
time_t time;
unsigned int packet_num;
};
struct stg_conn_icmp {

View File

@ -5,6 +5,7 @@ struct s_mac_addr *mac; /* MAC address of the device */
char *dev; /* capture device name */
int dev_index; /* capture device index */
struct in_addr *dev_ip; /* IP address associated with the device */
struct in6_addr ip6addr_wrapsix; /* IPv6 prefix of WrapSix addresses */
struct in_addr ip4addr_wrapsix; /* IPv4 address for WrapSix */
/* storage trees */
@ -70,8 +71,9 @@ int main(int argc, char **argv)
/* get index of the device */
dev_index = get_dev_index(dev);
/* set the WrapSix IPv4 address */
/* set the WrapSix addresses */
inet_aton("10.0.0.111", &ip4addr_wrapsix);
inet_pton(AF_INET6, "fc00:1::", &ip6addr_wrapsix);
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, 0) == -1) {

View File

@ -97,6 +97,14 @@ struct s_ip6_pseudo {
unsigned char next_header; /* 8 b; next header */
};
/* IPv6 fragment header */
struct s_ip6_fragment {
unsigned char next_header; /* 8 b; next header */
unsigned char zeros; /* 8 b; reserved */
unsigned short offset_flag; /* 16 b; 13 b - data offset, 2 b - reserved, 1 b - flag */
unsigned int id; /* 32 b; identification */
};
/* TCP structure */
struct s_tcp {
unsigned short port_src; /* 16 b; source port */
@ -187,13 +195,14 @@ void process_icmp4(const struct s_ethernet *eth_hdr, struct s_ip4 *ip_hdr, const
void process_arp(const struct s_ethernet *eth_hdr, const unsigned char *arp_packet);
void process_packet6(const struct s_ethernet *eth, const unsigned char *packet);
void process_tcp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload);
void process_tcp6(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, const unsigned char *payload);
void process_udp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload);
void process_icmp6(const struct s_ethernet *eth, struct s_ip6 *ip, const unsigned char *payload);
void process_ndp(const struct s_ethernet *eth_hdr, struct s_ip6 *ip_hdr, unsigned char *icmp_data);
void send_there(struct in_addr ip4_addr, unsigned char ttl, unsigned int type, unsigned char *payload, unsigned int paylen);
void send_raw(unsigned char *packet, int packet_size);
void send_raw_ipv4(struct in_addr ip4_addr, unsigned char *packet, int packet_size);
unsigned short checksum(const void *_buf, int len);
unsigned short checksum_ipv4(struct in_addr ip_src, struct in_addr ip_dest, unsigned short length, unsigned char proto, unsigned char *data);