clatd: change to pass in tun filedescriptor via command line

Test: atest clatd_test, built and installed on aosp_blueline device
  connected to ipv6-only wifi network: ping 8.8.8.8 still works
  and it is via v4-wlan0 clat tun interface

Bug: 65674744
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I8c9e235e9a5bf1a1436e8dc3af8d0aa86f6dc1a5
diff --git a/main.c b/main.c
index 54d12d1..9e796fd 100644
--- a/main.c
+++ b/main.c
@@ -46,6 +46,7 @@
   printf("-6 [IPv6 address]\n");
   printf("-n [NetId]\n");
   printf("-m [socket mark]\n");
+  printf("-t [tun file descriptor number]\n");
 }
 
 /* function: main
@@ -55,12 +56,12 @@
   struct tun_data tunnel;
   int opt;
   char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL, *mark_str = NULL;
-  char *v4_addr = NULL, *v6_addr = NULL;
+  char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL;
   unsigned net_id = NETID_UNSET;
   uint32_t mark   = MARK_UNSET;
   unsigned len;
 
-  while ((opt = getopt(argc, argv, "i:p:4:6:n:m:h")) != -1) {
+  while ((opt = getopt(argc, argv, "i:p:4:6:n:m:t:h")) != -1) {
     switch (opt) {
       case 'i':
         uplink_interface = optarg;
@@ -80,6 +81,9 @@
       case 'm':
         mark_str = optarg;
         break;
+      case 't':
+        tunfd_str = optarg;
+        break;
       case 'h':
         print_help();
         exit(0);
@@ -104,6 +108,15 @@
     exit(1);
   }
 
+  if (tunfd_str != NULL && !parse_int(tunfd_str, &tunnel.fd4)) {
+    logmsg(ANDROID_LOG_FATAL, "invalid tunfd %s", tunfd_str);
+    exit(1);
+  }
+  if (!tunnel.fd4) {
+    logmsg(ANDROID_LOG_FATAL, "no tunfd specified on commandline.");
+    exit(1);
+  }
+
   len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface);
   if (len >= sizeof(tunnel.device4)) {
     logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4);
@@ -124,13 +137,6 @@
   // keeps only admin capability
   set_capability(1 << CAP_NET_ADMIN);
 
-  // we can create tun devices as non-root because we're in the VPN group.
-  tunnel.fd4 = tun_open();
-  if (tunnel.fd4 < 0) {
-    logmsg(ANDROID_LOG_FATAL, "tun_open4 failed: %s", strerror(errno));
-    exit(1);
-  }
-
   // When run from netd, the environment variable ANDROID_DNS_MODE is set to
   // "local", but that only works for the netd process itself. Removing the
   // following line causes XLAT failure in permissive mode.