blob: ac724ac77a53699f816072e1d3d56a04f7b440cd [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>
Sam Protsenko28cfaab2017-10-30 17:02:26 +020031#include <limits.h>
Chia-chi Yeh79e62322009-06-02 08:49:55 +080032
Chia-chi Yeh84e31952009-06-08 14:11:34 +080033#ifdef ANDROID_CHANGES
34#include <android/log.h>
35#include <cutils/sockets.h>
36#endif
37
Chia-chi Yeh79e62322009-06-02 08:49:55 +080038#include "mtpd.h"
Robin Leeb8e401e2017-03-14 14:13:58 +000039#include "NetdClient.h"
Chia-chi Yeh79e62322009-06-02 08:49:55 +080040
Sam Protsenko28cfaab2017-10-30 17:02:26 +020041#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
42/* Characters count in string with max value of unsigned type t */
43#define TYPE_STRLEN_U(t) ((((sizeof(t) * CHAR_BIT) * 1233) >> 12) + 1)
44/* Length of string with max file descriptor value */
45#define FD_MAX_LEN TYPE_STRLEN_U(int)
46
Chia-chi Yeh79e62322009-06-02 08:49:55 +080047int the_socket = -1;
48
49extern struct protocol l2tp;
Chia-chi Yeh063bb922009-06-15 14:43:38 +080050extern struct protocol pptp;
51static struct protocol *protocols[] = {&l2tp, &pptp, NULL};
Chia-chi Yeh79e62322009-06-02 08:49:55 +080052static struct protocol *the_protocol;
53
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070054static char *interface;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080055static int pppd_argc;
56static char **pppd_argv;
57static pid_t pppd_pid;
58
59/* We redirect signals to a pipe in order to prevent race conditions. */
60static int signals[2];
61
62static void interrupt(int signal)
63{
64 write(signals[1], &signal, sizeof(int));
65}
66
67static int initialize(int argc, char **argv)
68{
Chia-chi Yeh79e62322009-06-02 08:49:55 +080069 int i;
70
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070071 for (i = 0; protocols[i]; ++i) {
72 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070073 if (argc - 3 >= p->arguments && !strcmp(argv[2], p->name)) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070074 log_print(INFO, "Using protocol %s", p->name);
75 the_protocol = p;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080076 break;
77 }
78 }
79
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070080 if (!the_protocol) {
81 printf("Usages:\n");
Chia-chi Yeh79e62322009-06-02 08:49:55 +080082 for (i = 0; protocols[i]; ++i) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070083 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070084 printf(" %s interface %s %s pppd-arguments\n",
85 argv[0], p->name, p->usage);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080086 }
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070087 exit(0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080088 }
89
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070090 interface = argv[1];
91 pppd_argc = argc - 3 - the_protocol->arguments;
92 pppd_argv = &argv[3 + the_protocol->arguments];
93 return the_protocol->connect(&argv[3]);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080094}
95
96static void stop_pppd()
97{
98 if (pppd_pid) {
Chia-chi Yeh02696122011-08-22 12:59:46 -070099 int status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800100 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
101 kill(pppd_pid, SIGTERM);
Chia-chi Yeh02696122011-08-22 12:59:46 -0700102 waitpid(pppd_pid, &status, 0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800103 pppd_pid = 0;
104 }
105}
106
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800107#ifdef ANDROID_CHANGES
108
Chia-chi Yeh02696122011-08-22 12:59:46 -0700109static int android_get_control_and_arguments(int *argc, char ***argv)
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800110{
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700111 static char *args[32];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800112 int control;
113 int i;
114
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800115 if ((i = android_get_control_socket("mtpd")) == -1) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700116 return -1;
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800117 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800118 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800119 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800120 log_print(FATAL, "Cannot get control socket");
121 exit(SYSTEM_ERROR);
122 }
123 close(i);
Chia-chi Yeh02696122011-08-22 12:59:46 -0700124 fcntl(control, F_SETFD, FD_CLOEXEC);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800125
126 args[0] = (*argv)[0];
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700127 for (i = 1; i < 32; ++i) {
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700128 unsigned char bytes[2];
Chia-chi Yeh02696122011-08-22 12:59:46 -0700129 if (recv(control, &bytes[0], 1, 0) != 1 ||
130 recv(control, &bytes[1], 1, 0) != 1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800131 log_print(FATAL, "Cannot get argument length");
132 exit(SYSTEM_ERROR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800133 } else {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700134 int length = bytes[0] << 8 | bytes[1];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800135 int offset = 0;
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700136
Chia-chi Yeh02696122011-08-22 12:59:46 -0700137 if (length == 0xFFFF) {
138 break;
139 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800140 args[i] = malloc(length + 1);
141 while (offset < length) {
142 int n = recv(control, &args[i][offset], length - offset, 0);
143 if (n > 0) {
144 offset += n;
145 } else {
146 log_print(FATAL, "Cannot get argument value");
147 exit(SYSTEM_ERROR);
148 }
149 }
150 args[i][length] = 0;
151 }
152 }
153 log_print(DEBUG, "Received %d arguments", i - 1);
154
155 *argc = i;
156 *argv = args;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700157 return control;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800158}
159
160#endif
161
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800162int main(int argc, char **argv)
163{
Chia-chi Yeh02696122011-08-22 12:59:46 -0700164 struct pollfd pollfds[3];
165 int control = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800166 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800167 int status;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700168
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800169#ifdef ANDROID_CHANGES
Chia-chi Yeh02696122011-08-22 12:59:46 -0700170 control = android_get_control_and_arguments(&argc, &argv);
171 shutdown(control, SHUT_WR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800172#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800173
174 srandom(time(NULL));
175
176 if (pipe(signals) == -1) {
177 log_print(FATAL, "Pipe() %s", strerror(errno));
178 exit(SYSTEM_ERROR);
179 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800180 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
181 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800182
Chia-chi Yeha7776542009-06-19 16:36:32 +0800183 timeout = initialize(argc, argv);
184
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800185 signal(SIGHUP, interrupt);
186 signal(SIGINT, interrupt);
187 signal(SIGTERM, interrupt);
188 signal(SIGCHLD, interrupt);
189 signal(SIGPIPE, SIG_IGN);
190 atexit(stop_pppd);
191
Chia-chi Yeh02696122011-08-22 12:59:46 -0700192 pollfds[0].fd = the_socket;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800193 pollfds[0].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700194 pollfds[1].fd = signals[0];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800195 pollfds[1].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700196 pollfds[2].fd = control;
197 pollfds[2].events = 0;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800198
199 while (timeout >= 0) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700200 if (poll(pollfds, 3, timeout ? timeout : -1) == -1 && errno != EINTR) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800201 log_print(FATAL, "Poll() %s", strerror(errno));
202 exit(SYSTEM_ERROR);
203 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700204 if (pollfds[1].revents) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800205 break;
206 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700207 if (pollfds[2].revents) {
208 interrupt(SIGTERM);
209 }
Chia-chi Yehfba8fdc2011-12-27 13:39:15 -0800210 timeout = pollfds[0].revents ?
211 the_protocol->process() : the_protocol->timeout();
Chia-chi Yeh35c31502011-12-08 16:35:09 -0800212#ifdef ANDROID_CHANGES
213 if (!access("/data/misc/vpn/abort", F_OK)) {
214 interrupt(SIGTERM);
215 }
Chia-chi Yehfba8fdc2011-12-27 13:39:15 -0800216 if (!timeout) {
217 timeout = 5000;
218 }
Chia-chi Yeh35c31502011-12-08 16:35:09 -0800219#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800220 }
221
222 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800223 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800224 } else {
225 int signal;
226 read(signals[0], &signal, sizeof(int));
227 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800228 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700229 && WIFEXITED(status)) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800230 status = WEXITSTATUS(status);
231 log_print(INFO, "Pppd is terminated (status = %d)", status);
232 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800233 pppd_pid = 0;
234 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800235 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800236 }
237 }
238
239 stop_pppd();
240 the_protocol->shutdown();
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800241 log_print(INFO, "Mtpd is terminated (status = %d)", status);
242 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800243}
244
245void log_print(int level, char *format, ...)
246{
247 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800248#ifdef ANDROID_CHANGES
249 static int levels[5] = {
250 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
251 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
252 };
253 va_list ap;
254 va_start(ap, format);
255 __android_log_vprint(levels[level], "mtpd", format, ap);
256 va_end(ap);
257#else
258 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800259 va_list ap;
260 fprintf(stderr, "%c: ", levels[level]);
261 va_start(ap, format);
262 vfprintf(stderr, format, ap);
263 va_end(ap);
264 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800265#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800266 }
267}
268
269void create_socket(int family, int type, char *server, char *port)
270{
271 struct addrinfo hints = {
272 .ai_flags = AI_NUMERICSERV,
273 .ai_family = family,
274 .ai_socktype = type,
275 };
276 struct addrinfo *records;
277 struct addrinfo *r;
278 int error;
279
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700280 log_print(INFO, "Connecting to %s port %s via %s", server, port, interface);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800281
282 error = getaddrinfo(server, port, &hints, &records);
283 if (error) {
284 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700285 strerror(errno) : gai_strerror(error));
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800286 exit(NETWORK_ERROR);
287 }
288
289 for (r = records; r; r = r->ai_next) {
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700290 int s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
291 if (!setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
292 strlen(interface)) && !connect(s, r->ai_addr, r->ai_addrlen)) {
293 the_socket = s;
294 break;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800295 }
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700296 close(s);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800297 }
298
299 freeaddrinfo(records);
300
301 if (the_socket == -1) {
302 log_print(FATAL, "Connect() %s", strerror(errno));
303 exit(NETWORK_ERROR);
304 }
305
Robin Leeb8e401e2017-03-14 14:13:58 +0000306#ifdef ANDROID_CHANGES
307 protectFromVpn(the_socket);
308#endif
309
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800310 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
311 log_print(INFO, "Connection established (socket = %d)", the_socket);
312}
313
314void start_pppd(int pppox)
315{
316 if (pppd_pid) {
317 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
318 close(pppox);
319 return;
320 }
321
322 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
323
324 pppd_pid = fork();
325 if (pppd_pid < 0) {
326 log_print(FATAL, "Fork() %s", strerror(errno));
327 exit(SYSTEM_ERROR);
328 }
329
330 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800331 char *args[pppd_argc + 5];
Sam Protsenko28cfaab2017-10-30 17:02:26 +0200332 char number[FD_MAX_LEN + 1];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800333
Sam Protsenko28cfaab2017-10-30 17:02:26 +0200334 snprintf(number, FD_MAX_LEN + 1, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800335 args[0] = "pppd";
336 args[1] = "nodetach";
337 args[2] = "pppox";
338 args[3] = number;
339 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
340 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800341
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800342 execvp("pppd", args);
343 log_print(FATAL, "Exec() %s", strerror(errno));
Sam Protsenko28cfaab2017-10-30 17:02:26 +0200344 exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800345 }
346
347 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
348 close(pppox);
349}
Sam Protsenko28cfaab2017-10-30 17:02:26 +0200350
351/**
352 * Start pppd daemon with pppol2tp-android plugin.
353 *
354 * @param tunnel_fd Tunnel socket file descriptor
355 * @param session_fd Session socket file descriptor
356 * @param tunnel_id Tunnel ID; must be in host byte order
357 * @param session_id Session ID; must be in host byte order
358 */
359void start_pppd_ol2tp(int tunnel_fd, int session_fd, int tunnel_id,
360 int session_id)
361{
362 if (pppd_pid) {
363 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
364 goto ret;
365 }
366
367 log_print(INFO, "Starting pppd (tunnel_fd = %d, session_fd = %d)",
368 tunnel_fd, session_fd);
369
370 pppd_pid = fork();
371 if (pppd_pid < 0) {
372 log_print(FATAL, "Fork() %s", strerror(errno));
373 exit(SYSTEM_ERROR);
374 }
375
376 if (!pppd_pid) {
377 char tunnel_fd_str[FD_MAX_LEN + 1];
378 char session_fd_str[FD_MAX_LEN + 1];
379 char tunnel_id_str[FD_MAX_LEN + 1];
380 char session_id_str[FD_MAX_LEN + 1];
381
382 snprintf(tunnel_fd_str, FD_MAX_LEN + 1, "%d", tunnel_fd);
383 snprintf(session_fd_str, FD_MAX_LEN + 1, "%d", session_fd);
384 snprintf(tunnel_id_str, FD_MAX_LEN + 1, "%d", tunnel_id);
385 snprintf(session_id_str, FD_MAX_LEN + 1, "%d", session_id);
386
387 const char *l2tp_args[] = {
388 "pppd",
389 "nodetach",
390 "plugin",
391 "pppol2tp-android.so",
392 "session_fd",
393 session_fd_str,
394 "tunnel_fd",
395 tunnel_fd_str,
396 "session_id",
397 session_id_str,
398 "tunnel_id",
399 tunnel_id_str,
400 };
401 const size_t args_len = ARRAY_SIZE(l2tp_args) + pppd_argc + 1;
402 char *args[args_len];
403
404 /* Populate args[] from l2tp_args[] and pppd_argv[] */
405 memcpy(args, l2tp_args, sizeof(l2tp_args));
406 memcpy(args + ARRAY_SIZE(l2tp_args), pppd_argv,
407 sizeof(char *) * pppd_argc);
408 args[args_len - 1] = NULL;
409
410 execvp("pppd", args);
411 log_print(FATAL, "Exec() %s", strerror(errno));
412 exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
413 }
414
415 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
416
417ret:
418 close(session_fd);
419 close(tunnel_fd);
420}
Sam Protsenko0368bbd2018-06-08 01:11:16 +0300421
422/**
423 * Start pppd daemon with pppopptp-android plugin.
424 *
425 * @param pptp_fd PPTP socket file descriptor
426 */
427void start_pppd_pptp(int pptp_fd)
428{
429 if (pppd_pid) {
430 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
431 goto ret;
432 }
433
434 log_print(INFO, "Starting pppd (pptp_fd = %d)", pptp_fd);
435
436 pppd_pid = fork();
437 if (pppd_pid < 0) {
438 log_print(FATAL, "Fork() %s", strerror(errno));
439 exit(SYSTEM_ERROR);
440 }
441
442 if (!pppd_pid) {
443 char pptp_fd_str[FD_MAX_LEN + 1];
444
445 snprintf(pptp_fd_str, FD_MAX_LEN + 1, "%d", pptp_fd);
446
447 const char *pptp_args[] = {
448 "pppd",
449 "nodetach",
450 "plugin",
451 "pppopptp-android.so",
452 "pptp_socket",
453 pptp_fd_str,
454 };
455 const size_t args_len = ARRAY_SIZE(pptp_args) + pppd_argc + 1;
456 char *args[args_len];
457
458 /* Populate args[] from pptp_args[] and pppd_argv[] */
459 memcpy(args, pptp_args, sizeof(pptp_args));
460 memcpy(args + ARRAY_SIZE(pptp_args), pppd_argv,
461 sizeof(char *) * pppd_argc);
462 args[args_len - 1] = NULL;
463
464 execvp("pppd", args);
465 log_print(FATAL, "Exec() %s", strerror(errno));
466 exit(SYSTEM_ERROR); /* Pretending a fatal error in pppd. */
467 }
468
469 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
470
471ret:
472 close(pptp_fd);
473}