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