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