ipv6.c revision 5a50c0283346a197cda7af19e68f611f14b8fe57
1a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* 2a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Copyright 2011 Daniel Drown 3a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 4a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Licensed under the Apache License, Version 2.0 (the "License"); 5a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * you may not use this file except in compliance with the License. 6a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * You may obtain a copy of the License at 7a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 8a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * http://www.apache.org/licenses/LICENSE-2.0 9a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 10a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Unless required by applicable law or agreed to in writing, software 11a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * distributed under the License is distributed on an "AS IS" BASIS, 12a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * See the License for the specific language governing permissions and 14a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * limitations under the License. 15a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 16a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ipv6.c - takes ipv6 packets, finds their headers, and then calls translation functions on them 17a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 18a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <string.h> 19a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 20a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/in.h> 21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/ip.h> 22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/ip_icmp.h> 23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/udp.h> 24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/tcp.h> 25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/ip6.h> 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/icmp6.h> 27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/icmp.h> 28d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti#include <arpa/inet.h> 29a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 30a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "translate.h" 31a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "checksum.h" 32a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "logging.h" 33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "dump.h" 34a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "config.h" 35a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "debug.h" 36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: icmp6_packet 38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * takes an icmp6 packet and sets it up for translation 39d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 40d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * icmp6 - pointer to icmp6 header in packet 41d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * checksum - pseudo-header checksum (unused) 42d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * len - size of ip payload 43d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 44a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 459477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colittiint icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, size_t len) { 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown const char *payload; 47a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t payload_size; 48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 49d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct icmp6_hdr)) { 50d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "icmp6_packet/(too small)"); 51d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 54d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti payload = (const char *) (icmp6 + 1); 55d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti payload_size = len - sizeof(struct icmp6_hdr); 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 579477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti return icmp6_to_icmp(out, pos, icmp6, payload, payload_size); 58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 59a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 60a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: log_bad_address 61a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * logs a bad address to android's log buffer if debugging is turned on 62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * fmt - printf-style format, use %s to place the address 63a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * badaddr - the bad address in question 64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 65a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#if CLAT_DEBUG 669477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colittivoid log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) { 67cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti char srcstr[INET6_ADDRSTRLEN]; 68cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti char dststr[INET6_ADDRSTRLEN]; 69a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 70cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti inet_ntop(AF_INET6, src, srcstr, sizeof(srcstr)); 71cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti inet_ntop(AF_INET6, dst, dststr, sizeof(dststr)); 72cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, fmt, srcstr, dststr); 73a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 749477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#else 759477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#define log_bad_address(fmt, src, dst) 769477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#endif 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 78a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: ipv6_packet 79a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * takes an ipv6 packet and hands it off to the layer 4 protocol function 80d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * packet - packet data 82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * len - size of packet 83d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 85d90841824dc00f65a48a789396c7f428807432caLorenzo Colittiint ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { 86d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti const struct ip6_hdr *ip6 = (struct ip6_hdr *) packet; 87d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti struct iphdr *ip_targ = (struct iphdr *) out[pos].iov_base; 88d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti uint8_t protocol; 89a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown const char *next_header; 90a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t len_left; 915a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti uint32_t old_sum, new_sum; 92d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti int iov_len; 93a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 94d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct ip6_hdr)) { 95cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header: %d", len); 96d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 98a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 99d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 100cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti log_bad_address("ipv6_packet/multicast %s->%s", &ip6->ip6_src, &ip6->ip6_dst); 101d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; // silently ignore 102a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 103a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 104cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // If the packet is not from the plat subnet to the local subnet, or vice versa, drop it, unless 105cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // it's an ICMP packet (which can come from anywhere). We do not send IPv6 packets from the plat 106cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // subnet to the local subnet, but these can appear as inner packets in ICMP errors, so we need 107cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // to translate them. We accept third-party ICMPv6 errors, even though their source addresses 108cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // cannot be translated, so that things like unreachables and traceroute will work. fill_ip_header 109cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // takes care of faking a source address for them. 110cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti if (!(is_in_plat_subnet(&ip6->ip6_src) && 111cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) && 112cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti !(is_in_plat_subnet(&ip6->ip6_dst) && 113cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet)) && 114cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti ip6->ip6_nxt != IPPROTO_ICMPV6) { 115cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti log_bad_address("ipv6_packet/wrong source address: %s->%s", &ip6->ip6_src, &ip6->ip6_dst); 116d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 117d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti } 118d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 119d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti next_header = packet + sizeof(struct ip6_hdr); 120d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left = len - sizeof(struct ip6_hdr); 121d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 122d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti protocol = ip6->ip6_nxt; 123d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if (protocol == IPPROTO_ICMPV6) { 124d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // ICMP and ICMPv6 have different protocol numbers. 125d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti protocol = IPPROTO_ICMP; 126a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 127a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 128d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti /* Fill in the IPv4 header. We need to do this before we translate the packet because TCP and 129d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * UDP include parts of the IP header in the checksum. Set the length to zero because we don't 130d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * know it yet. 131d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti */ 132d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti fill_ip_header(ip_targ, 0, protocol, ip6); 133d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti out[pos].iov_len = sizeof(struct iphdr); 134d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 135d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // Calculate the pseudo-header checksum. 1365a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti old_sum = ipv6_pseudo_header_checksum(0, ip6, len_left); 1375a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti new_sum = ipv4_pseudo_header_checksum(0, ip_targ, len_left); 138d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 139a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown // does not support IPv6 extension headers, this will drop any packet with them 140c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti if (protocol == IPPROTO_ICMP) { 1419477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti iov_len = icmp6_packet(out, pos + 1, (const struct icmp6_hdr *) next_header, len_left); 142c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (ip6->ip6_nxt == IPPROTO_TCP) { 1435a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti iov_len = tcp_packet(out, pos + 1, (const struct tcphdr *) next_header, old_sum, new_sum, 144d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left); 145c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (ip6->ip6_nxt == IPPROTO_UDP) { 1465a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti iov_len = udp_packet(out, pos + 1, (const struct udphdr *) next_header, old_sum, new_sum, 147d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left); 148c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (ip6->ip6_nxt == IPPROTO_GRE) { 149c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti iov_len = generic_packet(out, pos + 1, next_header, len_left); 150a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } else { 151a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#if CLAT_DEBUG 152cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt); 153a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown logcat_hexdump("ipv6/nxthdr", packet, len); 154a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#endif 155d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 156a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 157d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 158d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // Set the length and calculate the checksum. 159ee80ca65907d214e2483e315a1ba7f610184de03Lorenzo Colitti ip_targ->tot_len = htons(ntohs(ip_targ->tot_len) + packet_length(out, pos)); 160d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti ip_targ->check = ip_checksum(ip_targ, sizeof(struct iphdr)); 161d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return iov_len; 162a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 163