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 * ipv4.c - takes ipv4 packets, finds their headers, and then calls translation functions on them 17a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 18a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <string.h> 19a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 20a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "translate.h" 21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "checksum.h" 22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "logging.h" 23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "debug.h" 24d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti#include "dump.h" 25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: icmp_packet 27d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * translates an icmp packet 28d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 29d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * icmp - pointer to icmp header in packet 30d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * checksum - pseudo-header checksum 31d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * len - size of ip payload 32d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 34a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colittiint icmp_packet(clat_packet out, clat_packet_index pos, const struct icmphdr *icmp, 35a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colitti uint32_t checksum, size_t len) { 36fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom const uint8_t *payload; 37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t payload_size; 38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 39d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct icmphdr)) { 40d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "icmp_packet/(too small)"); 41d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 42a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 43a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 44fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom payload = (const uint8_t *) (icmp + 1); 45d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti payload_size = len - sizeof(struct icmphdr); 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 47d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return icmp_to_icmp6(out, pos, icmp, checksum, payload, payload_size); 48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 50d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti/* function: ipv4_packet 51d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * translates an ipv4 packet 52d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * out - output packet 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * packet - packet data 54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * len - size of packet 55d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * returns: the highest position in the output clat_packet that's filled in 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 57a4454bfda99803c287b78f8d1cd7bdc1b56065dbLorenzo Colittiint ipv4_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len) { 58d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti const struct iphdr *header = (struct iphdr *) packet; 59d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti struct ip6_hdr *ip6_targ = (struct ip6_hdr *) out[pos].iov_base; 6057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti struct ip6_frag *frag_hdr; 6157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti size_t frag_hdr_len; 62d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti uint8_t nxthdr; 63fcac410fa15613873a07143ccd46470b869346a3Brian Carlstrom const uint8_t *next_header; 64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown size_t len_left; 655a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti uint32_t old_sum, new_sum; 66d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti int iov_len; 67a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 68d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(len < sizeof(struct iphdr)) { 69d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/too short for an ip header"); 70d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 73d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(header->ihl < 5) { 74d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set to less than 5: %x", header->ihl); 75d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 76a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 78d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if((size_t) header->ihl * 4 > len) { // ip header length larger than entire packet 79d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set too large: %x", header->ihl); 80d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 83d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if(header->version != 4) { 84d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header version not 4: %x", header->version); 85d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 86a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 88a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown /* rfc6145 - If any IPv4 options are present in the IPv4 packet, they MUST be 89a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ignored and the packet translated normally; there is no attempt to 90a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * translate the options. 91a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 93d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti next_header = packet + header->ihl*4; 94d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti len_left = len - header->ihl * 4; 95d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 96d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti nxthdr = header->protocol; 97d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti if (nxthdr == IPPROTO_ICMP) { 98d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // ICMP and ICMPv6 have different protocol numbers. 99d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti nxthdr = IPPROTO_ICMPV6; 100d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti } 101a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 102d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti /* Fill in the IPv6 header. We need to do this before we translate the packet because TCP and 103d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * UDP include parts of the IP header in the checksum. Set the length to zero because we don't 104d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti * know it yet. 105d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti */ 106d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti fill_ip6_header(ip6_targ, 0, nxthdr, header); 107d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti out[pos].iov_len = sizeof(struct ip6_hdr); 108d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 10957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti /* Calculate the pseudo-header checksum. 11057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * Technically, the length that is used in the pseudo-header checksum is the transport layer 11157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * length, which is not the same as len_left in the case of fragmented packets. But since 11257d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti * translation does not change the transport layer length, the checksum is unaffected. 11357d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti */ 11407f0265830fcae2632159e9993b93a161d7ea23bLorenzo Colitti old_sum = ipv4_pseudo_header_checksum(header, len_left); 11507f0265830fcae2632159e9993b93a161d7ea23bLorenzo Colitti new_sum = ipv6_pseudo_header_checksum(ip6_targ, len_left, nxthdr); 116d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 11757d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // If the IPv4 packet is fragmented, add a Fragment header. 11857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti frag_hdr = (struct ip6_frag *) out[pos + 1].iov_base; 11957d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti frag_hdr_len = maybe_fill_frag_header(frag_hdr, ip6_targ, header); 12057d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti out[pos + 1].iov_len = frag_hdr_len; 12157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti 12257d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti if (frag_hdr_len && frag_hdr->ip6f_offlg & IP6F_OFF_MASK) { 12357d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti // Non-first fragment. Copy the rest of the packet as is. 12457d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = generic_packet(out, pos + 2, next_header, len_left); 12557d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti } else if (nxthdr == IPPROTO_ICMPV6) { 12657d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = icmp_packet(out, pos + 2, (const struct icmphdr *) next_header, new_sum, len_left); 127c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (nxthdr == IPPROTO_TCP) { 12857d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, 1295a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti len_left); 130c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (nxthdr == IPPROTO_UDP) { 13157d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, 1325a50c0283346a197cda7af19e68f611f14b8fe57Lorenzo Colitti len_left); 133c9f4c89da6c76ebc59a0ec1047853a13ce5f5d96Lorenzo Colitti } else if (nxthdr == IPPROTO_GRE) { 13457d480d2b425ef20d8b6f84abd4e9e3209fa9422Lorenzo Colitti iov_len = generic_packet(out, pos + 2, next_header, len_left); 135a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } else { 136a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#if CLAT_DEBUG 137d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/unknown protocol: %x",header->protocol); 138a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown logcat_hexdump("ipv4/protocol", packet, len); 139a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#endif 140d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return 0; 141a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 142d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti 143d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti // Set the length. 144ee80ca65907d214e2483e315a1ba7f610184de03Lorenzo Colitti ip6_targ->ip6_plen = htons(packet_length(out, pos)); 145d90841824dc00f65a48a789396c7f428807432caLorenzo Colitti return iov_len; 146a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 147