diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | checksum.c | 54 | ||||
-rw-r--r-- | checksum.h | 6 | ||||
-rw-r--r-- | clatd.c | 89 | ||||
-rw-r--r-- | clatd.conf | 3 | ||||
-rw-r--r-- | clatd.h | 6 | ||||
-rw-r--r-- | config.c | 6 | ||||
-rw-r--r-- | config.h | 3 | ||||
-rw-r--r-- | dump.c | 9 | ||||
-rw-r--r-- | icmp.c | 2 | ||||
-rw-r--r-- | ipv4.c | 56 | ||||
-rw-r--r-- | ipv4.h | 25 | ||||
-rw-r--r-- | ipv6.c | 77 | ||||
-rw-r--r-- | ipv6.h | 25 | ||||
-rw-r--r-- | translate.c | 186 | ||||
-rw-r--r-- | translate.h | 48 |
16 files changed, 353 insertions, 243 deletions
@@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:=clatd.c dump.c checksum.c translate.c icmp.c ipv4.c ipv6.c config.c dns64.c logging.c getaddr.c getroute.c netlink_callbacks.c netlink_msg.c setif.c setroute.c mtu.c +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter LOCAL_C_INCLUDES := external/libnl-headers LOCAL_STATIC_LIBRARIES := libnl_2 LOCAL_SHARED_LIBRARIES := libcutils liblog @@ -49,19 +49,27 @@ uint32_t ip_checksum_add(uint32_t current, const void *data, int len) { return checksum; } -/* function: ip_checksum_finish - * close the checksum +/* function: ip_checksum_fold + * folds a 32-bit partial checksum into 16 bits * temp_sum - sum from ip_checksum_add + * returns: the folded checksum in network byte order */ -uint16_t ip_checksum_finish(uint32_t temp_sum) { +uint16_t ip_checksum_fold(uint32_t temp_sum) { while(temp_sum > 0xffff) temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF); - temp_sum = (~temp_sum) & 0xffff; - return temp_sum; } +/* function: ip_checksum_finish + * folds and closes the checksum + * temp_sum - sum from ip_checksum_add + * returns: a header checksum value in network byte order + */ +uint16_t ip_checksum_finish(uint32_t temp_sum) { + return ~ip_checksum_fold(temp_sum); +} + /* function: ip_checksum * combined ip_checksum_add and ip_checksum_finish * data - data to checksum @@ -76,16 +84,16 @@ uint16_t ip_checksum(const void *data, int len) { /* function: ipv6_pseudo_header_checksum * calculate the pseudo header checksum for use in tcp/udp/icmp headers - * current - the current checksum or 0 to start a new checksum - * ip6 - the ipv6 header - * len - the transport length (transport header + payload) + * ip6 - the ipv6 header + * len - the transport length (transport header + payload) + * protocol - the transport layer protocol, can be different from ip6->ip6_nxt for fragments */ -uint32_t ipv6_pseudo_header_checksum(uint32_t current, const struct ip6_hdr *ip6, uint16_t len) { +uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr *ip6, uint16_t len, uint8_t protocol) { uint32_t checksum_len, checksum_next; - checksum_len = htonl((uint32_t) len); - checksum_next = htonl(ip6->ip6_nxt); + checksum_next = htonl(protocol); + uint32_t current = 0; current = ip_checksum_add(current, &(ip6->ip6_src), sizeof(struct in6_addr)); current = ip_checksum_add(current, &(ip6->ip6_dst), sizeof(struct in6_addr)); current = ip_checksum_add(current, &checksum_len, sizeof(checksum_len)); @@ -96,16 +104,16 @@ uint32_t ipv6_pseudo_header_checksum(uint32_t current, const struct ip6_hdr *ip6 /* function: ipv4_pseudo_header_checksum * calculate the pseudo header checksum for use in tcp/udp headers - * current - the current checksum or 0 to start a new checksum * ip - the ipv4 header * len - the transport length (transport header + payload) */ -uint32_t ipv4_pseudo_header_checksum(uint32_t current, const struct iphdr *ip, uint16_t len) { +uint32_t ipv4_pseudo_header_checksum(const struct iphdr *ip, uint16_t len) { uint16_t temp_protocol, temp_length; temp_protocol = htons(ip->protocol); temp_length = htons(len); + uint32_t current = 0; current = ip_checksum_add(current, &(ip->saddr), sizeof(uint32_t)); current = ip_checksum_add(current, &(ip->daddr), sizeof(uint32_t)); current = ip_checksum_add(current, &temp_protocol, sizeof(uint16_t)); @@ -113,3 +121,23 @@ uint32_t ipv4_pseudo_header_checksum(uint32_t current, const struct iphdr *ip, u return current; } + +/* function: ip_checksum_adjust + * calculates a new checksum given a previous checksum and the old and new pseudo-header checksums + * checksum - the header checksum in the original packet in network byte order + * old_hdr_sum - the pseudo-header checksum of the original packet + * new_hdr_sum - the pseudo-header checksum of the translated packet + * returns: the new header checksum in network byte order + */ +uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum) { + // Algorithm suggested in RFC 1624. + // http://tools.ietf.org/html/rfc1624#section-3 + checksum = ~checksum; + uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum); + uint16_t folded_old = ip_checksum_fold(old_hdr_sum); + if (folded_sum > folded_old) { + return ~(folded_sum - folded_old); + } else { + return ~(folded_sum - folded_old - 1); // end-around borrow + } +} @@ -22,7 +22,9 @@ uint32_t ip_checksum_add(uint32_t current, const void *data, int len); uint16_t ip_checksum_finish(uint32_t temp_sum); uint16_t ip_checksum(const void *data, int len); -uint32_t ipv6_pseudo_header_checksum(uint32_t current, const struct ip6_hdr *ip6, uint16_t len); -uint32_t ipv4_pseudo_header_checksum(uint32_t current, const struct iphdr *ip, uint16_t len); +uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr *ip6, uint16_t len, uint8_t protocol); +uint32_t ipv4_pseudo_header_checksum(const struct iphdr *ip, uint16_t len); + +uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum); #endif /* __CHECKSUM_H__ */ @@ -29,15 +29,6 @@ #include <arpa/inet.h> #include <fcntl.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/udp.h> -#include <netinet/tcp.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <linux/icmp.h> - #include <sys/capability.h> #include <sys/uio.h> #include <linux/prctl.h> @@ -47,8 +38,6 @@ #include <private/android_filesystem_config.h> -#include "ipv4.h" -#include "ipv6.h" #include "translate.h" #include "clatd.h" #include "config.h" @@ -62,14 +51,12 @@ #define DEVICENAME6 "clat" #define DEVICENAME4 "clat4" +/* 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header */ +#define MTU_DELTA 28 + int forwarding_fd = -1; volatile sig_atomic_t running = 1; -struct tun_data { - char device6[IFNAMSIZ], device4[IFNAMSIZ]; - int fd6, fd4; -}; - /* function: set_forwarding * enables/disables ipv6 forwarding */ @@ -84,7 +71,7 @@ void set_forwarding(int fd, const char *setting) { /* function: stop_loop * signal handler: stop the event loop */ -void stop_loop(int signal) { +void stop_loop() { running = 0; } @@ -146,7 +133,6 @@ void deconfigure_tun_ipv6(const struct tun_data *tunnel) { * tunnel - tun device data */ void configure_tun_ipv6(const struct tun_data *tunnel) { - struct in6_addr local_nat64_prefix_6; int status; status = if_route(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, @@ -205,6 +191,13 @@ void configure_tun_ip(const struct tun_data *tunnel) { exit(1); } + status = add_address(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_address, + 64, NULL); + if(status < 0) { + logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_address(6) failed: %s",strerror(-status)); + exit(1); + } + if((status = if_up(tunnel->device6, Global_Clatd_Config.mtu)) < 0) { logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(6) failed: %s",strerror(-status)); exit(1); @@ -281,8 +274,9 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, Global_Clatd_Config.mtu = 1280; } - if(Global_Clatd_Config.ipv4mtu <= 0 || (Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - 20)) { - Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu-20; + if(Global_Clatd_Config.ipv4mtu <= 0 || + Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - MTU_DELTA) { + Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu - MTU_DELTA; logmsg(ANDROID_LOG_WARN,"ipv4mtu now set to = %d",Global_Clatd_Config.ipv4mtu); } @@ -301,56 +295,6 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, configure_tun_ip(tunnel); } -/* function: packet_handler - * takes a tun header and a packet and sends it down the stack - * tunnel - tun device data - * tun_header - tun header - * packet - packet - * packetsize - size of packet - */ -void packet_handler(const struct tun_data *tunnel, struct tun_pi *tun_header, const char *packet, - size_t packetsize) { - int fd; - int iov_len = 0; - - // Allocate buffers for all packet headers. - struct tun_pi tun_targ; - char iphdr[sizeof(struct ip6_hdr)]; - char transporthdr[MAX_TCP_HDR]; - char icmp_iphdr[sizeof(struct ip6_hdr)]; - char icmp_transporthdr[MAX_TCP_HDR]; - - // iovec of the packets we'll send. This gets passed down to the translation functions. - clat_packet out = { - { &tun_targ, sizeof(tun_targ) }, // Tunnel header. - { iphdr, 0 }, // IP header. - { transporthdr, 0 }, // Transport layer header. - { icmp_iphdr, 0 }, // ICMP error inner IP header. - { icmp_transporthdr, 0 }, // ICMP error transport layer header. - { NULL, 0 }, // Payload. No buffer, it's a pointer to the original payload. - }; - - if(tun_header->flags != 0) { - logmsg(ANDROID_LOG_WARN,"packet_handler: unexpected flags = %d", tun_header->flags); - } - - if(ntohs(tun_header->proto) == ETH_P_IP) { - fd = tunnel->fd6; - fill_tun_header(&tun_targ, ETH_P_IPV6); - iov_len = ipv4_packet(out, CLAT_POS_IPHDR, packet, packetsize); - } else if(ntohs(tun_header->proto) == ETH_P_IPV6) { - fd = tunnel->fd4; - fill_tun_header(&tun_targ, ETH_P_IP); - iov_len = ipv6_packet(out, CLAT_POS_IPHDR, packet, packetsize); - } else { - logmsg(ANDROID_LOG_WARN,"packet_handler: unknown packet type = %x",tun_header->proto); - } - - if (iov_len > 0) { - writev(fd, out, iov_len); - } -} - /* function: read_packet * reads a packet from the tunnel fd and passes it down the stack * active_fd - tun file descriptor marked ready for reading @@ -372,7 +316,6 @@ void read_packet(int active_fd, const struct tun_data *tunnel) { logmsg(ANDROID_LOG_WARN,"read_packet/tun interface removed"); running = 0; } else { - struct tun_pi tun_header; ssize_t header_size = sizeof(struct tun_pi); if(readlen < header_size) { @@ -380,7 +323,7 @@ void read_packet(int active_fd, const struct tun_data *tunnel) { return; } - packet_handler(tunnel, (struct tun_pi *) packet, packet + header_size, readlen - header_size); + translate_packet(tunnel, (struct tun_pi *) packet, packet + header_size, readlen - header_size); } } @@ -470,7 +413,7 @@ int main(int argc, char **argv) { // open the tunnel device before dropping privs tunnel.fd6 = tun_open(); if(tunnel.fd6 < 0) { - logmsg(ANDROID_LOG_FATAL, "tun_open failed: %s", strerror(errno)); + logmsg(ANDROID_LOG_FATAL, "tun_open6 failed: %s", strerror(errno)); exit(1); } @@ -5,6 +5,9 @@ ipv6_host_id ::464 # ipv4 subnet for the local traffic to use. This is a /32 host address ipv4_local_subnet 192.0.0.4 +# ipv6 extra link local address for the ip6 iface. +ipv6_local_address fe80::c000:0004 + # get the plat_subnet from dns lookups (requires DNS64) plat_from_dns64 yes # hostname to use to lookup plat subnet. must contain only A records @@ -18,6 +18,7 @@ #ifndef __CLATD_H__ #define __CLATD_H__ +#include <linux/if.h> #include <linux/if_tun.h> #define MAXMTU 1500 @@ -30,4 +31,9 @@ // how frequently (in seconds) to poll for an address change while there is no traffic #define NO_TRAFFIC_INTERFACE_POLL_FREQUENCY 90 +struct tun_data { + char device6[IFNAMSIZ], device4[IFNAMSIZ]; + int fd6, fd4; +}; + #endif /* __CLATD_H__ */ @@ -154,7 +154,7 @@ void free_config() { * does dns lookups to set the plat subnet or exits on failure, waits forever for a dns response with a query backoff timer */ void dns64_detection() { - int i, backoff_sleep, status; + int backoff_sleep, status; struct in6_addr tmp_ptr; backoff_sleep = 1; @@ -255,6 +255,9 @@ int read_config(const char *file, const char *uplink_interface, const char *plat if(!config_item_ip(root, "ipv4_local_subnet", DEFAULT_IPV4_LOCAL_SUBNET, &Global_Clatd_Config.ipv4_local_subnet)) goto failed; + if(!config_item_ip6(root, "ipv6_local_address", DEFAULT_IPV6_LOCAL_ADDRESS, &Global_Clatd_Config.ipv6_local_address)) + goto failed; + if(plat_prefix) { // plat subnet is coming from the command line if(inet_pton(AF_INET6, plat_prefix, &Global_Clatd_Config.plat_subnet) <= 0) { logmsg(ANDROID_LOG_FATAL,"invalid IPv6 address specified for plat prefix: %s", plat_prefix); @@ -295,6 +298,7 @@ void dump_config() { logmsg(ANDROID_LOG_DEBUG,"mtu = %d",Global_Clatd_Config.mtu); logmsg(ANDROID_LOG_DEBUG,"ipv4mtu = %d",Global_Clatd_Config.ipv4mtu); + logmsg(ANDROID_LOG_DEBUG,"ipv6_local_address = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_address, charbuffer, sizeof(charbuffer))); logmsg(ANDROID_LOG_DEBUG,"ipv6_local_subnet = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, charbuffer, sizeof(charbuffer))); logmsg(ANDROID_LOG_DEBUG,"ipv4_local_subnet = %s",inet_ntop(AF_INET, &Global_Clatd_Config.ipv4_local_subnet, charbuffer, sizeof(charbuffer))); logmsg(ANDROID_LOG_DEBUG,"plat_subnet = %s",inet_ntop(AF_INET6, &Global_Clatd_Config.plat_subnet, charbuffer, sizeof(charbuffer))); @@ -22,10 +22,13 @@ #include <sys/system_properties.h> #define DEFAULT_IPV4_LOCAL_SUBNET "192.168.255.1" +#define DEFAULT_IPV6_LOCAL_ADDRESS "fe80::c000:0004" + #define DEFAULT_DNS64_DETECTION_HOSTNAME "ipv4.google.com" struct clat_config { int16_t mtu, ipv4mtu; + struct in6_addr ipv6_local_address; struct in6_addr ipv6_local_subnet; struct in6_addr ipv6_host_id; struct in_addr ipv4_local_subnet; @@ -147,14 +147,14 @@ void dump_udp_generic(const struct udphdr *udp, uint32_t temp_checksum, const ch /* print ipv4/udp header */ void dump_udp(const struct udphdr *udp, const struct iphdr *ip, const char *payload, size_t payload_size) { uint32_t temp_checksum; - temp_checksum = ipv4_pseudo_header_checksum(0, ip, sizeof(*udp) + payload_size); + temp_checksum = ipv4_pseudo_header_checksum(ip, sizeof(*udp) + payload_size); dump_udp_generic(udp, temp_checksum, payload, payload_size); } /* print ipv6/udp header */ void dump_udp6(const struct udphdr *udp, const struct ip6_hdr *ip6, const char *payload, size_t payload_size) { uint32_t temp_checksum; - temp_checksum = ipv6_pseudo_header_checksum(0, ip6, sizeof(*udp) + payload_size); + temp_checksum = ipv6_pseudo_header_checksum(ip6, sizeof(*udp) + payload_size, IPPROTO_UDP); dump_udp_generic(udp, temp_checksum, payload, payload_size); } @@ -203,7 +203,7 @@ void dump_tcp_generic(const struct tcphdr *tcp, const char *options, size_t opti void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, const char *payload, size_t payload_size, const char *options, size_t options_size) { uint32_t temp_checksum; - temp_checksum = ipv4_pseudo_header_checksum(0, ip, sizeof(*tcp) + options_size + payload_size); + temp_checksum = ipv4_pseudo_header_checksum(ip, sizeof(*tcp) + options_size + payload_size); dump_tcp_generic(tcp, options, options_size, temp_checksum, payload, payload_size); } @@ -211,7 +211,7 @@ void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, const char *payl void dump_tcp6(const struct tcphdr *tcp, const struct ip6_hdr *ip6, const char *payload, size_t payload_size, const char *options, size_t options_size) { uint32_t temp_checksum; - temp_checksum = ipv6_pseudo_header_checksum(0, ip6, sizeof(*tcp) + options_size + payload_size); + temp_checksum = ipv6_pseudo_header_checksum(ip6, sizeof(*tcp) + options_size + payload_size, IPPROTO_TCP); dump_tcp_generic(tcp, options, options_size, temp_checksum, payload, payload_size); } @@ -220,6 +220,7 @@ void logcat_hexdump(const char *info, const char *data, size_t len) { char output[PACKETLEN*3+2]; size_t i; + output[0] = '\0'; for(i = 0; i < len && i < PACKETLEN; i++) { snprintf(output + i*3, 4, " %02x", (uint8_t)data[i]); } @@ -139,7 +139,7 @@ uint8_t icmp6_to_icmp_type(uint8_t type, uint8_t code) { } // We don't understand this ICMP type. Return parameter problem so the caller will bail out. - logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_type: unhandled ICMP type %d", type); + logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_type: unhandled ICMP type/code %d/%d", type, code); return ICMP_PARAMETERPROB; } @@ -17,18 +17,8 @@ */ #include <string.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/udp.h> -#include <netinet/tcp.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <linux/icmp.h> - #include "translate.h" #include "checksum.h" -#include "ipv4.h" #include "logging.h" #include "debug.h" #include "dump.h" @@ -67,11 +57,12 @@ int icmp_packet(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t c int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { const struct iphdr *header = (struct iphdr *) packet; struct ip6_hdr *ip6_targ = (struct ip6_hdr *) out[pos].iov_base; - uint16_t frag_flags; + struct ip6_frag *frag_hdr; + size_t frag_hdr_len; uint8_t nxthdr; const char *next_header; size_t len_left; - uint32_t checksum; + uint32_t old_sum, new_sum; int iov_len; if(len < sizeof(struct iphdr)) { @@ -79,12 +70,6 @@ int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { return 0; } - frag_flags = ntohs(header->frag_off); - if(frag_flags & IP_MF) { // this could theoretically be supported, but isn't - logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/more fragments set, dropping"); - return 0; - } - if(header->ihl < 5) { logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set to less than 5: %x", header->ihl); return 0; @@ -121,15 +106,32 @@ int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { fill_ip6_header(ip6_targ, 0, nxthdr, header); out[pos].iov_len = sizeof(struct ip6_hdr); - // Calculate the pseudo-header checksum. - checksum = ipv6_pseudo_header_checksum(0, ip6_targ, len_left); - - if(nxthdr == IPPROTO_ICMPV6) { - iov_len = icmp_packet(out, pos + 1, (const struct icmphdr *) next_header, checksum, len_left); - } else if(nxthdr == IPPROTO_TCP) { - iov_len = tcp_packet(out, pos + 1, (const struct tcphdr *) next_header, checksum, len_left); - } else if(nxthdr == IPPROTO_UDP) { - iov_len = udp_packet(out, pos + 1, (const struct udphdr *) next_header, checksum, len_left); + /* Calculate the pseudo-header checksum. + * Technically, the length that is used in the pseudo-header checksum is the transport layer + * length, which is not the same as len_left in the case of fragmented packets. But since + * translation does not change the transport layer length, the checksum is unaffected. + */ + old_sum = ipv4_pseudo_header_checksum(header, len_left); + new_sum = ipv6_pseudo_header_checksum(ip6_targ, len_left, nxthdr); + + // If the IPv4 packet is fragmented, add a Fragment header. + frag_hdr = (struct ip6_frag *) out[pos + 1].iov_base; + frag_hdr_len = maybe_fill_frag_header(frag_hdr, ip6_targ, header); + out[pos + 1].iov_len = frag_hdr_len; + + if (frag_hdr_len && frag_hdr->ip6f_offlg & IP6F_OFF_MASK) { + // Non-first fragment. Copy the rest of the packet as is. + iov_len = generic_packet(out, pos + 2, next_header, len_left); + } else if (nxthdr == IPPROTO_ICMPV6) { + iov_len = icmp_packet(out, pos + 2, (const struct icmphdr *) next_header, new_sum, len_left); + } else if (nxthdr == IPPROTO_TCP) { + iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, + len_left); + } else if (nxthdr == IPPROTO_UDP) { + iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, + len_left); + } else if (nxthdr == IPPROTO_GRE) { + iov_len = generic_packet(out, pos + 2, next_header, len_left); } else { #if CLAT_DEBUG logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/unknown protocol: %x",header->protocol); @@ -1,25 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ipv4.h - takes an ipv4 packet and hands it off to the proper translate function - */ -#ifndef __IPV4_H__ -#define __IPV4_H__ - -#include "translate.h" - -int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len); - -#endif /* __IPV4_H__ */ @@ -17,19 +17,10 @@ */ #include <string.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/udp.h> -#include <netinet/tcp.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <linux/icmp.h> #include <arpa/inet.h> #include "translate.h" #include "checksum.h" -#include "ipv6.h" #include "logging.h" #include "dump.h" #include "config.h" @@ -43,8 +34,7 @@ * len - size of ip payload * returns: the highest position in the output clat_packet that's filled in */ -int icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32_t checksum, - size_t len) { +int icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, size_t len) { const char *payload; size_t payload_size; @@ -56,7 +46,7 @@ int icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32 payload = (const char *) (icmp6 + 1); payload_size = len - sizeof(struct icmp6_hdr); - return icmp6_to_icmp(out, pos, icmp6, checksum, payload, payload_size); + return icmp6_to_icmp(out, pos, icmp6, payload, payload_size); } /* function: log_bad_address @@ -64,16 +54,18 @@ int icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32 * fmt - printf-style format, use %s to place the address * badaddr - the bad address in question */ -void log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) { #if CLAT_DEBUG +void log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) { char srcstr[INET6_ADDRSTRLEN]; char dststr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, src, srcstr, sizeof(srcstr)); inet_ntop(AF_INET6, dst, dststr, sizeof(dststr)); logmsg_dbg(ANDROID_LOG_ERROR, fmt, srcstr, dststr); -#endif } +#else +#define log_bad_address(fmt, src, dst) +#endif /* function: ipv6_packet * takes an ipv6 packet and hands it off to the layer 4 protocol function @@ -85,12 +77,12 @@ void log_bad_address(const char *fmt, const struct in6_addr *src, const struct i int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { const struct ip6_hdr *ip6 = (struct ip6_hdr *) packet; struct iphdr *ip_targ = (struct iphdr *) out[pos].iov_base; + struct ip6_frag *frag_hdr = NULL; uint8_t protocol; const char *next_header; size_t len_left; - uint32_t checksum; + uint32_t old_sum, new_sum; int iov_len; - int i; if(len < sizeof(struct ip6_hdr)) { logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header: %d", len); @@ -121,10 +113,6 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { len_left = len - sizeof(struct ip6_hdr); protocol = ip6->ip6_nxt; - if (protocol == IPPROTO_ICMPV6) { - // ICMP and ICMPv6 have different protocol numbers. - protocol = IPPROTO_ICMP; - } /* Fill in the IPv4 header. We need to do this before we translate the packet because TCP and * UDP include parts of the IP header in the checksum. Set the length to zero because we don't @@ -133,19 +121,48 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { fill_ip_header(ip_targ, 0, protocol, ip6); out[pos].iov_len = sizeof(struct iphdr); - // Calculate the pseudo-header checksum. - checksum = ipv4_pseudo_header_checksum(0, ip_targ, len_left); + // If there's a Fragment header, parse it and decide what the next header is. + // Do this before calculating the pseudo-header checksum because it updates the next header value. + if (protocol == IPPROTO_FRAGMENT) { + frag_hdr = (struct ip6_frag *) next_header; + if (len_left < sizeof(*frag_hdr)) { + logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for fragment header: %d", len); + return 0; + } + + next_header += sizeof(*frag_hdr); + len_left -= sizeof(*frag_hdr); - // does not support IPv6 extension headers, this will drop any packet with them - if(protocol == IPPROTO_ICMP) { - iov_len = icmp6_packet(out, pos + 1, (const struct icmp6_hdr *) next_header, checksum, - len_left); - } else if(ip6->ip6_nxt == IPPROTO_TCP) { - iov_len = tcp_packet(out, pos + 1, (const struct tcphdr *) next_header, checksum, + protocol = parse_frag_header(frag_hdr, ip_targ); + } + + // ICMP and ICMPv6 have different protocol numbers. + if (protocol == IPPROTO_ICMPV6) { + protocol = IPPROTO_ICMP; + ip_targ->protocol = IPPROTO_ICMP; + } + + /* Calculate the pseudo-header checksum. + * Technically, the length that is used in the pseudo-header checksum is the transport layer + * length, which is not the same as len_left in the case of fragmented packets. But since + * translation does not change the transport layer length, the checksum is unaffected. + */ + old_sum = ipv6_pseudo_header_checksum(ip6, len_left, protocol); + new_sum = ipv4_pseudo_header_checksum(ip_targ, len_left); + + // Does not support IPv6 extension headers except Fragment. + if (frag_hdr && (frag_hdr->ip6f_offlg & IP6F_OFF_MASK)) { + iov_len = generic_packet(out, pos + 2, next_header, len_left); + } else if (protocol == IPPROTO_ICMP) { + iov_len = icmp6_packet(out, pos + 2, (const struct icmp6_hdr *) next_header, len_left); + } else if (protocol == IPPROTO_TCP) { + iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, len_left); - } else if(ip6->ip6_nxt == IPPROTO_UDP) { - iov_len = udp_packet(out, pos + 1, (const struct udphdr *) next_header, checksum, + } else if (protocol == IPPROTO_UDP) { + iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, len_left); + } else if (protocol == IPPROTO_GRE) { + iov_len = generic_packet(out, pos + 2, next_header, len_left); } else { #if CLAT_DEBUG logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt); @@ -1,25 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ipv6.h - takes an ipv6 packet and hands it off to the proper translate function - */ -#ifndef __IPV6_H__ -#define __IPV6_H__ - -#include "translate.h" - -int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len); - -#endif /* __IPV6_H__ */ diff --git a/translate.c b/translate.c index fc70f3d..7585092 100644 --- a/translate.c +++ b/translate.c @@ -16,15 +16,7 @@ * translate.c - CLAT functions / partial implementation of rfc6145 */ #include <string.h> - -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/udp.h> -#include <netinet/tcp.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <linux/icmp.h> +#include <sys/uio.h> #include "icmp.h" #include "translate.h" @@ -149,7 +141,7 @@ void fill_ip_header(struct iphdr *ip, uint16_t payload_len, uint8_t protocol, // Third-party ICMPv6 message. This may have been originated by an native IPv6 address. // In that case, the source IPv6 address can't be translated and we need to make up an IPv4 // source address. For now, use 255.0.0.<ttl>, which at least looks useful in traceroute. - if (ip->saddr == (uint32_t) INADDR_NONE) { + if ((uint32_t) ip->saddr == INADDR_NONE) { ttl_guess = icmp_guess_ttl(old_header->ip6_hlim); ip->saddr = htonl((0xff << 24) + ttl_guess); } @@ -175,6 +167,54 @@ void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol ip6->ip6_dst = ipv4_addr_to_ipv6_addr(old_header->daddr); } +/* function: maybe_fill_frag_header + * fills a fragmentation header + * generate an ipv6 fragment header from an ipv4 header + * frag_hdr - target (ipv6) fragmentation header + * ip6_targ - target (ipv6) header + * old_header - (ipv4) source packet header + * returns: the length of the fragmentation header if present, or zero if not present + */ +size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, + const struct iphdr *old_header) { + uint16_t frag_flags = ntohs(old_header->frag_off); + uint16_t frag_off = frag_flags & IP_OFFMASK; + if (frag_off == 0 && (frag_flags & IP_MF) == 0) { + // Not a fragment. + return 0; + } + + frag_hdr->ip6f_nxt = ip6_targ->ip6_nxt; + frag_hdr->ip6f_reserved = 0; + // In IPv4, the offset is the bottom 13 bits; in IPv6 it's the top 13 bits. + frag_hdr->ip6f_offlg = htons(frag_off << 3); + if (frag_flags & IP_MF) { + frag_hdr->ip6f_offlg |= IP6F_MORE_FRAG; + } + frag_hdr->ip6f_ident = htonl(ntohs(old_header->id)); + ip6_targ->ip6_nxt = IPPROTO_FRAGMENT; + + return sizeof(*frag_hdr); +} + +/* function: parse_frag_header + * return the length of the fragmentation header if present, or zero if not present + * generate an ipv6 fragment header from an ipv4 header + * frag_hdr - (ipv6) fragmentation header + * ip_targ - target (ipv4) header + * returns: the next header value + */ +uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ) { + uint16_t frag_off = (ntohs(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) >> 3); + if (frag_hdr->ip6f_offlg & IP6F_MORE_FRAG) { + frag_off |= IP_MF; + } + ip_targ->frag_off = htons(frag_off); + ip_targ->id = htons(ntohl(frag_hdr->ip6f_ident) & 0xffff); + ip_targ->protocol = frag_hdr->ip6f_nxt; + return frag_hdr->ip6f_nxt; +} + /* function: icmp_to_icmp6 * translate ipv4 icmp to ipv6 icmp * out - output packet @@ -208,12 +248,10 @@ int icmp_to_icmp6(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t // The pseudo-header checksum was calculated on the transport length of the original IPv4 // packet that we were asked to translate. This transport length is 20 bytes smaller than it // needs to be, because the ICMP error contains an IPv4 header, which we will be translating to - // an IPv6 header, which is 20 bytes longer. Fix it up here. This is simpler than the - // alternative, which is to always update the pseudo-header checksum in all UDP/TCP/ICMP - // translation functions (rather than pre-calculating it when translating the IPv4 header). + // an IPv6 header, which is 20 bytes longer. Fix it up here. // We only need to do this for ICMP->ICMPv6, not ICMPv6->ICMP, because ICMP does not use the // pseudo-header when calculating its checksum (as the IPv4 header has its own checksum). - checksum = htonl(ntohl(checksum) + 20); + checksum = checksum + htons(20); } else if (icmp6_type == ICMP6_ECHO_REQUEST || icmp6_type == ICMP6_ECHO_REPLY) { // Ping packet. icmp6_targ->icmp6_id = icmp->un.echo.id; @@ -236,16 +274,14 @@ int icmp_to_icmp6(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t * translate ipv6 icmp to ipv4 icmp * out - output packet * icmp6 - source packet icmp6 header - * checksum - pseudo-header checksum (unused) * payload - icmp6 payload * payload_size - size of payload * returns: the highest position in the output clat_packet that's filled in */ -int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32_t checksum, +int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, const char *payload, size_t payload_size) { struct icmphdr *icmp_targ = out[pos].iov_base; uint8_t icmp_type; - int ttl; int clat_packet_len; memset(icmp_targ, 0, sizeof(struct icmphdr)); @@ -280,14 +316,32 @@ int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint3 return clat_packet_len; } +/* function: generic_packet + * takes a generic IP packet and sets it up for translation + * out - output packet + * pos - position in the output packet of the transport header + * payload - pointer to IP payload + * len - size of ip payload + * returns: the highest position in the output clat_packet that's filled in + */ +int generic_packet(clat_packet out, int pos, const char *payload, size_t len) { + out[pos].iov_len = 0; + out[CLAT_POS_PAYLOAD].iov_base = (char *) payload; + out[CLAT_POS_PAYLOAD].iov_len = len; + + return CLAT_POS_PAYLOAD + 1; +} + /* function: udp_packet * takes a udp packet and sets it up for translation * out - output packet * udp - pointer to udp header in packet - * checksum - pseudo-header checksum + * old_sum - pseudo-header checksum of old header + * new_sum - pseudo-header checksum of new header * len - size of ip payload */ -int udp_packet(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum, size_t len) { +int udp_packet(clat_packet out, int pos, const struct udphdr *udp, + uint32_t old_sum, uint32_t new_sum, size_t len) { const char *payload; size_t payload_size; @@ -299,7 +353,7 @@ int udp_packet(clat_packet out, int pos, const struct udphdr *udp, uint32_t chec payload = (const char *) (udp + 1); payload_size = len - sizeof(struct udphdr); - return udp_translate(out, pos, udp, checksum, payload, payload_size); + return udp_translate(out, pos, udp, old_sum, new_sum, payload, payload_size); } /* function: tcp_packet @@ -310,7 +364,8 @@ int udp_packet(clat_packet out, int pos, const struct udphdr *udp, uint32_t chec * len - size of ip payload * returns: the highest position in the output clat_packet that's filled in */ -int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, uint32_t checksum, size_t len) { +int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, + uint32_t old_sum, uint32_t new_sum, size_t len) { const char *payload; size_t payload_size, header_size; @@ -333,20 +388,21 @@ int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, uint32_t chec payload = ((const char *) tcp) + header_size; payload_size = len - header_size; - return tcp_translate(out, pos, tcp, header_size, checksum, payload, payload_size); + return tcp_translate(out, pos, tcp, header_size, old_sum, new_sum, payload, payload_size); } /* function: udp_translate * common between ipv4/ipv6 - setup checksum and send udp packet * out - output packet * udp - udp header - * checksum - pseudo-header checksum + * old_sum - pseudo-header checksum of old header + * new_sum - pseudo-header checksum of new header * payload - tcp payload * payload_size - size of payload * returns: the highest position in the output clat_packet that's filled in */ -int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum, - const char *payload, size_t payload_size) { +int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t old_sum, + uint32_t new_sum, const char *payload, size_t payload_size) { struct udphdr *udp_targ = out[pos].iov_base; memcpy(udp_targ, udp, sizeof(struct udphdr)); @@ -355,8 +411,22 @@ int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t c out[CLAT_POS_PAYLOAD].iov_base = (char *) payload; out[CLAT_POS_PAYLOAD].iov_len = payload_size; - udp_targ->check = 0; // Checksum field must be 0 when calculating checksum. - udp_targ->check = packet_checksum(checksum, out, pos); + if (udp_targ->check) { + udp_targ->check = ip_checksum_adjust(udp->check, old_sum, new_sum); + } else { + // Zero checksums are special. RFC 768 says, "An all zero transmitted checksum value means that + // the transmitter generated no checksum (for debugging or for higher level protocols that + // don't care)." However, in IPv6 zero UDP checksums were only permitted by RFC 6935 (2013). So + // for safety we recompute it. + udp_targ->check = 0; // Checksum field must be 0 when calculating checksum. + udp_targ->check = packet_checksum(new_sum, out, pos); + } + + // RFC 768: "If the computed checksum is zero, it is transmitted as all ones (the equivalent + // in one's complement arithmetic)." + if (!udp_targ->check) { + udp_targ->check = 0xffff; + } return CLAT_POS_PAYLOAD + 1; } @@ -370,12 +440,9 @@ int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t c * payload - tcp payload * payload_size - size of payload * returns: the highest position in the output clat_packet that's filled in - * - * TODO: mss rewrite - * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented) */ int tcp_translate(clat_packet out, int pos, const struct tcphdr *tcp, size_t header_size, - uint32_t checksum, const char *payload, size_t payload_size) { + uint32_t old_sum, uint32_t new_sum, const char *payload, size_t payload_size) { struct tcphdr *tcp_targ = out[pos].iov_base; out[pos].iov_len = header_size; @@ -392,8 +459,61 @@ int tcp_translate(clat_packet out, int pos, const struct tcphdr *tcp, size_t hea out[CLAT_POS_PAYLOAD].iov_base = (char *)payload; out[CLAT_POS_PAYLOAD].iov_len = payload_size; - tcp_targ->check = 0; // Checksum field must be 0 when calculating checksum. - tcp_targ->check = packet_checksum(checksum, out, pos); + tcp_targ->check = ip_checksum_adjust(tcp->check, old_sum, new_sum); return CLAT_POS_PAYLOAD + 1; } + +/* function: translate_packet + * takes a tun header and a packet and sends it down the stack + * tunnel - tun device data + * tun_header - tun header + * packet - packet + * packetsize - size of packet + */ +void translate_packet(const struct tun_data *tunnel, struct tun_pi *tun_header, const char *packet, + size_t packetsize) { + int fd; + int iov_len = 0; + + // Allocate buffers for all packet headers. + struct tun_pi tun_targ; + char iphdr[sizeof(struct ip6_hdr)]; + char fraghdr[sizeof(struct ip6_frag)]; + char transporthdr[MAX_TCP_HDR]; + char icmp_iphdr[sizeof(struct ip6_hdr)]; + char icmp_fraghdr[sizeof(struct ip6_frag)]; + char icmp_transporthdr[MAX_TCP_HDR]; + + // iovec of the packets we'll send. This gets passed down to the translation functions. + clat_packet out = { + { &tun_targ, sizeof(tun_targ) }, // Tunnel header. + { iphdr, 0 }, // IP header. + { fraghdr, 0 }, // Fragment header. + { transporthdr, 0 }, // Transport layer header. + { icmp_iphdr, 0 }, // ICMP error inner IP header. + { icmp_fraghdr, 0 }, // ICMP error fragmentation header. + { icmp_transporthdr, 0 }, // ICMP error transport layer header. + { NULL, 0 }, // Payload. No buffer, it's a pointer to the original payload. + }; + + if(tun_header->flags != 0) { + logmsg(ANDROID_LOG_WARN, "translate_packet: unexpected flags = %d", tun_header->flags); + } + + if(ntohs(tun_header->proto) == ETH_P_IP) { + fd = tunnel->fd6; + fill_tun_header(&tun_targ, ETH_P_IPV6); + iov_len = ipv4_packet(out, CLAT_POS_IPHDR, packet, packetsize); + } else if(ntohs(tun_header->proto) == ETH_P_IPV6) { + fd = tunnel->fd4; + fill_tun_header(&tun_targ, ETH_P_IP); + iov_len = ipv6_packet(out, CLAT_POS_IPHDR, packet, packetsize); + } else { + logmsg(ANDROID_LOG_WARN, "translate_packet: unknown packet type = %x",tun_header->proto); + } + + if (iov_len > 0) { + writev(fd, out, iov_len); + } +} diff --git a/translate.h b/translate.h index fded251..5efa817 100644 --- a/translate.h +++ b/translate.h @@ -18,17 +18,29 @@ #ifndef __TRANSLATE_H__ #define __TRANSLATE_H__ +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#include <linux/icmp.h> #include <linux/if_tun.h> +#include "clatd.h" + #define MAX_TCP_HDR (15 * 4) // Data offset field is 4 bits and counts in 32-bit words. // A clat_packet is an array of iovec structures representing a packet that we are translating. // The CLAT_POS_XXX constants represent the array indices within the clat_packet that contain // specific parts of the packet. The packet_* functions operate on all the packet segments past a // given position. -enum clat_packet_index { CLAT_POS_TUNHDR, CLAT_POS_IPHDR, CLAT_POS_TRANSPORTHDR, - CLAT_POS_ICMPERR_IPHDR, CLAT_POS_ICMPERR_TRANSPORTHDR, - CLAT_POS_PAYLOAD, CLAT_POS_MAX }; +enum clat_packet_index { + CLAT_POS_TUNHDR, CLAT_POS_IPHDR, CLAT_POS_FRAGHDR, CLAT_POS_TRANSPORTHDR, + CLAT_POS_ICMPERR_IPHDR, CLAT_POS_ICMPERR_FRAGHDR, CLAT_POS_ICMPERR_TRANSPORTHDR, + CLAT_POS_PAYLOAD, CLAT_POS_MAX +}; typedef struct iovec clat_packet[CLAT_POS_MAX]; // Calculates the checksum over all the packet components starting from pos. @@ -47,19 +59,37 @@ void fill_ip_header(struct iphdr *ip_targ, uint16_t payload_len, uint8_t protoco void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol, const struct iphdr *old_header); +// Translate and send packets. +void translate_packet(const struct tun_data *tunnel, struct tun_pi *tun_header, const char *packet, + size_t packetsize); + +// Translate IPv4 and IPv6 packets. +int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len); +int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len); + +// Deal with fragmented packets. +size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, + const struct iphdr *old_header); +uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ); + // Translate ICMP packets. int icmp_to_icmp6(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t checksum, const char *payload, size_t payload_size); -int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32_t checksum, +int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, const char *payload, size_t payload_size); +// Translate generic IP packets. +int generic_packet(clat_packet out, int pos, const char *payload, size_t len); + // Translate TCP and UDP packets. -int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, uint32_t checksum, size_t len); -int udp_packet(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum, size_t len); +int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, + uint32_t old_sum, uint32_t new_sum, size_t len); +int udp_packet(clat_packet out, int pos, const struct udphdr *udp, + uint32_t old_sum, uint32_t new_sum, size_t len); int tcp_translate(clat_packet out, int pos, const struct tcphdr *tcp, size_t header_size, - uint32_t checksum, const char *payload, size_t payload_size); -int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum, - const char *payload, size_t payload_size); + uint32_t old_sum, uint32_t new_sum, const char *payload, size_t payload_size); +int udp_translate(clat_packet out, int pos, const struct udphdr *udp, + uint32_t old_sum, uint32_t new_sum, const char *payload, size_t payload_size); #endif /* __TRANSLATE_H__ */ |