summaryrefslogtreecommitdiffstats
path: root/ipv6.c
diff options
context:
space:
mode:
authorDaniel Drown <dan-android@drown.org>2012-03-23 10:42:54 -0500
committerJP Abgrall <jpa@google.com>2012-11-12 15:59:12 -0800
commita45056e35c1af2a0f0a6eed258fd5fdf4846a79f (patch)
tree5dd035946e9ab1201289292f7343af3230a26433 /ipv6.c
parent62ea9b6658a4c2116eeb6450c8244269448e79aa (diff)
downloadandroid_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.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/ipv6.c b/ipv6.c
new file mode 100644
index 0000000..8fc36a4
--- /dev/null
+++ b/ipv6.c
@@ -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
+ }
+}