diff options
author | Daniel Drown <dan-android@drown.org> | 2012-03-23 10:42:54 -0500 |
---|---|---|
committer | JP Abgrall <jpa@google.com> | 2012-11-12 15:59:12 -0800 |
commit | a45056e35c1af2a0f0a6eed258fd5fdf4846a79f (patch) | |
tree | 5dd035946e9ab1201289292f7343af3230a26433 /ipv6.c | |
parent | 62ea9b6658a4c2116eeb6450c8244269448e79aa (diff) | |
download | android_external_android-clat-a45056e35c1af2a0f0a6eed258fd5fdf4846a79f.tar.gz android_external_android-clat-a45056e35c1af2a0f0a6eed258fd5fdf4846a79f.tar.bz2 android_external_android-clat-a45056e35c1af2a0f0a6eed258fd5fdf4846a79f.zip |
android clat service
This software provides the nat 4->6 translation needed for the "clat" part of
the 464xlat standard. It is needed for better IPv4 application support while
on an IPv6-only mobile network connection using 464xlat's nat64 (such as
T-Mobile's IPv6 trial).
A general diagram of how 464xlat works:
http://dan.drown.org/android/clat/Clat-Plat.png
Depends-on: I2392f8127dcd90d16b0f20ff31bcc5aa096db464
Change-Id: If2bc6916fc66fd4bca7cc241c83cfae839b82e15
Signed-off-by: Daniel Drown <dan-android@drown.org>
Diffstat (limited to 'ipv6.c')
-rw-r--r-- | ipv6.c | 194 |
1 files changed, 194 insertions, 0 deletions
@@ -0,0 +1,194 @@ +/* + * 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.c - takes ipv6 packets, finds their headers, and then calls translation functions on them + */ +#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 "ipv6.h" +#include "logging.h" +#include "dump.h" +#include "config.h" +#include "debug.h" + +/* function: icmp6_packet + * takes an icmp6 packet and sets it up for translation + * fd - tun interface fd + * packet - ip payload + * len - size of ip payload + * ip6 - ip6 header + */ +void icmp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) { + struct icmp6_hdr icmp6; + const char *payload; + size_t payload_size; + + if(len < sizeof(icmp6)) { + logmsg_dbg(ANDROID_LOG_ERROR,"icmp6_packet/(too small)"); + return; + } + + memcpy(&icmp6, packet, sizeof(icmp6)); + payload = packet + sizeof(icmp6); + payload_size = len - sizeof(icmp6); + + icmp6_to_icmp(fd, ip6, &icmp6, payload, payload_size); +} + +/* function: tcp6_packet + * takes a tcp packet and sets it up for translation + * fd - tun interface fd + * packet - ip payload + * len - size of ip payload + * ip6 - ip6 header + */ +void tcp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) { + struct tcphdr tcp; + const char *payload; + const char *options; + size_t payload_size, options_size; + + if(len < sizeof(tcp)) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/(too small)"); + return; + } + + memcpy(&tcp, packet, sizeof(tcp)); + + if(tcp.doff < 5) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set to less than 5: %x",tcp.doff); + return; + } + + if((size_t)tcp.doff*4 > len) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set too large: %x",tcp.doff); + return; + } + + if(tcp.doff > 5) { + options = packet + sizeof(tcp); + options_size = tcp.doff*4 - sizeof(tcp); + } else { + options = NULL; + options_size = 0; + } + + payload = packet + tcp.doff*4; + payload_size = len - tcp.doff*4; + + tcp6_to_tcp(fd,ip6,&tcp,payload,payload_size,options,options_size); +} + +/* function: udp6_packet + * takes a udp packet and sets it up for translation + * fd - tun interface fd + * packet - ip payload + * len - size of ip payload + * ip6 - ip6 header + */ +void udp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) { + struct udphdr udp; + const char *payload; + size_t payload_size; + + if(len < sizeof(udp)) { + logmsg_dbg(ANDROID_LOG_ERROR,"udp6_packet/(too small)"); + return; + } + + memcpy(&udp, packet, sizeof(udp)); + payload = packet + sizeof(udp); + payload_size = len - sizeof(udp); + + udp6_to_udp(fd,ip6,&udp,payload,payload_size); +} + +/* function: log_bad_address + * logs a bad address to android's log buffer if debugging is turned on + * 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 *badaddr) { +#if CLAT_DEBUG + char badaddr_str[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, badaddr, badaddr_str, sizeof(badaddr_str)); + logmsg_dbg(ANDROID_LOG_ERROR,fmt,badaddr_str); +#endif +} + +/* function: ipv6_packet + * takes an ipv6 packet and hands it off to the layer 4 protocol function + * fd - tun interface fd + * packet - packet data + * len - size of packet + */ +void ipv6_packet(int fd, const char *packet, size_t len) { + struct ip6_hdr header; + const char *next_header; + size_t len_left; + int i; + + if(len < sizeof(header)) { + logmsg_dbg(ANDROID_LOG_ERROR,"ipv6_packet/too short for an ip6 header"); + return; + } + + memcpy(&header, packet, sizeof(header)); + + next_header = packet + sizeof(header); + len_left = len - sizeof(header); + + if(IN6_IS_ADDR_MULTICAST(&header.ip6_dst)) { + log_bad_address("ipv6_packet/multicast %s", &header.ip6_dst); + return; // silently ignore + } + + for(i = 0; i < 3; i++) { + if(header.ip6_src.s6_addr32[i] != Global_Clatd_Config.plat_subnet.s6_addr32[i]) { + log_bad_address("ipv6_packet/wrong source address: %s", &header.ip6_src); + return; + } + } + if(!IN6_ARE_ADDR_EQUAL(&header.ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) { + log_bad_address("ipv6_packet/wrong destination address: %s", &header.ip6_dst); + return; + } + + // does not support IPv6 extension headers, this will drop any packet with them + if(header.ip6_nxt == IPPROTO_ICMPV6) { + icmp6_packet(fd,next_header,len_left,&header); + } else if(header.ip6_nxt == IPPROTO_TCP) { + tcp6_packet(fd,next_header,len_left,&header); + } else if(header.ip6_nxt == IPPROTO_UDP) { + udp6_packet(fd,next_header,len_left,&header); + } else { +#if CLAT_DEBUG + logmsg(ANDROID_LOG_ERROR,"ipv6_packet/unknown next header type: %x",header.ip6_nxt); + logcat_hexdump("ipv6/nxthdr", packet, len); +#endif + } +} |