Home | History | Annotate | Download | only in android-clat
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      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  * main.c - main function
     17  */
     18 
     19 #include <errno.h>
     20 #include <netinet/in.h>
     21 #include <stdint.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <sys/capability.h>
     25 #include <unistd.h>
     26 
     27 #include "resolv_netid.h"
     28 
     29 #include "clatd.h"
     30 #include "common.h"
     31 #include "config.h"
     32 #include "logging.h"
     33 #include "setif.h"
     34 #include "tun.h"
     35 
     36 #define DEVICEPREFIX "v4-"
     37 
     38 /* function: print_help
     39  * in case the user is running this on the command line
     40  */
     41 void print_help() {
     42   printf("android-clat arguments:\n");
     43   printf("-i [uplink interface]\n");
     44   printf("-p [plat prefix]\n");
     45   printf("-4 [IPv4 address]\n");
     46   printf("-6 [IPv6 address]\n");
     47   printf("-n [NetId]\n");
     48   printf("-m [socket mark]\n");
     49   printf("-t [tun file descriptor number]\n");
     50 }
     51 
     52 /* function: main
     53  * allocate and setup the tun device, then run the event loop
     54  */
     55 int main(int argc, char **argv) {
     56   struct tun_data tunnel;
     57   int opt;
     58   char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL, *mark_str = NULL;
     59   char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL;
     60   unsigned net_id = NETID_UNSET;
     61   uint32_t mark   = MARK_UNSET;
     62   unsigned len;
     63 
     64   while ((opt = getopt(argc, argv, "i:p:4:6:n:m:t:h")) != -1) {
     65     switch (opt) {
     66       case 'i':
     67         uplink_interface = optarg;
     68         break;
     69       case 'p':
     70         plat_prefix = optarg;
     71         break;
     72       case '4':
     73         v4_addr = optarg;
     74         break;
     75       case '6':
     76         v6_addr = optarg;
     77         break;
     78       case 'n':
     79         net_id_str = optarg;
     80         break;
     81       case 'm':
     82         mark_str = optarg;
     83         break;
     84       case 't':
     85         tunfd_str = optarg;
     86         break;
     87       case 'h':
     88         print_help();
     89         exit(0);
     90       default:
     91         logmsg(ANDROID_LOG_FATAL, "Unknown option -%c. Exiting.", (char)optopt);
     92         exit(1);
     93     }
     94   }
     95 
     96   if (uplink_interface == NULL) {
     97     logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
     98     exit(1);
     99   }
    100 
    101   if (net_id_str != NULL && !parse_unsigned(net_id_str, &net_id)) {
    102     logmsg(ANDROID_LOG_FATAL, "invalid NetID %s", net_id_str);
    103     exit(1);
    104   }
    105 
    106   if (mark_str != NULL && !parse_unsigned(mark_str, &mark)) {
    107     logmsg(ANDROID_LOG_FATAL, "invalid mark %s", mark_str);
    108     exit(1);
    109   }
    110 
    111   if (tunfd_str != NULL && !parse_int(tunfd_str, &tunnel.fd4)) {
    112     logmsg(ANDROID_LOG_FATAL, "invalid tunfd %s", tunfd_str);
    113     exit(1);
    114   }
    115   if (!tunnel.fd4) {
    116     logmsg(ANDROID_LOG_FATAL, "no tunfd specified on commandline.");
    117     exit(1);
    118   }
    119 
    120   len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface);
    121   if (len >= sizeof(tunnel.device4)) {
    122     logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4);
    123     exit(1);
    124   }
    125 
    126   logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s netid=%s mark=%s plat=%s v4=%s v6=%s",
    127          CLATD_VERSION, uplink_interface, net_id_str ? net_id_str : "(none)",
    128          mark_str ? mark_str : "(none)", plat_prefix ? plat_prefix : "(none)",
    129          v4_addr ? v4_addr : "(none)", v6_addr ? v6_addr : "(none)");
    130 
    131   // run under a regular user but keep needed capabilities
    132   drop_root_but_keep_caps();
    133 
    134   // open our raw sockets before dropping privs
    135   open_sockets(&tunnel, mark);
    136 
    137   // keeps only admin capability
    138   set_capability(1 << CAP_NET_ADMIN);
    139 
    140   // When run from netd, the environment variable ANDROID_DNS_MODE is set to
    141   // "local", but that only works for the netd process itself. Removing the
    142   // following line causes XLAT failure in permissive mode.
    143   unsetenv("ANDROID_DNS_MODE");
    144 
    145   configure_interface(uplink_interface, plat_prefix, v4_addr, v6_addr, &tunnel, net_id);
    146 
    147   // Drop all remaining capabilities.
    148   set_capability(0);
    149 
    150   // Loop until someone sends us a signal or brings down the tun interface.
    151   if (signal(SIGTERM, stop_loop) == SIG_ERR) {
    152     logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno));
    153     exit(1);
    154   }
    155 
    156   event_loop(&tunnel);
    157 
    158   logmsg(ANDROID_LOG_INFO, "Shutting down clat on %s", uplink_interface);
    159   del_anycast_address(tunnel.write_fd6, &Global_Clatd_Config.ipv6_local_subnet);
    160 
    161   return 0;
    162 }
    163