diff --git a/src/icmp.c b/src/icmp.c index 3ed6d81..fbaaefb 100644 --- a/src/icmp.c +++ b/src/icmp.c @@ -115,8 +115,8 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, eth6->type = htons(ETHERTYPE_IPV6); /* build IPv6 packet */ - ip6->ver = 0x60; - ip6->traffic_class = 0x0; + ip6->ver = 0x60 | (ip4->tos >> 4); + ip6->traffic_class = ip4->tos << 4; ip6->flow_label = 0x0; ip6->len = htons(payload_size); ip6->next_header = IPPROTO_ICMPV6; @@ -228,7 +228,8 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload) /* build IPv4 packet */ ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */ - ip4->tos = 0x0; + ip4->tos = ((ip6->ver & 0x0f) << 4) | + ((ip6->traffic_class & 0xf0) >> 4); ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len)); ip4->id = 0x0; ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT); @@ -250,7 +251,6 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload) (unsigned char *) icmp); /* send translated packet */ - printf("[Debug] transmitting\n"); transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len)); /* clean-up */ @@ -320,8 +320,7 @@ int icmp_ndp(struct s_ethernet *ethq, struct s_ipv6 *ipq, /* ICMP */ icmp->type = ICMPV6_NDP_NA; - icmp->code = 0; - icmp->checksum = 0; + /* code = checksum = 0 by memset */ /* NDP NA */ ndp_na->flags = INNAF_S; diff --git a/src/ipv4.c b/src/ipv4.c index e314ec0..897265d 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -26,6 +26,15 @@ #include "udp.h" #include "wrapper.h" +/** + * Processing of IPv4 packets. + * + * @param eth Ethernet header + * @param packet Packet data + * + * @return 0 for success + * @return 1 for failure + */ int ipv4(struct s_ethernet *eth, char *packet) { struct s_ipv4 *ip; @@ -42,8 +51,6 @@ int ipv4(struct s_ethernet *eth, char *packet) return 1; } - /* TODO: verify checksum */ - /* compute sizes and get payload */ header_size = (ip->ver_hdrlen & 0x0f) * 4; /* # of 4 byte words */ data_size = htons(ip->len) - header_size; @@ -52,21 +59,16 @@ int ipv4(struct s_ethernet *eth, char *packet) switch (ip->proto) { case IPPROTO_TCP: printf("[Debug] IPv4 Protocol: TCP\n"); - tcp_ipv4(eth, ip, payload, data_size); - break; + return tcp_ipv4(eth, ip, payload, data_size); case IPPROTO_UDP: printf("[Debug] IPv4 Protocol: UDP\n"); - udp_ipv4(eth, ip, payload, data_size); - break; + return udp_ipv4(eth, ip, payload, data_size); case IPPROTO_ICMP: printf("[Debug] IPv4 Protocol: ICMP\n"); - icmp_ipv4(eth, ip, payload, data_size); - break; + return icmp_ipv4(eth, ip, payload, data_size); default: printf("[Debug] IPv4 Protocol: unknown [%d/0x%x]\n", ip->proto, ip->proto); return 1; } - - return 0; } diff --git a/src/ipv6.c b/src/ipv6.c index 0d16ef9..31bad2a 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -26,6 +26,15 @@ #include "udp.h" #include "wrapper.h" +/** + * Processing of IPv6 packets. + * + * @param eth Ethernet header + * @param packet Packet data + * + * @return 0 for success + * @return 1 for failure + */ int ipv6(struct s_ethernet *eth, char *packet) { struct s_ipv6 *ip; @@ -45,21 +54,16 @@ int ipv6(struct s_ethernet *eth, char *packet) switch (ip->next_header) { case IPPROTO_TCP: printf("[Debug] IPv6 Protocol: TCP\n"); - tcp_ipv6(eth, ip, payload); - break; + return tcp_ipv6(eth, ip, payload); case IPPROTO_UDP: printf("[Debug] IPv6 Protocol: UDP\n"); - udp_ipv6(eth, ip, payload); - break; + return udp_ipv6(eth, ip, payload); case IPPROTO_ICMPV6: printf("[Debug] IPv6 Protocol: ICMP\n"); - icmp_ipv6(eth, ip, payload); - break; + return icmp_ipv6(eth, ip, payload); default: printf("[Debug] IPv6 Protocol: unknown [%d/0x%x]\n", ip->next_header, ip->next_header); return 1; } - - return 0; } diff --git a/src/nat.c b/src/nat.c index d250a1e..aaa7982 100644 --- a/src/nat.c +++ b/src/nat.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2011 Michal Zima + * 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 @@ -50,6 +50,9 @@ radixtree_t *nat6_tcp, *nat6_udp, *nat6_icmp, *nat4_tcp, *nat4_udp, *nat4_icmp, *nat4_tcp_fragments; +/** + * Initialization of NAT tables. + */ void nat_init(void) { nat6_tcp = radixtree_create(); @@ -63,6 +66,9 @@ void nat_init(void) nat4_tcp_fragments = radixtree_create(); } +/** + * Clean-up of NAT tables. + */ void nat_quit(void) { /* 128 + 16 + 32 + 16 = 192 / 6 = 32 */ @@ -79,6 +85,20 @@ void nat_quit(void) radixtree_destroy(nat4_tcp_fragments, 8); } +/** + * Lookup or create NAT connection for outgoing IPv6 packet. + * + * @param nat_proto6 IPv6 NAT table + * @param nat_proto4 IPv4 NAT table + * @param eth_src Source MAC address + * @param ipv6_src Source IPv6 address + * @param ipv6_dst Destination IPv6 address + * @param port_src Source port + * @param port_dst Destination port + * + * @return NULL when it wasn't possible to create connection + * @return pointer to connection structure otherwise + */ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4, struct s_mac_addr eth_src, struct s_ipv6_addr ipv6_src, struct s_ipv6_addr ipv6_dst, @@ -137,6 +157,17 @@ struct s_nat *nat_out(radixtree_t *nat_proto6, radixtree_t *nat_proto4, } } +/** + * Lookup NAT connection for incoming IPv4 packet. + * + * @param nat_proto4 NAT table + * @param ipv4_src Source IPv4 address + * @param port_src Source port + * @param port_dst Destination port + * + * @return NULL when no connection was found + * @return pointer to connection structure otherwise + */ struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src, unsigned short port_src, unsigned short port_dst) { @@ -225,8 +256,8 @@ struct s_nat *nat_in_fragments(radixtree_t *nat_proto4, * @param ipv4_src Source IPv4 address * @param id Fragment identification */ -void nat_in_fragments_clenup(radixtree_t *nat_proto4, - struct s_ipv4_addr ipv4_src, unsigned short id) +void nat_in_fragments_cleanup(radixtree_t *nat_proto4, + struct s_ipv4_addr ipv4_src, unsigned short id) { /* create structure to search in the tree */ struct s_radixtree_fragments4 radixsearch4; diff --git a/src/nat.h b/src/nat.h index 79121a2..06f9ea4 100644 --- a/src/nat.h +++ b/src/nat.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2011 Michal Zima + * 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 @@ -53,7 +53,7 @@ struct s_nat *nat_in(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src, struct s_nat *nat_in_fragments(radixtree_t *nat_proto4, struct s_ipv4_addr ipv4_src, unsigned short id, struct s_nat *nat); -void nat_in_fragments_clenup(radixtree_t *nat_proto4, - struct s_ipv4_addr ipv4_src, unsigned short id); +void nat_in_fragments_cleanup(radixtree_t *nat_proto4, + struct s_ipv4_addr ipv4_src, unsigned short id); #endif /* NAT_H */ diff --git a/src/radixtree.c b/src/radixtree.c index b9cacb8..600747c 100644 --- a/src/radixtree.c +++ b/src/radixtree.c @@ -22,6 +22,11 @@ #include "radixtree.h" +/** + * Creates root of radix tree. + * + * @return Root of new radix tree + */ radixtree_t *radixtree_create(void) { radixtree_t *radixtree; @@ -36,21 +41,36 @@ radixtree_t *radixtree_create(void) return radixtree; } -void radixtree_destroy(radixtree_t *t, unsigned char depth) +/** + * Destroys a radix tree. + * + * @param root Root of the tree to destroy + * @param depth Depth of the tree + */ +void radixtree_destroy(radixtree_t *root, unsigned char depth) { unsigned char i; for (i = 0; i < ARRAY_SIZE; i++) { - if (depth != 1 && t->array[i] != NULL) { - radixtree_destroy(t->array[i], depth - 1); + if (depth != 1 && root->array[i] != NULL) { + radixtree_destroy(root->array[i], depth - 1); } else if (depth == 1) { - free(t->array[i]); + free(root->array[i]); } } - free(t); + free(root); } +/** + * Inserts new data entry into the tree. + * + * @param root Root of the radix tree + * @param chunker Function to use to get chunks for indexing internal array + * @param search_data Key used to search in the tree + * @param size Length of the key + * @param data Data to store in the tree + */ void radixtree_insert(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count), void *search_data, unsigned char size, void *data) @@ -85,6 +105,14 @@ void radixtree_insert(radixtree_t *root, free(chunks); } +/** + * Deletes an entry from the tree. + * + * @param root Root of the radix tree + * @param chunker Function to use to get chunks for indexing internal array + * @param data Key used to search in the tree + * @param size Length of the key + */ void radixtree_delete(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count), void *data, unsigned char size) @@ -97,7 +125,7 @@ void radixtree_delete(radixtree_t *root, chunks = chunker(data, size, &chunk_count); - for (i = 0, tmp = root; i < chunk_count && tmp != NULL; i++, tmp = tmp->array[chunks[i]]) { + for (i = 0, tmp = root; i < chunk_count && tmp != NULL; tmp = tmp->array[chunks[i++]]) { flags = tmp->count == 1 ? flags | (0x1 << i) : 0; if (i + 1 == chunk_count) { @@ -128,6 +156,14 @@ void radixtree_delete(radixtree_t *root, free(chunks); } +/** + * Lookups an entry in the tree. + * + * @param root Root of the radix tree + * @param chunker Function to use to get chunks for indexing internal array + * @param data Key used to search in the tree + * @param size Length of the key + */ void *radixtree_lookup(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count), void *data, unsigned char size) diff --git a/src/radixtree.h b/src/radixtree.h index 59ee089..dc8c747 100644 --- a/src/radixtree.h +++ b/src/radixtree.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2011 Michal Zima + * 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 @@ -28,7 +28,7 @@ typedef struct radixtree { } radixtree_t; radixtree_t *radixtree_create(void); -void radixtree_destroy(radixtree_t *t, unsigned char depth); +void radixtree_destroy(radixtree_t *root, unsigned char depth); void radixtree_insert(radixtree_t *root, unsigned char *(chunker)(void *data, unsigned char size, unsigned char *count), void *search_data, unsigned char size, void *data); diff --git a/src/tcp.c b/src/tcp.c index 3b62d5d..74c818e 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -57,12 +57,12 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, struct s_ipv6_fragment *frag; /* full processing of unfragmented packet or the first fragment with - * TCP header with checksum field (this is safe) + * TCP header */ 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)) { + payload_size >= sizeof(struct s_tcp))) { /* parse TCP header */ tcp = (struct s_tcp *) payload; @@ -249,8 +249,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, sizeof(struct s_ipv6_fragment)); /* fill in missing IPv6 fragment header fields */ - frag->offset_flag = htons((htons(ip4->flags_offset) << 3) | - IPV6_FLAG_MORE_FRAGMENTS); + frag->offset_flag = htons((htons(ip4->flags_offset) << + 3) | IPV6_FLAG_MORE_FRAGMENTS); /* copy the payload data */ memcpy((unsigned char *) frag + @@ -264,7 +264,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, ip6->len = htons(payload_size + sizeof(struct s_ipv6_fragment) - FRAGMENT_LEN); - frag->offset_flag = htons((htons(ip4->flags_offset) + + frag->offset_flag = htons(((htons(ip4->flags_offset) & + 0xfffc) + FRAGMENT_LEN / 8) << 3); if (ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) { @@ -378,7 +379,8 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload) /* build IPv4 packet */ ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */ - ip4->tos = 0x0; + ip4->tos = ((ip6->ver & 0x0f) << 4) | + ((ip6->traffic_class & 0xf0) >> 4); ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len)); ip4->id = 0x0; ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT); diff --git a/src/tcp.h b/src/tcp.h index dbcde8a..aa5f22a 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -30,7 +30,6 @@ struct s_tcp { 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 *eth4, struct s_ipv4 *ip4, char *payload, diff --git a/src/transmitter.c b/src/transmitter.c index 38e191e..8196d6b 100644 --- a/src/transmitter.c +++ b/src/transmitter.c @@ -18,7 +18,8 @@ #include /* struct ifreq */ #include /* {P,A}F_PACKET, ETH_P_*, socket, SOCK_RAW, - * setsockopt, SOL_SOCKET, SO_BINDTODEVICE, sendto */ + * setsockopt, SOL_SOCKET, SO_BINDTODEVICE, + * sendto */ #include /* htons */ #include /* sockaddr_ll, PACKET_OTHERHOST */ #include /* fprintf, stderr, perror */ @@ -34,7 +35,8 @@ struct sockaddr_in socket_address_ipv4; int sock, sock_ipv4; /** - * Initialize socket and all needed properties. Should be called only once on program startup. + * Initialize sockets and all needed properties. Should be called only once on + * program startup. * * @return 0 for success * @return 1 for failure @@ -45,10 +47,10 @@ int transmission_init(void) /** RAW socket **/ /* prepare settings for RAW socket */ - socket_address.sll_family = PF_PACKET; /* RAW communication */ - socket_address.sll_protocol = htons(ETH_P_IP); /* protocol above the ethernet layer */ - socket_address.sll_ifindex = interface.ifr_ifindex; /* set index of the network device */ - socket_address.sll_pkttype = PACKET_OTHERHOST; /* target host is another host */ + socket_address.sll_family = PF_PACKET; /* raw communication */ + socket_address.sll_protocol = htons(ETH_P_IP); /* L3 proto */ + socket_address.sll_ifindex = interface.ifr_ifindex; + socket_address.sll_pkttype = PACKET_OTHERHOST; /* initialize RAW socket */ if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) { @@ -58,8 +60,10 @@ int transmission_init(void) } /* bind the socket to the interface */ - if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(struct ifreq)) == -1) { - fprintf(stderr, "[Error] Couldn't bind the socket to the interface.\n"); + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &interface, + sizeof(struct ifreq)) == -1) { + fprintf(stderr, "[Error] Couldn't bind the socket to the " + "interface.\n"); perror("setsockopt()"); return 1; } @@ -78,8 +82,10 @@ int transmission_init(void) } /* we will provide our own IPv4 header */ - if (setsockopt(sock_ipv4, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) { - fprintf(stderr, "[Error] Couldn't apply the socket settings.\n"); + if (setsockopt(sock_ipv4, IPPROTO_IP, IP_HDRINCL, &on, + sizeof(on)) == -1) { + fprintf(stderr, "[Error] Couldn't apply the socket " + "settings.\n"); perror("setsockopt()"); return 1; } @@ -88,7 +94,7 @@ int transmission_init(void) } /** - * Close socket. Should be called only once on program shutdown. + * Close sockets. Should be called only once on program shutdown. * * @return 0 for success * @return 1 for failure @@ -97,7 +103,8 @@ int transmission_quit(void) { /* close the socket */ if (close(sock) || close(sock_ipv4)) { - fprintf(stderr, "[Error] Couldn't close the transmission sockets.\n"); + fprintf(stderr, "[Error] Couldn't close the transmission " + "sockets.\n"); perror("close()"); return 1; } else { @@ -116,7 +123,8 @@ int transmission_quit(void) */ int transmit_raw(unsigned char *data, unsigned int length) { - if (sendto(sock, data, length, 0, (struct sockaddr *) &socket_address, sizeof(struct sockaddr_ll)) != (int) length) { + if (sendto(sock, data, length, 0, (struct sockaddr *) &socket_address, + sizeof(struct sockaddr_ll)) != (int) length) { fprintf(stderr, "[Error] Couldn't send a RAW packet.\n"); perror("sendto()"); return 1; @@ -129,18 +137,23 @@ int transmit_raw(unsigned char *data, unsigned int length) * Send IPv4 packet with IPv4 header supplied. Ethernet header is added by OS. * * @param ip Destination IPv4 address - * @param data Raw packet data, excluding ethernet header, but including IPv4 header + * @param data Raw packet data, excluding ethernet header, but + * including IPv4 header * @param length Length of the whole packet in bytes * * @return 0 for success * @return 1 for failure */ -int transmit_ipv4(struct s_ipv4_addr *ip, unsigned char *data, unsigned int length) +int transmit_ipv4(struct s_ipv4_addr *ip, unsigned char *data, + unsigned int length) { /* set the destination IPv4 address */ - memcpy(&socket_address_ipv4.sin_addr.s_addr, ip, sizeof(struct s_ipv4_addr)); + memcpy(&socket_address_ipv4.sin_addr.s_addr, ip, + sizeof(struct s_ipv4_addr)); - if (sendto(sock_ipv4, data, length, 0, (struct sockaddr *) &socket_address_ipv4, sizeof(struct sockaddr)) != (int) length) { + if (sendto(sock_ipv4, data, length, 0, + (struct sockaddr *) &socket_address_ipv4, + sizeof(struct sockaddr)) != (int) length) { fprintf(stderr, "[Error] Couldn't send an IPv4 packet.\n"); perror("sendto()"); return 1; diff --git a/src/udp.c b/src/udp.c index 119e777..d936a9c 100644 --- a/src/udp.c +++ b/src/udp.c @@ -97,8 +97,8 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload, eth6->type = htons(ETHERTYPE_IPV6); /* build IPv6 packet */ - ip6->ver = 0x60; - ip6->traffic_class = 0x0; + ip6->ver = 0x60 | (ip4->tos >> 4); + ip6->traffic_class = ip4->tos << 4; ip6->flow_label = 0x0; ip6->len = htons(payload_size); ip6->next_header = IPPROTO_UDP; @@ -193,7 +193,8 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload) /* build IPv4 packet */ ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */ - ip4->tos = 0x0; + ip4->tos = ((ip6->ver & 0x0f) << 4) | + ((ip6->traffic_class & 0xf0) >> 4); ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len)); ip4->id = 0x0; ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT); diff --git a/src/wrapper.c b/src/wrapper.c index d5fbcf5..4c73362 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -37,10 +37,12 @@ #include "transmitter.h" #include "wrapper.h" -#define INTERFACE "eth0" -#define BUFFER_SIZE 65536 -#define PREFIX "fd77::" +-/* +++ CONFIGURATION +++ */ +#define INTERFACE "eth0" /* be sure to turn off generic-segmentation-offload! */ +#define PREFIX "64:ff9b::" #define IPV4_ADDR "192.168.0.111" +/* --- CONFIGURATION --- */ + struct ifreq interface; struct s_mac_addr mac; diff --git a/src/wrapper.h b/src/wrapper.h index 410f7d6..d8e1dc9 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -22,7 +22,9 @@ #include "ipv4.h" #include "ipv6.h" +/* +++ CONFIGURE +++ */ #define MTU 1280 +/* --- CONFIGURE --- */ extern struct ifreq interface; extern struct s_mac_addr mac;