blob: 3ab23711ef81e15e95185bf18ae0bc5b8b7f818c [file] [log] [blame]
Daniel Drowna45056e2012-03-23 10:42:54 -05001/*
2 * Copyright 2012 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 * clatd.c - tun interface setup and main event loop
17 */
18#include <poll.h>
19#include <signal.h>
20#include <time.h>
21#include <stdio.h>
22#include <sys/types.h>
23#include <sys/ioctl.h>
24#include <sys/stat.h>
25#include <string.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <arpa/inet.h>
30#include <fcntl.h>
31
Nick Kralevich2edb7562013-02-28 14:15:22 -080032#include <sys/capability.h>
Lorenzo Colittid9084182013-03-22 00:42:21 +090033#include <sys/uio.h>
Daniel Drowna45056e2012-03-23 10:42:54 -050034#include <linux/prctl.h>
35#include <linux/if.h>
36#include <linux/if_tun.h>
37#include <linux/if_ether.h>
38
39#include <private/android_filesystem_config.h>
40
Lorenzo Colittid9084182013-03-22 00:42:21 +090041#include "translate.h"
Daniel Drowna45056e2012-03-23 10:42:54 -050042#include "clatd.h"
43#include "config.h"
44#include "logging.h"
45#include "setif.h"
46#include "setroute.h"
47#include "mtu.h"
48#include "getaddr.h"
49#include "dump.h"
50
51#define DEVICENAME6 "clat"
52#define DEVICENAME4 "clat4"
53
54int forwarding_fd = -1;
55volatile sig_atomic_t running = 1;
56
Daniel Drowna45056e2012-03-23 10:42:54 -050057/* function: set_forwarding
58 * enables/disables ipv6 forwarding
59 */
60void set_forwarding(int fd, const char *setting) {
61 /* we have to forward packets from the WAN to the tun interface */
62 if(write(fd, setting, strlen(setting)) < 0) {
63 logmsg(ANDROID_LOG_FATAL,"set_forwarding(%s) failed: %s", setting, strerror(errno));
64 exit(1);
65 }
66}
67
Lorenzo Colittibaf62992013-03-01 20:29:39 +090068/* function: stop_loop
69 * signal handler: stop the event loop
Daniel Drowna45056e2012-03-23 10:42:54 -050070 */
Lorenzo Colitti9477a462013-11-18 15:56:02 +090071void stop_loop() {
Daniel Drowna45056e2012-03-23 10:42:54 -050072 running = 0;
73}
74
75/* function: tun_open
76 * tries to open the tunnel device
77 */
78int tun_open() {
79 int fd;
80
81 fd = open("/dev/tun", O_RDWR);
82 if(fd < 0) {
83 fd = open("/dev/net/tun", O_RDWR);
84 }
85
86 return fd;
87}
88
89/* function: tun_alloc
90 * creates a tun interface and names it
91 * dev - the name for the new tun device
92 */
93int tun_alloc(char *dev, int fd) {
94 struct ifreq ifr;
95 int err;
96
97 memset(&ifr, 0, sizeof(ifr));
98
99 ifr.ifr_flags = IFF_TUN;
100 if( *dev ) {
101 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
102 ifr.ifr_name[IFNAMSIZ-1] = '\0';
103 }
104
105 if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
106 close(fd);
107 return err;
108 }
109 strcpy(dev, ifr.ifr_name);
110 return 0;
111}
112
113/* function: deconfigure_tun_ipv6
114 * removes the ipv6 route
115 * tunnel - tun device data
116 */
117void deconfigure_tun_ipv6(const struct tun_data *tunnel) {
118 int status;
119
120 status = if_route(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_subnet,
121 128, NULL, 1, 0, ROUTE_DELETE);
122 if(status < 0) {
123 logmsg(ANDROID_LOG_WARN,"deconfigure_tun_ipv6/if_route(6) failed: %s",strerror(-status));
124 }
125}
126
127/* function: configure_tun_ipv6
128 * configures the ipv6 route
129 * note: routes a /128 out of the (assumed routed to us) /64 to the CLAT interface
130 * tunnel - tun device data
131 */
132void configure_tun_ipv6(const struct tun_data *tunnel) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500133 int status;
134
135 status = if_route(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_subnet,
136 128, NULL, 1, 0, ROUTE_CREATE);
137 if(status < 0) {
138 logmsg(ANDROID_LOG_FATAL,"configure_tun_ipv6/if_route(6) failed: %s",strerror(-status));
139 exit(1);
140 }
141}
142
143/* function: interface_poll
144 * polls the uplink network interface for address changes
145 * tunnel - tun device data
146 */
147void interface_poll(const struct tun_data *tunnel) {
148 union anyip *interface_ip;
149
150 interface_ip = getinterface_ip(Global_Clatd_Config.default_pdp_interface, AF_INET6);
151 if(!interface_ip) {
152 logmsg(ANDROID_LOG_WARN,"unable to find an ipv6 ip on interface %s",Global_Clatd_Config.default_pdp_interface);
153 return;
154 }
155
156 config_generate_local_ipv6_subnet(&interface_ip->ip6);
157
158 if(!IN6_ARE_ADDR_EQUAL(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
159 char from_addr[INET6_ADDRSTRLEN], to_addr[INET6_ADDRSTRLEN];
160 inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, from_addr, sizeof(from_addr));
161 inet_ntop(AF_INET6, &interface_ip->ip6, to_addr, sizeof(to_addr));
162 logmsg(ANDROID_LOG_WARN, "clat subnet changed from %s to %s", from_addr, to_addr);
163
164 // remove old route
165 deconfigure_tun_ipv6(tunnel);
166
167 // add new route, start translating packets to the new prefix
168 memcpy(&Global_Clatd_Config.ipv6_local_subnet, &interface_ip->ip6, sizeof(struct in6_addr));
169 configure_tun_ipv6(tunnel);
170 }
171
172 free(interface_ip);
173}
174
175/* function: configure_tun_ip
176 * configures the ipv4 and ipv6 addresses on the tunnel interface
177 * tunnel - tun device data
178 */
179void configure_tun_ip(const struct tun_data *tunnel) {
Daniel Drowna45056e2012-03-23 10:42:54 -0500180 int status;
181
Lorenzo Colitti3ca03022013-03-27 12:39:10 +0900182 // Configure the interface before bringing it up. As soon as we bring the interface up, the
183 // framework will be notified and will assume the interface's configuration has been finalized.
184 status = add_address(tunnel->device4, AF_INET, &Global_Clatd_Config.ipv4_local_subnet,
185 32, &Global_Clatd_Config.ipv4_local_subnet);
186 if(status < 0) {
187 logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_address(4) failed: %s",strerror(-status));
188 exit(1);
189 }
Daniel Drowna45056e2012-03-23 10:42:54 -0500190
JP Abgrall4e0dd832013-12-20 14:51:26 -0800191 status = add_address(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_address,
192 64, NULL);
193 if(status < 0) {
194 logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_address(6) failed: %s",strerror(-status));
195 exit(1);
196 }
197
Daniel Drowna45056e2012-03-23 10:42:54 -0500198 if((status = if_up(tunnel->device6, Global_Clatd_Config.mtu)) < 0) {
199 logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(6) failed: %s",strerror(-status));
200 exit(1);
201 }
Lorenzo Colitti3ca03022013-03-27 12:39:10 +0900202
Daniel Drowna45056e2012-03-23 10:42:54 -0500203 if((status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu)) < 0) {
204 logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(4) failed: %s",strerror(-status));
205 exit(1);
206 }
Daniel Drowna45056e2012-03-23 10:42:54 -0500207
208 configure_tun_ipv6(tunnel);
Daniel Drowna45056e2012-03-23 10:42:54 -0500209}
210
211/* function: drop_root
212 * drops root privs but keeps the needed capability
213 */
214void drop_root() {
215 gid_t groups[] = { AID_INET };
216 if(setgroups(sizeof(groups)/sizeof(groups[0]), groups) < 0) {
217 logmsg(ANDROID_LOG_FATAL,"drop_root/setgroups failed: %s",strerror(errno));
218 exit(1);
219 }
220
221 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
222
223 if(setgid(AID_CLAT) < 0) {
224 logmsg(ANDROID_LOG_FATAL,"drop_root/setgid failed: %s",strerror(errno));
225 exit(1);
226 }
227 if(setuid(AID_CLAT) < 0) {
228 logmsg(ANDROID_LOG_FATAL,"drop_root/setuid failed: %s",strerror(errno));
229 exit(1);
230 }
231
232 struct __user_cap_header_struct header;
233 struct __user_cap_data_struct cap;
234 memset(&header, 0, sizeof(header));
235 memset(&cap, 0, sizeof(cap));
236
237 header.version = _LINUX_CAPABILITY_VERSION;
238 header.pid = 0; // 0 = change myself
239 cap.effective = cap.permitted = (1 << CAP_NET_ADMIN);
240
241 if(capset(&header, &cap) < 0) {
242 logmsg(ANDROID_LOG_FATAL,"drop_root/capset failed: %s",strerror(errno));
243 exit(1);
244 }
245}
246
247/* function: configure_interface
248 * reads the configuration and applies it to the interface
249 * uplink_interface - network interface to use to reach the ipv6 internet
250 * plat_prefix - PLAT prefix to use
251 * tunnel - tun device data
252 */
253void configure_interface(const char *uplink_interface, const char *plat_prefix, struct tun_data *tunnel) {
254 int error;
255
256 if(!read_config("/system/etc/clatd.conf", uplink_interface, plat_prefix)) {
257 logmsg(ANDROID_LOG_FATAL,"read_config failed");
258 exit(1);
259 }
260
261 if(Global_Clatd_Config.mtu > MAXMTU) {
262 logmsg(ANDROID_LOG_WARN,"Max MTU is %d, requested %d", MAXMTU, Global_Clatd_Config.mtu);
263 Global_Clatd_Config.mtu = MAXMTU;
264 }
265 if(Global_Clatd_Config.mtu <= 0) {
266 Global_Clatd_Config.mtu = getifmtu(Global_Clatd_Config.default_pdp_interface);
267 logmsg(ANDROID_LOG_WARN,"ifmtu=%d",Global_Clatd_Config.mtu);
268 }
269 if(Global_Clatd_Config.mtu < 1280) {
270 logmsg(ANDROID_LOG_WARN,"mtu too small = %d", Global_Clatd_Config.mtu);
271 Global_Clatd_Config.mtu = 1280;
272 }
273
274 if(Global_Clatd_Config.ipv4mtu <= 0 || (Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - 20)) {
275 Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu-20;
276 logmsg(ANDROID_LOG_WARN,"ipv4mtu now set to = %d",Global_Clatd_Config.ipv4mtu);
277 }
278
279 error = tun_alloc(tunnel->device6, tunnel->fd6);
280 if(error < 0) {
281 logmsg(ANDROID_LOG_FATAL,"tun_alloc failed: %s",strerror(errno));
282 exit(1);
283 }
284
285 error = tun_alloc(tunnel->device4, tunnel->fd4);
286 if(error < 0) {
287 logmsg(ANDROID_LOG_FATAL,"tun_alloc/4 failed: %s",strerror(errno));
288 exit(1);
289 }
290
291 configure_tun_ip(tunnel);
292}
293
Daniel Drowna45056e2012-03-23 10:42:54 -0500294/* function: read_packet
295 * reads a packet from the tunnel fd and passes it down the stack
296 * active_fd - tun file descriptor marked ready for reading
297 * tunnel - tun device data
298 */
299void read_packet(int active_fd, const struct tun_data *tunnel) {
300 ssize_t readlen;
301 char packet[PACKETLEN];
302
303 // in case something ignores the packet length
304 memset(packet, 0, PACKETLEN);
305
306 readlen = read(active_fd,packet,PACKETLEN);
307
308 if(readlen < 0) {
309 logmsg(ANDROID_LOG_WARN,"read_packet/read error: %s", strerror(errno));
310 return;
311 } else if(readlen == 0) {
312 logmsg(ANDROID_LOG_WARN,"read_packet/tun interface removed");
313 running = 0;
314 } else {
Daniel Drowna45056e2012-03-23 10:42:54 -0500315 ssize_t header_size = sizeof(struct tun_pi);
316
317 if(readlen < header_size) {
318 logmsg(ANDROID_LOG_WARN,"read_packet/short read: got %ld bytes", readlen);
319 return;
320 }
321
Lorenzo Colittif9390602014-02-13 12:53:35 +0900322 translate_packet(tunnel, (struct tun_pi *) packet, packet + header_size, readlen - header_size);
Daniel Drowna45056e2012-03-23 10:42:54 -0500323 }
324}
325
326/* function: event_loop
327 * reads packets from the tun network interface and passes them down the stack
328 * tunnel - tun device data
329 */
330void event_loop(const struct tun_data *tunnel) {
331 time_t last_interface_poll;
332 struct pollfd wait_fd[2];
333
334 // start the poll timer
335 last_interface_poll = time(NULL);
336
337 wait_fd[0].fd = tunnel->fd6;
338 wait_fd[0].events = POLLIN;
339 wait_fd[0].revents = 0;
340 wait_fd[1].fd = tunnel->fd4;
341 wait_fd[1].events = POLLIN;
342 wait_fd[1].revents = 0;
343
344 while(running) {
345 if(poll(wait_fd, 2, NO_TRAFFIC_INTERFACE_POLL_FREQUENCY*1000) == -1) {
346 if(errno != EINTR) {
347 logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno));
348 }
349 } else {
350 int i;
351 for(i = 0; i < 2; i++) {
352 if((wait_fd[i].revents & POLLIN) != 0) {
353 read_packet(wait_fd[i].fd,tunnel);
354 }
355 }
356 }
357
358 time_t now = time(NULL);
359 if(last_interface_poll < (now - INTERFACE_POLL_FREQUENCY)) {
360 interface_poll(tunnel);
361 last_interface_poll = now;
362 }
363 }
364}
365
366/* function: print_help
367 * in case the user is running this on the command line
368 */
369void print_help() {
370 printf("android-clat arguments:\n");
371 printf("-i [uplink interface]\n");
372 printf("-p [plat prefix]\n");
373}
374
375/* function: main
376 * allocate and setup the tun device, then run the event loop
377 */
378int main(int argc, char **argv) {
379 struct tun_data tunnel;
380 int opt;
381 char *uplink_interface = NULL, *plat_prefix = NULL;
382
383 strcpy(tunnel.device6, DEVICENAME6);
384 strcpy(tunnel.device4, DEVICENAME4);
385
386 while((opt = getopt(argc, argv, "i:p:h")) != -1) {
387 switch(opt) {
388 case 'i':
389 uplink_interface = optarg;
390 break;
391 case 'p':
392 plat_prefix = optarg;
393 break;
394 case 'h':
395 default:
396 print_help();
397 exit(1);
398 break;
399 }
400 }
401
402 if(uplink_interface == NULL) {
Lorenzo Colittid9084182013-03-22 00:42:21 +0900403 logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
Daniel Drowna45056e2012-03-23 10:42:54 -0500404 printf("I need an interface\n");
405 exit(1);
406 }
Lorenzo Colittid9084182013-03-22 00:42:21 +0900407 logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s", CLATD_VERSION, uplink_interface);
Daniel Drowna45056e2012-03-23 10:42:54 -0500408
409 // open the tunnel device before dropping privs
410 tunnel.fd6 = tun_open();
411 if(tunnel.fd6 < 0) {
JP Abgrall4e0dd832013-12-20 14:51:26 -0800412 logmsg(ANDROID_LOG_FATAL, "tun_open6 failed: %s", strerror(errno));
Daniel Drowna45056e2012-03-23 10:42:54 -0500413 exit(1);
414 }
415
416 tunnel.fd4 = tun_open();
417 if(tunnel.fd4 < 0) {
Lorenzo Colittid9084182013-03-22 00:42:21 +0900418 logmsg(ANDROID_LOG_FATAL, "tun_open4 failed: %s", strerror(errno));
Daniel Drowna45056e2012-03-23 10:42:54 -0500419 exit(1);
420 }
421
422 // open the forwarding configuration before dropping privs
423 forwarding_fd = open("/proc/sys/net/ipv6/conf/all/forwarding", O_RDWR);
424 if(forwarding_fd < 0) {
Lorenzo Colittid9084182013-03-22 00:42:21 +0900425 logmsg(ANDROID_LOG_FATAL,"open /proc/sys/net/ipv6/conf/all/forwarding failed: %s",
426 strerror(errno));
Daniel Drowna45056e2012-03-23 10:42:54 -0500427 exit(1);
428 }
429
Daniel Drowna45056e2012-03-23 10:42:54 -0500430 // run under a regular user
431 drop_root();
432
Lorenzo Colittibaf62992013-03-01 20:29:39 +0900433 // When run from netd, the environment variable ANDROID_DNS_MODE is set to
434 // "local", but that only works for the netd process itself.
435 unsetenv("ANDROID_DNS_MODE");
Daniel Drowna45056e2012-03-23 10:42:54 -0500436
437 configure_interface(uplink_interface, plat_prefix, &tunnel);
438
Daniel Drowna45056e2012-03-23 10:42:54 -0500439 set_forwarding(forwarding_fd,"1\n");
440
Lorenzo Colittibaf62992013-03-01 20:29:39 +0900441 // Loop until someone sends us a signal or brings down the tun interface.
442 if(signal(SIGTERM, stop_loop) == SIG_ERR) {
443 logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno));
444 exit(1);
445 }
446 event_loop(&tunnel);
Daniel Drowna45056e2012-03-23 10:42:54 -0500447
448 set_forwarding(forwarding_fd,"0\n");
Lorenzo Colittibaf62992013-03-01 20:29:39 +0900449 logmsg(ANDROID_LOG_INFO,"Shutting down clat on %s", uplink_interface);
Daniel Drowna45056e2012-03-23 10:42:54 -0500450
451 return 0;
452}