blob: ae0a1e633c9e482ac6884453e9f117b0234a20a4 [file] [log] [blame]
Chia-chi Yeh79e62322009-06-02 08:49:55 +08001/*
2 * Copyright (C) 2009 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
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/poll.h>
25#include <sys/wait.h>
26#include <netdb.h>
27#include <signal.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <time.h>
31
Chia-chi Yeh84e31952009-06-08 14:11:34 +080032#ifdef ANDROID_CHANGES
33#include <android/log.h>
34#include <cutils/sockets.h>
35#endif
36
Chia-chi Yeh79e62322009-06-02 08:49:55 +080037#include "mtpd.h"
Robin Leeb8e401e2017-03-14 14:13:58 +000038#include "NetdClient.h"
Chia-chi Yeh79e62322009-06-02 08:49:55 +080039
40int the_socket = -1;
41
42extern struct protocol l2tp;
Chia-chi Yeh063bb922009-06-15 14:43:38 +080043extern struct protocol pptp;
44static struct protocol *protocols[] = {&l2tp, &pptp, NULL};
Chia-chi Yeh79e62322009-06-02 08:49:55 +080045static struct protocol *the_protocol;
46
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070047static char *interface;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080048static int pppd_argc;
49static char **pppd_argv;
50static pid_t pppd_pid;
51
52/* We redirect signals to a pipe in order to prevent race conditions. */
53static int signals[2];
54
55static void interrupt(int signal)
56{
57 write(signals[1], &signal, sizeof(int));
58}
59
60static int initialize(int argc, char **argv)
61{
Chia-chi Yeh79e62322009-06-02 08:49:55 +080062 int i;
63
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070064 for (i = 0; protocols[i]; ++i) {
65 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070066 if (argc - 3 >= p->arguments && !strcmp(argv[2], p->name)) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070067 log_print(INFO, "Using protocol %s", p->name);
68 the_protocol = p;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080069 break;
70 }
71 }
72
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070073 if (!the_protocol) {
74 printf("Usages:\n");
Chia-chi Yeh79e62322009-06-02 08:49:55 +080075 for (i = 0; protocols[i]; ++i) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070076 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070077 printf(" %s interface %s %s pppd-arguments\n",
78 argv[0], p->name, p->usage);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080079 }
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070080 exit(0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080081 }
82
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070083 interface = argv[1];
84 pppd_argc = argc - 3 - the_protocol->arguments;
85 pppd_argv = &argv[3 + the_protocol->arguments];
86 return the_protocol->connect(&argv[3]);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080087}
88
89static void stop_pppd()
90{
91 if (pppd_pid) {
Chia-chi Yeh02696122011-08-22 12:59:46 -070092 int status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080093 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
94 kill(pppd_pid, SIGTERM);
Chia-chi Yeh02696122011-08-22 12:59:46 -070095 waitpid(pppd_pid, &status, 0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080096 pppd_pid = 0;
97 }
98}
99
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800100#ifdef ANDROID_CHANGES
101
Chia-chi Yeh02696122011-08-22 12:59:46 -0700102static int android_get_control_and_arguments(int *argc, char ***argv)
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800103{
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700104 static char *args[32];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800105 int control;
106 int i;
107
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800108 if ((i = android_get_control_socket("mtpd")) == -1) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700109 return -1;
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800110 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800111 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800112 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800113 log_print(FATAL, "Cannot get control socket");
114 exit(SYSTEM_ERROR);
115 }
116 close(i);
Chia-chi Yeh02696122011-08-22 12:59:46 -0700117 fcntl(control, F_SETFD, FD_CLOEXEC);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800118
119 args[0] = (*argv)[0];
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700120 for (i = 1; i < 32; ++i) {
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700121 unsigned char bytes[2];
Chia-chi Yeh02696122011-08-22 12:59:46 -0700122 if (recv(control, &bytes[0], 1, 0) != 1 ||
123 recv(control, &bytes[1], 1, 0) != 1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800124 log_print(FATAL, "Cannot get argument length");
125 exit(SYSTEM_ERROR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800126 } else {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700127 int length = bytes[0] << 8 | bytes[1];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800128 int offset = 0;
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700129
Chia-chi Yeh02696122011-08-22 12:59:46 -0700130 if (length == 0xFFFF) {
131 break;
132 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800133 args[i] = malloc(length + 1);
134 while (offset < length) {
135 int n = recv(control, &args[i][offset], length - offset, 0);
136 if (n > 0) {
137 offset += n;
138 } else {
139 log_print(FATAL, "Cannot get argument value");
140 exit(SYSTEM_ERROR);
141 }
142 }
143 args[i][length] = 0;
144 }
145 }
146 log_print(DEBUG, "Received %d arguments", i - 1);
147
148 *argc = i;
149 *argv = args;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700150 return control;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800151}
152
153#endif
154
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800155int main(int argc, char **argv)
156{
Chia-chi Yeh02696122011-08-22 12:59:46 -0700157 struct pollfd pollfds[3];
158 int control = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800159 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800160 int status;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700161
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800162#ifdef ANDROID_CHANGES
Chia-chi Yeh02696122011-08-22 12:59:46 -0700163 control = android_get_control_and_arguments(&argc, &argv);
164 shutdown(control, SHUT_WR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800165#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800166
167 srandom(time(NULL));
168
169 if (pipe(signals) == -1) {
170 log_print(FATAL, "Pipe() %s", strerror(errno));
171 exit(SYSTEM_ERROR);
172 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800173 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
174 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800175
Chia-chi Yeha7776542009-06-19 16:36:32 +0800176 timeout = initialize(argc, argv);
177
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800178 signal(SIGHUP, interrupt);
179 signal(SIGINT, interrupt);
180 signal(SIGTERM, interrupt);
181 signal(SIGCHLD, interrupt);
182 signal(SIGPIPE, SIG_IGN);
183 atexit(stop_pppd);
184
Chia-chi Yeh02696122011-08-22 12:59:46 -0700185 pollfds[0].fd = the_socket;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800186 pollfds[0].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700187 pollfds[1].fd = signals[0];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800188 pollfds[1].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700189 pollfds[2].fd = control;
190 pollfds[2].events = 0;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800191
192 while (timeout >= 0) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700193 if (poll(pollfds, 3, timeout ? timeout : -1) == -1 && errno != EINTR) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800194 log_print(FATAL, "Poll() %s", strerror(errno));
195 exit(SYSTEM_ERROR);
196 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700197 if (pollfds[1].revents) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800198 break;
199 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700200 if (pollfds[2].revents) {
201 interrupt(SIGTERM);
202 }
Chia-chi Yehfba8fdc2011-12-27 13:39:15 -0800203 timeout = pollfds[0].revents ?
204 the_protocol->process() : the_protocol->timeout();
Chia-chi Yeh35c31502011-12-08 16:35:09 -0800205#ifdef ANDROID_CHANGES
206 if (!access("/data/misc/vpn/abort", F_OK)) {
207 interrupt(SIGTERM);
208 }
Chia-chi Yehfba8fdc2011-12-27 13:39:15 -0800209 if (!timeout) {
210 timeout = 5000;
211 }
Chia-chi Yeh35c31502011-12-08 16:35:09 -0800212#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800213 }
214
215 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800216 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800217 } else {
218 int signal;
219 read(signals[0], &signal, sizeof(int));
220 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800221 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700222 && WIFEXITED(status)) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800223 status = WEXITSTATUS(status);
224 log_print(INFO, "Pppd is terminated (status = %d)", status);
225 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800226 pppd_pid = 0;
227 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800228 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800229 }
230 }
231
232 stop_pppd();
233 the_protocol->shutdown();
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800234 log_print(INFO, "Mtpd is terminated (status = %d)", status);
235 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800236}
237
238void log_print(int level, char *format, ...)
239{
240 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800241#ifdef ANDROID_CHANGES
242 static int levels[5] = {
243 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
244 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
245 };
246 va_list ap;
247 va_start(ap, format);
248 __android_log_vprint(levels[level], "mtpd", format, ap);
249 va_end(ap);
250#else
251 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800252 va_list ap;
253 fprintf(stderr, "%c: ", levels[level]);
254 va_start(ap, format);
255 vfprintf(stderr, format, ap);
256 va_end(ap);
257 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800258#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800259 }
260}
261
262void create_socket(int family, int type, char *server, char *port)
263{
264 struct addrinfo hints = {
265 .ai_flags = AI_NUMERICSERV,
266 .ai_family = family,
267 .ai_socktype = type,
268 };
269 struct addrinfo *records;
270 struct addrinfo *r;
271 int error;
272
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700273 log_print(INFO, "Connecting to %s port %s via %s", server, port, interface);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800274
275 error = getaddrinfo(server, port, &hints, &records);
276 if (error) {
277 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700278 strerror(errno) : gai_strerror(error));
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800279 exit(NETWORK_ERROR);
280 }
281
282 for (r = records; r; r = r->ai_next) {
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700283 int s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
284 if (!setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
285 strlen(interface)) && !connect(s, r->ai_addr, r->ai_addrlen)) {
286 the_socket = s;
287 break;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800288 }
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700289 close(s);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800290 }
291
292 freeaddrinfo(records);
293
294 if (the_socket == -1) {
295 log_print(FATAL, "Connect() %s", strerror(errno));
296 exit(NETWORK_ERROR);
297 }
298
Robin Leeb8e401e2017-03-14 14:13:58 +0000299#ifdef ANDROID_CHANGES
300 protectFromVpn(the_socket);
301#endif
302
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800303 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
304 log_print(INFO, "Connection established (socket = %d)", the_socket);
305}
306
307void start_pppd(int pppox)
308{
309 if (pppd_pid) {
310 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
311 close(pppox);
312 return;
313 }
314
315 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
316
317 pppd_pid = fork();
318 if (pppd_pid < 0) {
319 log_print(FATAL, "Fork() %s", strerror(errno));
320 exit(SYSTEM_ERROR);
321 }
322
323 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800324 char *args[pppd_argc + 5];
325 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800326
327 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800328 args[0] = "pppd";
329 args[1] = "nodetach";
330 args[2] = "pppox";
331 args[3] = number;
332 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
333 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800334
Chia-chi Yeh4a721df2009-12-15 03:53:47 +0800335#ifdef ANDROID_CHANGES
336 {
337 char envargs[65536];
338 char *tail = envargs;
339 int i;
340 /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
341 for (i = 0; args[i]; ++i) {
342 char *p = args[i];
343 do {
344 *tail++ = 'A' + ((*p >> 4) & 0x0F);
345 *tail++ = 'A' + (*p & 0x0F);
346 } while (*p++);
347 }
348 *tail = 0;
349 setenv("envargs", envargs, 1);
350 args[1] = NULL;
351 }
352#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800353 execvp("pppd", args);
354 log_print(FATAL, "Exec() %s", strerror(errno));
355 exit(1); /* Pretending a fatal error in pppd. */
356 }
357
358 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
359 close(pppox);
360}