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 20d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti#include <arpa/inet.h> 21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "translate.h" 23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "checksum.h" 24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "logging.h" 25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "dump.h" 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "config.h" 27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "debug.h" 28a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 29a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: icmp6_packet 30a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * takes an icmp6 packet and sets it up for translation 31d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 32d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * icmp6 - pointer to icmp6 header in packet 33d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * checksum - pseudo-header checksum (unused) 34d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * len - size of ip payload 35d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 37a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colittiint icmp6_packet(clat_packet out, clat_packet_index pos, const struct icmp6_hdr *icmp6, 38a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colitti size_t len) { 39fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom const uint8_t *payload; 40a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t payload_size; 41a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 42d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct icmp6_hdr)) { 43d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "icmp6_packet/(too small)"); 44d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 45a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 47fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom payload = (const uint8_t *) (icmp6 + 1); 48d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti payload_size = len - sizeof(struct icmp6_hdr); 49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 509477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti return icmp6_to_icmp(out, pos, icmp6, payload, payload_size); 51a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: log_bad_address 54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * logs a bad address to android's log buffer if debugging is turned on 55a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * fmt - printf-style format, use %s to place the address 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * badaddr - the bad address in question 57a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#if CLAT_DEBUG 599477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colittivoid log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) { 60cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti char srcstr[INET6_ADDRSTRLEN]; 61cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti char dststr[INET6_ADDRSTRLEN]; 62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 63cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti inet_ntop(AF_INET6, src, srcstr, sizeof(srcstr)); 64cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti inet_ntop(AF_INET6, dst, dststr, sizeof(dststr)); 65cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, fmt, srcstr, dststr); 66a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 679477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#else 689477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#define log_bad_address(fmt, src, dst) 699477a464bd70849bcddcb8d11613cff117235cb0Lorenzo Colitti#endif 70a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: ipv6_packet 72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * takes an ipv6 packet and hands it off to the layer 4 protocol function 73d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 74a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * packet - packet data 75a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * len - size of packet 76d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 78a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colittiint ipv6_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len) { 79d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti const struct ip6_hdr *ip6 = (struct ip6_hdr *) packet; 80d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti struct iphdr *ip_targ = (struct iphdr *) out[pos].iov_base; 8157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti struct ip6_frag *frag_hdr = NULL; 82d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti uint8_t protocol; 83fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom const uint8_t *next_header; 84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t len_left; 855a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti uint32_t old_sum, new_sum; 86d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti int iov_len; 87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 88d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct ip6_hdr)) { 89cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header: %d", len); 90d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 91a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 93d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 94cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti log_bad_address("ipv6_packet/multicast %s->%s", &ip6->ip6_src, &ip6->ip6_dst); 95d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; // silently ignore 96a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 98cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // If the packet is not from the plat subnet to the local subnet, or vice versa, drop it, unless 99cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // it's an ICMP packet (which can come from anywhere). We do not send IPv6 packets from the plat 100cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // subnet to the local subnet, but these can appear as inner packets in ICMP errors, so we need 101cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // to translate them. We accept third-party ICMPv6 errors, even though their source addresses 102cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // cannot be translated, so that things like unreachables and traceroute will work. fill_ip_header 103cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti // takes care of faking a source address for them. 104cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti if (!(is_in_plat_subnet(&ip6->ip6_src) && 105cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) && 106cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti !(is_in_plat_subnet(&ip6->ip6_dst) && 107cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet)) && 108cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti ip6->ip6_nxt != IPPROTO_ICMPV6) { 109cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti log_bad_address("ipv6_packet/wrong source address: %s->%s", &ip6->ip6_src, &ip6->ip6_dst); 110d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 111d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti } 112d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 113d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti next_header = packet + sizeof(struct ip6_hdr); 114d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left = len - sizeof(struct ip6_hdr); 115d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 116d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti protocol = ip6->ip6_nxt; 117a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 118d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti /* Fill in the IPv4 header. We need to do this before we translate the packet because TCP and 119d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * UDP include parts of the IP header in the checksum. Set the length to zero because we don't 120d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * know it yet. 121d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti */ 122d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti fill_ip_header(ip_targ, 0, protocol, ip6); 123d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti out[pos].iov_len = sizeof(struct iphdr); 124d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 12557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // If there's a Fragment header, parse it and decide what the next header is. 12657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // Do this before calculating the pseudo-header checksum because it updates the next header value. 12757d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti if (protocol == IPPROTO_FRAGMENT) { 12857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti frag_hdr = (struct ip6_frag *) next_header; 12957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti if (len_left < sizeof(*frag_hdr)) { 13057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for fragment header: %d", len); 13157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti return 0; 13257d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } 13357d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti 13457d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti next_header += sizeof(*frag_hdr); 13557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti len_left -= sizeof(*frag_hdr); 13657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti 13757d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti protocol = parse_frag_header(frag_hdr, ip_targ); 13857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } 13957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti 14057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // ICMP and ICMPv6 have different protocol numbers. 14157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti if (protocol == IPPROTO_ICMPV6) { 14257d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti protocol = IPPROTO_ICMP; 14357d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti ip_targ->protocol = IPPROTO_ICMP; 14457d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } 14557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti 14657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti /* Calculate the pseudo-header checksum. 14757d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * Technically, the length that is used in the pseudo-header checksum is the transport layer 14857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * length, which is not the same as len_left in the case of fragmented packets. But since 14957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * translation does not change the transport layer length, the checksum is unaffected. 15057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti */ 15107f0265830fcae2632159e9993b93a161d7ea23bLorenzo Colitti old_sum = ipv6_pseudo_header_checksum(ip6, len_left, protocol); 15207f0265830fcae2632159e9993b93a161d7ea23bLorenzo Colitti new_sum = ipv4_pseudo_header_checksum(ip_targ, len_left); 153d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 15457d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // Does not support IPv6 extension headers except Fragment. 15557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti if (frag_hdr && (frag_hdr->ip6f_offlg & IP6F_OFF_MASK)) { 15657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = generic_packet(out, pos + 2, next_header, len_left); 15757d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } else if (protocol == IPPROTO_ICMP) { 15857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = icmp6_packet(out, pos + 2, (const struct icmp6_hdr *) next_header, len_left); 15957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } else if (protocol == IPPROTO_TCP) { 16057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, 161d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left); 16257d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } else if (protocol == IPPROTO_UDP) { 16357d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, 164d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left); 16557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } else if (protocol == IPPROTO_GRE) { 16657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = generic_packet(out, pos + 2, next_header, len_left); 167a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } else { 168a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#if CLAT_DEBUG 169cd70b354eb985678175904a937085bed6094af77Lorenzo Colitti logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt); 170a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown logcat_hexdump("ipv6/nxthdr", packet, len); 171a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#endif 172d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 173a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 174d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 175d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // Set the length and calculate the checksum. 176ee80ca65907d214e2483e315a1ba7f610184de03Lorenzo Colitti ip_targ->tot_len = htons(ntohs(ip_targ->tot_len) + packet_length(out, pos)); 177d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti ip_targ->check = ip_checksum(ip_targ, sizeof(struct iphdr)); 178d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return iov_len; 179a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 180