blob: 936c7816f5b7c3b36fc14b91d0a59d35f58f3b8c [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>
19#include <sys/uio.h>
20
21#include <netinet/in.h>
22#include <netinet/ip.h>
23#include <netinet/ip_icmp.h>
24#include <netinet/udp.h>
25#include <netinet/tcp.h>
26#include <netinet/ip6.h>
27#include <netinet/icmp6.h>
28#include <linux/icmp.h>
29
30#include "checksum.h"
31#include "clatd.h"
32#include "config.h"
33#include "logging.h"
34#include "debug.h"
35
36/* function: fill_tun_header
37 * fill in the header for the tun fd
38 * tun_header - tunnel header, already allocated
39 * proto - ethernet protocol id: ETH_P_IP(ipv4) or ETH_P_IPV6(ipv6)
40 */
41void fill_tun_header(struct tun_pi *tun_header, uint16_t proto) {
42 tun_header->flags = 0;
43 tun_header->proto = htons(proto);
44}
45
46/* function: ipv6_src_to_ipv4_src
47 * return the corresponding ipv4 address for the given ipv6 address
48 * sourceaddr - ipv6 source address
49 */
50uint32_t ipv6_src_to_ipv4_src(const struct in6_addr *sourceaddr) {
51 // assumes a /96 plat subnet
52 return sourceaddr->s6_addr32[3];
53}
54
55/* function: fill_ip_header
56 * generating an ipv4 header from an ipv6 header (called by the layer 4 protocol-specific functions)
57 * ip_targ - (ipv4) target packet header, source addr: original ipv4 addr, dest addr: local subnet addr
58 * payload_len - length of other data inside packet
59 * protocol - protocol number (tcp, udp, etc)
60 * old_header - (ipv6) source packet header, source addr: nat64 prefix, dest addr: local subnet prefix
61 */
62void fill_ip_header(struct iphdr *ip_targ, uint16_t payload_len, uint8_t protocol, const struct ip6_hdr *old_header) {
63 memset(ip_targ, 0, sizeof(ip_targ));
64
65 ip_targ->ihl = 5;
66 ip_targ->version = 4;
67 ip_targ->tos = 0;
68 ip_targ->tot_len = htons(sizeof(struct iphdr) + payload_len);
69 ip_targ->id = 0;
70 ip_targ->frag_off = htons(IP_DF);
71 ip_targ->ttl = old_header->ip6_hlim;
72 ip_targ->protocol = protocol;
73 ip_targ->check = 0;
74
75 ip_targ->saddr = ipv6_src_to_ipv4_src(&old_header->ip6_src);
76 ip_targ->daddr = Global_Clatd_Config.ipv4_local_subnet.s_addr;
77
78 ip_targ->check = ip_checksum(ip_targ, sizeof(struct iphdr));
79}
80
81/* function: ipv4_dst_to_ipv6_dst
82 * return the corresponding ipv6 address for the given ipv4 address
83 * destination - ipv4 destination address (network byte order)
84 */
85struct in6_addr ipv4_dst_to_ipv6_dst(uint32_t destination) {
86 struct in6_addr v6_destination;
87
88 // assumes a /96 plat subnet
89 v6_destination = Global_Clatd_Config.plat_subnet;
90 v6_destination.s6_addr32[3] = destination;
91
92 return v6_destination;
93}
94
95/* function: fill_ip6_header
96 * generating an ipv6 header from an ipv4 header (called by the layer 4 protocol-specific functions)
97 * ip6 - (ipv6) target packet header, source addr: local subnet prefix, dest addr: nat64 prefix
98 * payload_len - length of other data inside packet
99 * protocol - protocol number (tcp, udp, etc)
100 * old_header - (ipv4) source packet header, source addr: local subnet addr, dest addr: internet's ipv4 addr
101 */
102void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol, const struct iphdr *old_header) {
103 memset(ip6, 0, sizeof(struct ip6_hdr));
104
105 ip6->ip6_vfc = 6 << 4;
106 ip6->ip6_plen = htons(payload_len);
107 ip6->ip6_nxt = protocol;
108 ip6->ip6_hlim = old_header->ttl;
109
110 ip6->ip6_src = Global_Clatd_Config.ipv6_local_subnet;
111 ip6->ip6_dst = ipv4_dst_to_ipv6_dst(old_header->daddr);
112}
113
114/* function: icmp_to_icmp6
115 * translate ipv4 icmp to ipv6 icmp (only currently supports echo/echo reply)
116 * fd - tun interface fd
117 * ip - source packet ipv4 header
118 * icmp - source packet icmp header
119 * payload - icmp payload
120 * payload_size - size of payload
121 */
122void icmp_to_icmp6(int fd, const struct iphdr *ip, const struct icmphdr *icmp, const char *payload, size_t payload_size) {
123 struct ip6_hdr ip6_targ;
124 struct icmp6_hdr icmp6_targ;
125 struct iovec io_targ[4];
126 struct tun_pi tun_header;
127 uint32_t checksum_temp;
128
129 if((icmp->type != ICMP_ECHO) && (icmp->type != ICMP_ECHOREPLY)) {
130 logmsg_dbg(ANDROID_LOG_WARN,"icmp_to_icmp6/unhandled icmp type: 0x%x",icmp->type);
131 return;
132 }
133
134 fill_tun_header(&tun_header,ETH_P_IPV6);
135
136 fill_ip6_header(&ip6_targ,payload_size + sizeof(icmp6_targ),IPPROTO_ICMPV6,ip);
137
138 memset(&icmp6_targ, 0, sizeof(icmp6_targ));
139 icmp6_targ.icmp6_type = (icmp->type == ICMP_ECHO) ? ICMP6_ECHO_REQUEST : ICMP6_ECHO_REPLY;
140 icmp6_targ.icmp6_code = 0;
141 icmp6_targ.icmp6_cksum = 0;
142 icmp6_targ.icmp6_id = icmp->un.echo.id;
143 icmp6_targ.icmp6_seq = icmp->un.echo.sequence;
144
Lorenzo Colitti02786272013-04-08 18:02:24 +0900145 checksum_temp = ipv6_pseudo_header_checksum(0, &ip6_targ, sizeof(icmp6_targ) + payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500146 checksum_temp = ip_checksum_add(checksum_temp, &icmp6_targ, sizeof(icmp6_targ));
147 checksum_temp = ip_checksum_add(checksum_temp, payload, payload_size);
148 icmp6_targ.icmp6_cksum = ip_checksum_finish(checksum_temp);
149
150 io_targ[0].iov_base = &tun_header;
151 io_targ[0].iov_len = sizeof(tun_header);
152 io_targ[1].iov_base = &ip6_targ;
153 io_targ[1].iov_len = sizeof(ip6_targ);
154 io_targ[2].iov_base = &icmp6_targ;
155 io_targ[2].iov_len = sizeof(icmp6_targ);
156 io_targ[3].iov_base = (char *)payload;
157 io_targ[3].iov_len = payload_size;
158
159 writev(fd, io_targ, 4);
160}
161
162/* function: icmp6_to_icmp
163 * translate ipv6 icmp to ipv4 icmp (only currently supports echo/echo reply)
164 * fd - tun interface fd
165 * ip6 - source packet ipv6 header
166 * icmp6 - source packet icmp6 header
167 * payload - icmp6 payload
168 * payload_size - size of payload
169 */
170void icmp6_to_icmp(int fd, const struct ip6_hdr *ip6, const struct icmp6_hdr *icmp6, const char *payload, size_t payload_size) {
171 struct iphdr ip_targ;
172 struct icmphdr icmp_targ;
173 struct iovec io_targ[4];
174 struct tun_pi tun_header;
175 uint32_t temp_icmp_checksum;
176
177 if((icmp6->icmp6_type != ICMP6_ECHO_REQUEST) && (icmp6->icmp6_type != ICMP6_ECHO_REPLY)) {
178 logmsg_dbg(ANDROID_LOG_WARN,"icmp6_to_icmp/unhandled icmp6 type: 0x%x",icmp6->icmp6_type);
179 return;
180 }
181
182 memset(&icmp_targ, 0, sizeof(icmp_targ));
183
184 fill_tun_header(&tun_header,ETH_P_IP);
185 fill_ip_header(&ip_targ,sizeof(icmp_targ) + payload_size, IPPROTO_ICMP, ip6);
186
187 icmp_targ.type = (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) ? ICMP_ECHO : ICMP_ECHOREPLY;
188 icmp_targ.code = 0x0;
189 icmp_targ.checksum = 0;
190 icmp_targ.un.echo.id = icmp6->icmp6_id;
191 icmp_targ.un.echo.sequence = icmp6->icmp6_seq;
192
193 temp_icmp_checksum = ip_checksum_add(0, &icmp_targ, sizeof(icmp_targ));
194 temp_icmp_checksum = ip_checksum_add(temp_icmp_checksum, (void *)payload, payload_size);
195 icmp_targ.checksum = ip_checksum_finish(temp_icmp_checksum);
196
197 io_targ[0].iov_base = &tun_header;
198 io_targ[0].iov_len = sizeof(tun_header);
199 io_targ[1].iov_base = &ip_targ;
200 io_targ[1].iov_len = sizeof(ip_targ);
201 io_targ[2].iov_base = &icmp_targ;
202 io_targ[2].iov_len = sizeof(icmp_targ);
203 io_targ[3].iov_base = (char *)payload;
204 io_targ[3].iov_len = payload_size;
205
206 writev(fd, io_targ, 4);
207}
208
209/* function: udp_translate
210 * common between ipv4/ipv6 - setup checksum and send udp packet
211 * fd - tun interface fd
212 * udp - source packet udp header
213 * payload - udp payload
214 * payload_size - size of payload
215 * io_targ - iovec with tun and ipv4/ipv6 header (see below)
216 * array position 0 - tun header
217 * array position 1 - ipv4/ipv6 header
218 * array position 2 - empty (will be udp header)
219 * array position 3 - empty (will be payload)
220 * checksum - partial checksum covering ipv4/ipv6 header
221 */
222void udp_translate(int fd, const struct udphdr *udp, const char *payload, size_t payload_size, struct iovec *io_targ, uint32_t checksum) {
223 struct udphdr udp_targ;
224
225 memcpy(&udp_targ, udp, sizeof(udp_targ));
226 udp_targ.check = 0; // reset checksum, to be calculated
227
228 checksum = ip_checksum_add(checksum, &udp_targ, sizeof(struct udphdr));
229 checksum = ip_checksum_add(checksum, payload, payload_size);
230 udp_targ.check = ip_checksum_finish(checksum);
231
232 io_targ[2].iov_base = &udp_targ;
233 io_targ[2].iov_len = sizeof(udp_targ);
234 io_targ[3].iov_base = (char *)payload;
235 io_targ[3].iov_len = payload_size;
236
237 writev(fd, io_targ, 4);
238}
239
240/* function: udp_to_udp6
241 * translate ipv4 udp to ipv6 udp
242 * fd - tun interface fd
243 * ip - source packet ipv4 header
244 * udp - source packet udp header
245 * payload - udp payload
246 * payload_size - size of payload
247 */
248void udp_to_udp6(int fd, const struct iphdr *ip, const struct udphdr *udp, const char *payload, size_t payload_size) {
249 struct ip6_hdr ip6_targ;
250 struct iovec io_targ[4];
251 struct tun_pi tun_header;
252 uint32_t checksum;
253
254 fill_tun_header(&tun_header,ETH_P_IPV6);
255
256 fill_ip6_header(&ip6_targ,payload_size + sizeof(struct udphdr),IPPROTO_UDP,ip);
257
Lorenzo Colitti02786272013-04-08 18:02:24 +0900258 checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, sizeof(*udp) + payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500259
260 io_targ[0].iov_base = &tun_header;
261 io_targ[0].iov_len = sizeof(tun_header);
262 io_targ[1].iov_base = &ip6_targ;
263 io_targ[1].iov_len = sizeof(ip6_targ);
264
265 udp_translate(fd,udp,payload,payload_size,io_targ,checksum);
266}
267
268/* function: udp6_to_udp
269 * translate ipv6 udp to ipv4 udp
270 * fd - tun interface fd
271 * ip6 - source packet ipv6 header
272 * udp - source packet udp header
273 * payload - udp payload
274 * payload_size - size of payload
275 */
276void udp6_to_udp(int fd, const struct ip6_hdr *ip6, const struct udphdr *udp, const char *payload, size_t payload_size) {
277 struct iphdr ip_targ;
278 struct iovec io_targ[4];
279 struct tun_pi tun_header;
280 uint32_t checksum;
281
282 fill_tun_header(&tun_header,ETH_P_IP);
283
284 fill_ip_header(&ip_targ,payload_size + sizeof(struct udphdr),IPPROTO_UDP,ip6);
285
Lorenzo Colitti02786272013-04-08 18:02:24 +0900286 checksum = ipv4_pseudo_header_checksum(0, &ip_targ, sizeof(*udp) + payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500287
288 io_targ[0].iov_base = &tun_header;
289 io_targ[0].iov_len = sizeof(tun_header);
290 io_targ[1].iov_base = &ip_targ;
291 io_targ[1].iov_len = sizeof(ip_targ);
292
293 udp_translate(fd,udp,payload,payload_size,io_targ,checksum);
294}
295
296/* function: tcp_translate
297 * common between ipv4/ipv6 - setup checksum and send tcp packet
298 * fd - tun interface fd
299 * tcp - source packet tcp header
300 * payload - tcp payload
301 * payload_size - size of payload
302 * io_targ - iovec with tun and ipv4/ipv6 header (see below)
303 * array position 0 - tun header
304 * array position 1 - ipv4/ipv6 header
305 * array position 2 - empty (will be tcp header)
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900306 * array position 3 - empty (will be payload)
Daniel Drowna45056e2012-03-23 10:42:54 -0500307 * checksum - partial checksum covering ipv4/ipv6 header
Daniel Drowna45056e2012-03-23 10:42:54 -0500308 *
309 * TODO: mss rewrite
310 * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented)
311 */
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900312void tcp_translate(int fd, const struct tcphdr *tcp, size_t header_size, const char *payload,
313 size_t payload_size, struct iovec *io_targ, uint32_t checksum) {
314 union {
315 // Reserve space for the maximum size of the TCP header, including options. The TCP header
316 // length field is 4 bits long and counts 4-byte words, so it can be at most 60 bytes.
317 char buf[15 * 4];
318 struct tcphdr tcp;
319 } header;
Daniel Drowna45056e2012-03-23 10:42:54 -0500320
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900321 if (header_size > sizeof(header.buf)) {
322 // A TCP header cannot be more than 60 bytes long, so this can never happen unless there is a
323 // bug in the caller.
324 logmsg(ANDROID_LOG_ERROR, "tcp_translate: header too long %d > %d, truncating",
325 header_size, sizeof(header.buf));
326 header_size = sizeof(header.buf);
Daniel Drowna45056e2012-03-23 10:42:54 -0500327 }
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900328
329 memcpy(&header, tcp, header_size);
330
331 header.tcp.check = 0;
332 checksum = ip_checksum_add(checksum, &header, header_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500333 checksum = ip_checksum_add(checksum, payload, payload_size);
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900334 header.tcp.check = ip_checksum_finish(checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500335
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900336 io_targ[2].iov_base = &header;
337 io_targ[2].iov_len = header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500338
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900339 io_targ[3].iov_base = (char *)payload;
340 io_targ[3].iov_len = payload_size;
Daniel Drowna45056e2012-03-23 10:42:54 -0500341}
342
343/* function: tcp_to_tcp6
344 * translate ipv4 tcp to ipv6 tcp
345 * fd - tun interface fd
346 * ip - source packet ipv4 header
347 * tcp - source packet tcp header
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900348 * header_size - size of tcp header including options
Daniel Drowna45056e2012-03-23 10:42:54 -0500349 * payload - tcp payload
350 * payload_size - size of payload
Daniel Drowna45056e2012-03-23 10:42:54 -0500351 */
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900352void tcp_to_tcp6(int fd, const struct iphdr *ip, const struct tcphdr *tcp, size_t header_size,
353 const char *payload, size_t payload_size) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500354 struct ip6_hdr ip6_targ;
355 struct iovec io_targ[5];
356 struct tun_pi tun_header;
357 uint32_t checksum;
358
359 fill_tun_header(&tun_header,ETH_P_IPV6);
360
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900361 fill_ip6_header(&ip6_targ, header_size + payload_size, IPPROTO_TCP, ip);
Daniel Drowna45056e2012-03-23 10:42:54 -0500362
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900363 checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, header_size + payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500364
365 io_targ[0].iov_base = &tun_header;
366 io_targ[0].iov_len = sizeof(tun_header);
367 io_targ[1].iov_base = &ip6_targ;
368 io_targ[1].iov_len = sizeof(ip6_targ);
369
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900370 tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500371}
372
373/* function: tcp6_to_tcp
374 * translate ipv6 tcp to ipv4 tcp
375 * fd - tun interface fd
376 * ip6 - source packet ipv6 header
377 * tcp - source packet tcp header
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900378 * header_size - size of tcp header including options
Daniel Drowna45056e2012-03-23 10:42:54 -0500379 * payload - tcp payload
380 * payload_size - size of payload
Daniel Drowna45056e2012-03-23 10:42:54 -0500381 */
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900382void tcp6_to_tcp(int fd, const struct ip6_hdr *ip6, const struct tcphdr *tcp, size_t header_size,
383 const char *payload, size_t payload_size) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500384 struct iphdr ip_targ;
385 struct iovec io_targ[5];
386 struct tun_pi tun_header;
387 uint32_t checksum;
388
389 fill_tun_header(&tun_header,ETH_P_IP);
390
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900391 fill_ip_header(&ip_targ, header_size + payload_size, IPPROTO_TCP, ip6);
Daniel Drowna45056e2012-03-23 10:42:54 -0500392
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900393 checksum = ipv4_pseudo_header_checksum(0, &ip_targ, header_size + payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500394
395 io_targ[0].iov_base = &tun_header;
396 io_targ[0].iov_len = sizeof(tun_header);
397 io_targ[1].iov_base = &ip_targ;
398 io_targ[1].iov_len = sizeof(ip_targ);
399
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +0900400 tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum);
Daniel Drowna45056e2012-03-23 10:42:54 -0500401}