• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <arpa/inet.h>
20 #include <errno.h>
21 #include <netinet/in.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/capability.h>
26 #include <unistd.h>
27 
28 #include "clatd.h"
29 #include "common.h"
30 #include "config.h"
31 #include "logging.h"
32 
33 #define DEVICEPREFIX "v4-"
34 
35 /* function: stop_loop
36  * signal handler: stop the event loop
37  */
stop_loop()38 static void stop_loop() { running = 0; };
39 
40 /* function: print_help
41  * in case the user is running this on the command line
42  */
print_help()43 void print_help() {
44   printf("android-clat arguments:\n");
45   printf("-i [uplink interface]\n");
46   printf("-p [plat prefix]\n");
47   printf("-4 [IPv4 address]\n");
48   printf("-6 [IPv6 address]\n");
49   printf("-t [tun file descriptor number]\n");
50   printf("-r [read socket descriptor number]\n");
51   printf("-w [write socket descriptor number]\n");
52 }
53 
54 /* function: main
55  * allocate and setup the tun device, then run the event loop
56  */
main(int argc,char ** argv)57 int main(int argc, char **argv) {
58   struct tun_data tunnel;
59   int opt;
60   char *uplink_interface = NULL, *plat_prefix = NULL;
61   char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL, *read_sock_str = NULL,
62        *write_sock_str = NULL;
63   unsigned len;
64 
65   while ((opt = getopt(argc, argv, "i:p:4:6:t:r:w:h")) != -1) {
66     switch (opt) {
67       case 'i':
68         uplink_interface = optarg;
69         break;
70       case 'p':
71         plat_prefix = optarg;
72         break;
73       case '4':
74         v4_addr = optarg;
75         break;
76       case '6':
77         v6_addr = optarg;
78         break;
79       case 't':
80         tunfd_str = optarg;
81         break;
82       case 'r':
83         read_sock_str = optarg;
84         break;
85       case 'w':
86         write_sock_str = optarg;
87         break;
88       case 'h':
89         print_help();
90         exit(0);
91       default:
92         logmsg(ANDROID_LOG_FATAL, "Unknown option -%c. Exiting.", (char)optopt);
93         exit(1);
94     }
95   }
96 
97   if (uplink_interface == NULL) {
98     logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
99     exit(1);
100   }
101 
102   if (tunfd_str != NULL && !parse_int(tunfd_str, &tunnel.fd4)) {
103     logmsg(ANDROID_LOG_FATAL, "invalid tunfd %s", tunfd_str);
104     exit(1);
105   }
106   if (!tunnel.fd4) {
107     logmsg(ANDROID_LOG_FATAL, "no tunfd specified on commandline.");
108     exit(1);
109   }
110 
111   if (read_sock_str != NULL && !parse_int(read_sock_str, &tunnel.read_fd6)) {
112     logmsg(ANDROID_LOG_FATAL, "invalid read socket %s", read_sock_str);
113     exit(1);
114   }
115   if (!tunnel.read_fd6) {
116     logmsg(ANDROID_LOG_FATAL, "no read_fd6 specified on commandline.");
117     exit(1);
118   }
119 
120   if (write_sock_str != NULL && !parse_int(write_sock_str, &tunnel.write_fd6)) {
121     logmsg(ANDROID_LOG_FATAL, "invalid write socket %s", write_sock_str);
122     exit(1);
123   }
124   if (!tunnel.write_fd6) {
125     logmsg(ANDROID_LOG_FATAL, "no write_fd6 specified on commandline.");
126     exit(1);
127   }
128 
129   len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface);
130   if (len >= sizeof(tunnel.device4)) {
131     logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4);
132     exit(1);
133   }
134 
135   Global_Clatd_Config.native_ipv6_interface = uplink_interface;
136   if (!plat_prefix || inet_pton(AF_INET6, plat_prefix, &Global_Clatd_Config.plat_subnet) <= 0) {
137     logmsg(ANDROID_LOG_FATAL, "invalid IPv6 address specified for plat prefix: %s", plat_prefix);
138     exit(1);
139   }
140 
141   if (!v4_addr || !inet_pton(AF_INET, v4_addr, &Global_Clatd_Config.ipv4_local_subnet.s_addr)) {
142     logmsg(ANDROID_LOG_FATAL, "Invalid IPv4 address %s", v4_addr);
143     exit(1);
144   }
145 
146   if (!v6_addr || !inet_pton(AF_INET6, v6_addr, &Global_Clatd_Config.ipv6_local_subnet)) {
147     logmsg(ANDROID_LOG_FATAL, "Invalid source address %s", v6_addr);
148     exit(1);
149   }
150 
151   logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s plat=%s v4=%s v6=%s", CLATD_VERSION,
152          uplink_interface, plat_prefix ? plat_prefix : "(none)", v4_addr ? v4_addr : "(none)",
153          v6_addr ? v6_addr : "(none)");
154 
155   // Loop until someone sends us a signal or brings down the tun interface.
156   if (signal(SIGTERM, stop_loop) == SIG_ERR) {
157     logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno));
158     exit(1);
159   }
160 
161   event_loop(&tunnel);
162 
163   logmsg(ANDROID_LOG_INFO, "Shutting down clat on %s", uplink_interface);
164 
165   if (running) {
166     logmsg(ANDROID_LOG_INFO, "Clatd on %s waiting for SIGTERM", uplink_interface);
167     while (running) sleep(60);
168     logmsg(ANDROID_LOG_INFO, "Clatd on %s received SIGTERM", uplink_interface);
169   } else {
170     logmsg(ANDROID_LOG_INFO, "Clatd on %s already received SIGTERM", uplink_interface);
171   }
172   return 0;
173 }
174