blob: c0bd59a05fbc2579a8276ff67d31eb1735018dae [file] [log] [blame]
Daniel Drowna45056e2012-03-23 10:42:54 -05001/*
2 * Copyright 2011 Daniel Drown
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * translate.c - CLAT functions / partial implementation of rfc6145
17 */
18#include <string.h>
Daniel Drowna45056e2012-03-23 10:42:54 -050019
20#include <netinet/in.h>
21#include <netinet/ip.h>
22#include <netinet/ip_icmp.h>
23#include <netinet/udp.h>
24#include <netinet/tcp.h>
25#include <netinet/ip6.h>
26#include <netinet/icmp6.h>
27#include <linux/icmp.h>
28
Lorenzo Colittid9084182013-03-22 00:42:21 +090029#include "translate.h"
Daniel Drowna45056e2012-03-23 10:42:54 -050030#include "checksum.h"
31#include "clatd.h"
32#include "config.h"
33#include "logging.h"
34#include "debug.h"
35
Lorenzo Colittid9084182013-03-22 00:42:21 +090036/* function: payload_length
37 * calculates the total length of the packet components after pos
38 * packet - packet to calculate the length of
39 * pos - position to start counting from
40 * returns: the total length of the packet components after pos
41 */
42uint16_t payload_length(clat_packet packet, int pos) {
43 size_t len = 0;
44 int i;
45 for (i = pos + 1; i < POS_MAX; i++) {
46 len += packet[i].iov_len;
47 }
48 return len;
49}
50
Daniel Drowna45056e2012-03-23 10:42:54 -050051/* function: fill_tun_header
52 * fill in the header for the tun fd
53 * tun_header - tunnel header, already allocated
54 * proto - ethernet protocol id: ETH_P_IP(ipv4) or ETH_P_IPV6(ipv6)
55 */
56void fill_tun_header(struct tun_pi *tun_header, uint16_t proto) {
57 tun_header->flags = 0;
58 tun_header->proto = htons(proto);
59}
60
61/* function: ipv6_src_to_ipv4_src
62 * return the corresponding ipv4 address for the given ipv6 address
63 * sourceaddr - ipv6 source address
Lorenzo Colittid9084182013-03-22 00:42:21 +090064 * returns: the IPv4 address
Daniel Drowna45056e2012-03-23 10:42:54 -050065 */
66uint32_t ipv6_src_to_ipv4_src(const struct in6_addr *sourceaddr) {
67 // assumes a /96 plat subnet
68 return sourceaddr->s6_addr32[3];
69}
70
71/* function: fill_ip_header
Lorenzo Colittid9084182013-03-22 00:42:21 +090072 * generate an ipv4 header from an ipv6 header
73 * ip_targ - (ipv4) target packet header, source: original ipv4 addr, dest: local subnet addr
Daniel Drowna45056e2012-03-23 10:42:54 -050074 * payload_len - length of other data inside packet
75 * protocol - protocol number (tcp, udp, etc)
Lorenzo Colittid9084182013-03-22 00:42:21 +090076 * old_header - (ipv6) source packet header, source: nat64 prefix, dest: local subnet prefix
Daniel Drowna45056e2012-03-23 10:42:54 -050077 */
Lorenzo Colittid9084182013-03-22 00:42:21 +090078void fill_ip_header(struct iphdr *ip, uint16_t payload_len, uint8_t protocol,
79 const struct ip6_hdr *old_header) {
80 memset(ip, 0, sizeof(struct iphdr));
Daniel Drowna45056e2012-03-23 10:42:54 -050081
Lorenzo Colittid9084182013-03-22 00:42:21 +090082 ip->ihl = 5;
83 ip->version = 4;
84 ip->tos = 0;
85 ip->tot_len = htons(sizeof(struct iphdr) + payload_len);
86 ip->id = 0;
87 ip->frag_off = htons(IP_DF);
88 ip->ttl = old_header->ip6_hlim;
89 ip->protocol = protocol;
90 ip->check = 0;
Daniel Drowna45056e2012-03-23 10:42:54 -050091
Lorenzo Colittid9084182013-03-22 00:42:21 +090092 ip->saddr = ipv6_src_to_ipv4_src(&old_header->ip6_src);
93 ip->daddr = Global_Clatd_Config.ipv4_local_subnet.s_addr;
Daniel Drowna45056e2012-03-23 10:42:54 -050094}
95
96/* function: ipv4_dst_to_ipv6_dst
97 * return the corresponding ipv6 address for the given ipv4 address
98 * destination - ipv4 destination address (network byte order)
99 */
100struct in6_addr ipv4_dst_to_ipv6_dst(uint32_t destination) {
101 struct in6_addr v6_destination;
102
103 // assumes a /96 plat subnet
104 v6_destination = Global_Clatd_Config.plat_subnet;
105 v6_destination.s6_addr32[3] = destination;
106
107 return v6_destination;
108}
109
110/* function: fill_ip6_header
Lorenzo Colittid9084182013-03-22 00:42:21 +0900111 * generate an ipv6 header from an ipv4 header
112 * ip6 - (ipv6) target packet header, source: local subnet prefix, dest: nat64 prefix
Daniel Drowna45056e2012-03-23 10:42:54 -0500113 * payload_len - length of other data inside packet
114 * protocol - protocol number (tcp, udp, etc)
Lorenzo Colittid9084182013-03-22 00:42:21 +0900115 * old_header - (ipv4) source packet header, source: local subnet addr, dest: internet's ipv4 addr
Daniel Drowna45056e2012-03-23 10:42:54 -0500116 */
Lorenzo Colittid9084182013-03-22 00:42:21 +0900117void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol,
118 const struct iphdr *old_header) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500119 memset(ip6, 0, sizeof(struct ip6_hdr));
120
121 ip6->ip6_vfc = 6 << 4;
122 ip6->ip6_plen = htons(payload_len);
123 ip6->ip6_nxt = protocol;
124 ip6->ip6_hlim = old_header->ttl;
125
126 ip6->ip6_src = Global_Clatd_Config.ipv6_local_subnet;
127 ip6->ip6_dst = ipv4_dst_to_ipv6_dst(old_header->daddr);
128}
129
130/* function: icmp_to_icmp6
131 * translate ipv4 icmp to ipv6 icmp (only currently supports echo/echo reply)
Lorenzo Colittid9084182013-03-22 00:42:21 +0900132 * out - output packet
Daniel Drowna45056e2012-03-23 10:42:54 -0500133 * icmp - source packet icmp header
Lorenzo Colittid9084182013-03-22 00:42:21 +0900134 * checksum - pseudo-header checksum
Daniel Drowna45056e2012-03-23 10:42:54 -0500135 * payload - icmp payload
136 * payload_size - size of payload
Lorenzo Colittid9084182013-03-22 00:42:21 +0900137 * returns: the highest position in the output clat_packet that's filled in
Daniel Drowna45056e2012-03-23 10:42:54 -0500138 */
Lorenzo Colittid9084182013-03-22 00:42:21 +0900139int icmp_to_icmp6(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t checksum,
140 const char *payload, size_t payload_size) {
141 struct icmp6_hdr *icmp6_targ = out[pos].iov_base;
Daniel Drowna45056e2012-03-23 10:42:54 -0500142 uint32_t checksum_temp;
143
144 if((icmp->type != ICMP_ECHO) && (icmp->type != ICMP_ECHOREPLY)) {
Lorenzo Colittid9084182013-03-22 00:42:21 +0900145 logmsg_dbg(ANDROID_LOG_WARN,"icmp_to_icmp6/unhandled icmp type: 0x%x", icmp->type);
146 return 0;
Daniel Drowna45056e2012-03-23 10:42:54 -0500147 }
148
Lorenzo Colittid9084182013-03-22 00:42:21 +0900149 memset(icmp6_targ, 0, sizeof(struct icmp6_hdr));
150 icmp6_targ->icmp6_type = (icmp->type == ICMP_ECHO) ? ICMP6_ECHO_REQUEST : ICMP6_ECHO_REPLY;
151 icmp6_targ->icmp6_code = 0;
152 icmp6_targ->icmp6_id = icmp->un.echo.id;
153 icmp6_targ->icmp6_seq = icmp->un.echo.sequence;
Daniel Drowna45056e2012-03-23 10:42:54 -0500154
Lorenzo Colittid9084182013-03-22 00:42:21 +0900155 icmp6_targ->icmp6_cksum = 0;
156 checksum = ip_checksum_add(checksum, icmp6_targ, sizeof(struct icmp6_hdr));
157 checksum = ip_checksum_add(checksum, payload, payload_size);
158 icmp6_targ->icmp6_cksum = ip_checksum_finish(checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500159
Lorenzo Colittid9084182013-03-22 00:42:21 +0900160 out[pos].iov_len = sizeof(struct icmp6_hdr);
161 out[POS_PAYLOAD].iov_base = (char *) payload;
162 out[POS_PAYLOAD].iov_len = payload_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500163
Lorenzo Colittid9084182013-03-22 00:42:21 +0900164 return POS_PAYLOAD + 1;
Daniel Drowna45056e2012-03-23 10:42:54 -0500165}
166
167/* function: icmp6_to_icmp
168 * translate ipv6 icmp to ipv4 icmp (only currently supports echo/echo reply)
Lorenzo Colittid9084182013-03-22 00:42:21 +0900169 * out - output packet
Daniel Drowna45056e2012-03-23 10:42:54 -0500170 * icmp6 - source packet icmp6 header
Lorenzo Colittid9084182013-03-22 00:42:21 +0900171 * checksum - pseudo-header checksum (unused)
Daniel Drowna45056e2012-03-23 10:42:54 -0500172 * payload - icmp6 payload
173 * payload_size - size of payload
Lorenzo Colittid9084182013-03-22 00:42:21 +0900174 * returns: the highest position in the output clat_packet that's filled in
Daniel Drowna45056e2012-03-23 10:42:54 -0500175 */
Lorenzo Colittid9084182013-03-22 00:42:21 +0900176int icmp6_to_icmp(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32_t checksum,
177 const char *payload, size_t payload_size) {
178 struct icmphdr *icmp_targ = out[pos].iov_base;
Daniel Drowna45056e2012-03-23 10:42:54 -0500179
180 if((icmp6->icmp6_type != ICMP6_ECHO_REQUEST) && (icmp6->icmp6_type != ICMP6_ECHO_REPLY)) {
181 logmsg_dbg(ANDROID_LOG_WARN,"icmp6_to_icmp/unhandled icmp6 type: 0x%x",icmp6->icmp6_type);
Lorenzo Colittid9084182013-03-22 00:42:21 +0900182 return 0;
Daniel Drowna45056e2012-03-23 10:42:54 -0500183 }
184
Lorenzo Colittid9084182013-03-22 00:42:21 +0900185 memset(icmp_targ, 0, sizeof(struct icmphdr));
Daniel Drowna45056e2012-03-23 10:42:54 -0500186
Lorenzo Colittid9084182013-03-22 00:42:21 +0900187 icmp_targ->type = (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) ? ICMP_ECHO : ICMP_ECHOREPLY;
188 icmp_targ->code = 0x0;
189 icmp_targ->un.echo.id = icmp6->icmp6_id;
190 icmp_targ->un.echo.sequence = icmp6->icmp6_seq;
Daniel Drowna45056e2012-03-23 10:42:54 -0500191
Lorenzo Colittid9084182013-03-22 00:42:21 +0900192 icmp_targ->checksum = 0;
193 checksum = ip_checksum_add(0, icmp_targ, sizeof(struct icmphdr));
194 checksum = ip_checksum_add(checksum, (void *)payload, payload_size);
195 icmp_targ->checksum = ip_checksum_finish(checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500196
Lorenzo Colittid9084182013-03-22 00:42:21 +0900197 out[pos].iov_len = sizeof(struct icmphdr);
198 out[POS_PAYLOAD].iov_base = (char *) payload;
199 out[POS_PAYLOAD].iov_len = payload_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500200
Lorenzo Colittid9084182013-03-22 00:42:21 +0900201 return POS_PAYLOAD + 1;
202}
Daniel Drowna45056e2012-03-23 10:42:54 -0500203
Lorenzo Colittid9084182013-03-22 00:42:21 +0900204/* function: udp_packet
205 * takes a udp packet and sets it up for translation
206 * out - output packet
207 * udp - pointer to udp header in packet
208 * checksum - pseudo-header checksum
209 * len - size of ip payload
210 */
211int udp_packet(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum, size_t len) {
212 const char *payload;
213 size_t payload_size;
214
215 if(len < sizeof(struct udphdr)) {
216 logmsg_dbg(ANDROID_LOG_ERROR,"udp_packet/(too small)");
217 return 0;
218 }
219
220 payload = (const char *) (udp + 1);
221 payload_size = len - sizeof(struct udphdr);
222
223 return udp_translate(out, pos, udp, checksum, payload, payload_size);
224}
225
226/* function: tcp_packet
227 * takes a tcp packet and sets it up for translation
228 * out - output packet
229 * tcp - pointer to tcp header in packet
230 * checksum - pseudo-header checksum
231 * len - size of ip payload
232 * returns: the highest position in the output clat_packet that's filled in
233 */
234int tcp_packet(clat_packet out, int pos, const struct tcphdr *tcp, uint32_t checksum, size_t len) {
235 const char *payload;
236 size_t payload_size, header_size;
237
238 if(len < sizeof(struct tcphdr)) {
239 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/(too small)");
240 return 0;
241 }
242
243 if(tcp->doff < 5) {
244 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set to less than 5: %x", tcp->doff);
245 return 0;
246 }
247
248 if((size_t) tcp->doff*4 > len) {
249 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set too large: %x", tcp->doff);
250 return 0;
251 }
252
253 header_size = tcp->doff * 4;
254 payload = ((const char *) tcp) + header_size;
255 payload_size = len - header_size;
256
257 return tcp_translate(out, pos, tcp, header_size, checksum, payload, payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500258}
259
260/* function: udp_translate
261 * common between ipv4/ipv6 - setup checksum and send udp packet
Lorenzo Colittid9084182013-03-22 00:42:21 +0900262 * out - output packet
263 * udp - udp header
264 * checksum - pseudo-header checksum
265 * payload - tcp payload
Daniel Drowna45056e2012-03-23 10:42:54 -0500266 * payload_size - size of payload
Lorenzo Colittid9084182013-03-22 00:42:21 +0900267 * returns: the highest position in the output clat_packet that's filled in
Daniel Drowna45056e2012-03-23 10:42:54 -0500268 */
Lorenzo Colittid9084182013-03-22 00:42:21 +0900269int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t checksum,
270 const char *payload, size_t payload_size) {
271 struct udphdr *udp_targ = out[pos].iov_base;
Daniel Drowna45056e2012-03-23 10:42:54 -0500272
Lorenzo Colittid9084182013-03-22 00:42:21 +0900273 memcpy(udp_targ, udp, sizeof(struct udphdr));
274 udp_targ->check = 0; // reset checksum, to be calculated
Daniel Drowna45056e2012-03-23 10:42:54 -0500275
Lorenzo Colittid9084182013-03-22 00:42:21 +0900276 checksum = ip_checksum_add(checksum, udp_targ, sizeof(struct udphdr));
Daniel Drowna45056e2012-03-23 10:42:54 -0500277 checksum = ip_checksum_add(checksum, payload, payload_size);
Lorenzo Colittid9084182013-03-22 00:42:21 +0900278 udp_targ->check = ip_checksum_finish(checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500279
Lorenzo Colittid9084182013-03-22 00:42:21 +0900280 out[pos].iov_len = sizeof(struct udphdr);
281 out[POS_PAYLOAD].iov_base = (char *) payload;
282 out[POS_PAYLOAD].iov_len = payload_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500283
Lorenzo Colittid9084182013-03-22 00:42:21 +0900284 return POS_PAYLOAD + 1;
Daniel Drowna45056e2012-03-23 10:42:54 -0500285}
286
287/* function: tcp_translate
288 * common between ipv4/ipv6 - setup checksum and send tcp packet
Lorenzo Colittid9084182013-03-22 00:42:21 +0900289 * out - output packet
290 * tcp - tcp header
291 * header_size - size of tcp header including options
292 * checksum - partial checksum covering ipv4/ipv6 header
Daniel Drowna45056e2012-03-23 10:42:54 -0500293 * payload - tcp payload
294 * payload_size - size of payload
Lorenzo Colittid9084182013-03-22 00:42:21 +0900295 * returns: the highest position in the output clat_packet that's filled in
Daniel Drowna45056e2012-03-23 10:42:54 -0500296 *
297 * TODO: mss rewrite
298 * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented)
299 */
Lorenzo Colittid9084182013-03-22 00:42:21 +0900300int tcp_translate(clat_packet out, int pos, const struct tcphdr *tcp, size_t header_size,
301 uint32_t checksum, const char *payload, size_t payload_size) {
302 struct tcphdr *tcp_targ = out[pos].iov_base;
303 out[pos].iov_len = header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500304
Lorenzo Colittid9084182013-03-22 00:42:21 +0900305 if (header_size > MAX_TCP_HDR) {
306 // A TCP header cannot be more than MAX_TCP_HDR bytes long because it's a 4-bit field that
307 // counts in 4-byte words. So this can never happen unless there is a bug in the caller.
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900308 logmsg(ANDROID_LOG_ERROR, "tcp_translate: header too long %d > %d, truncating",
Lorenzo Colittid9084182013-03-22 00:42:21 +0900309 header_size, MAX_TCP_HDR);
310 header_size = MAX_TCP_HDR;
Daniel Drowna45056e2012-03-23 10:42:54 -0500311 }
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900312
Lorenzo Colittid9084182013-03-22 00:42:21 +0900313 memcpy(tcp_targ, tcp, header_size);
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900314
Lorenzo Colittid9084182013-03-22 00:42:21 +0900315 tcp_targ->check = 0;
316 checksum = ip_checksum_add(checksum, tcp_targ, header_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500317 checksum = ip_checksum_add(checksum, payload, payload_size);
Lorenzo Colittid9084182013-03-22 00:42:21 +0900318 tcp_targ->check = ip_checksum_finish(checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500319
Lorenzo Colittid9084182013-03-22 00:42:21 +0900320 out[POS_PAYLOAD].iov_base = (char *)payload;
321 out[POS_PAYLOAD].iov_len = payload_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500322
Lorenzo Colittid9084182013-03-22 00:42:21 +0900323 return POS_PAYLOAD + 1;
Daniel Drowna45056e2012-03-23 10:42:54 -0500324}