blob: cff57120a7cf5c3ddd6eaf16a56055efc08d73ea [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"
38
39int the_socket = -1;
40
41extern struct protocol l2tp;
Chia-chi Yeh063bb922009-06-15 14:43:38 +080042extern struct protocol pptp;
43static struct protocol *protocols[] = {&l2tp, &pptp, NULL};
Chia-chi Yeh79e62322009-06-02 08:49:55 +080044static struct protocol *the_protocol;
45
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070046static char *interface;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080047static int pppd_argc;
48static char **pppd_argv;
49static pid_t pppd_pid;
50
51/* We redirect signals to a pipe in order to prevent race conditions. */
52static int signals[2];
53
54static void interrupt(int signal)
55{
56 write(signals[1], &signal, sizeof(int));
57}
58
59static int initialize(int argc, char **argv)
60{
Chia-chi Yeh79e62322009-06-02 08:49:55 +080061 int i;
62
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070063 for (i = 0; protocols[i]; ++i) {
64 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070065 if (argc - 3 >= p->arguments && !strcmp(argv[2], p->name)) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070066 log_print(INFO, "Using protocol %s", p->name);
67 the_protocol = p;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080068 break;
69 }
70 }
71
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070072 if (!the_protocol) {
73 printf("Usages:\n");
Chia-chi Yeh79e62322009-06-02 08:49:55 +080074 for (i = 0; protocols[i]; ++i) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070075 struct protocol *p = protocols[i];
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070076 printf(" %s interface %s %s pppd-arguments\n",
77 argv[0], p->name, p->usage);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080078 }
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070079 exit(0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080080 }
81
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -070082 interface = argv[1];
83 pppd_argc = argc - 3 - the_protocol->arguments;
84 pppd_argv = &argv[3 + the_protocol->arguments];
85 return the_protocol->connect(&argv[3]);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080086}
87
88static void stop_pppd()
89{
90 if (pppd_pid) {
Chia-chi Yeh02696122011-08-22 12:59:46 -070091 int status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080092 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
93 kill(pppd_pid, SIGTERM);
Chia-chi Yeh02696122011-08-22 12:59:46 -070094 waitpid(pppd_pid, &status, 0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080095 pppd_pid = 0;
96 }
97}
98
Chia-chi Yeh84e31952009-06-08 14:11:34 +080099#ifdef ANDROID_CHANGES
100
Chia-chi Yeh02696122011-08-22 12:59:46 -0700101static int android_get_control_and_arguments(int *argc, char ***argv)
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800102{
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700103 static char *args[32];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800104 int control;
105 int i;
106
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800107 if ((i = android_get_control_socket("mtpd")) == -1) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700108 return -1;
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800109 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800110 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800111 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800112 log_print(FATAL, "Cannot get control socket");
113 exit(SYSTEM_ERROR);
114 }
115 close(i);
Chia-chi Yeh02696122011-08-22 12:59:46 -0700116 fcntl(control, F_SETFD, FD_CLOEXEC);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800117
118 args[0] = (*argv)[0];
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700119 for (i = 1; i < 32; ++i) {
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700120 unsigned char bytes[2];
Chia-chi Yeh02696122011-08-22 12:59:46 -0700121 if (recv(control, &bytes[0], 1, 0) != 1 ||
122 recv(control, &bytes[1], 1, 0) != 1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800123 log_print(FATAL, "Cannot get argument length");
124 exit(SYSTEM_ERROR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800125 } else {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700126 int length = bytes[0] << 8 | bytes[1];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800127 int offset = 0;
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700128
Chia-chi Yeh02696122011-08-22 12:59:46 -0700129 if (length == 0xFFFF) {
130 break;
131 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800132 args[i] = malloc(length + 1);
133 while (offset < length) {
134 int n = recv(control, &args[i][offset], length - offset, 0);
135 if (n > 0) {
136 offset += n;
137 } else {
138 log_print(FATAL, "Cannot get argument value");
139 exit(SYSTEM_ERROR);
140 }
141 }
142 args[i][length] = 0;
143 }
144 }
145 log_print(DEBUG, "Received %d arguments", i - 1);
146
147 *argc = i;
148 *argv = args;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700149 return control;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800150}
151
152#endif
153
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800154int main(int argc, char **argv)
155{
Chia-chi Yeh02696122011-08-22 12:59:46 -0700156 struct pollfd pollfds[3];
157 int control = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800158 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800159 int status;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700160
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800161#ifdef ANDROID_CHANGES
Chia-chi Yeh02696122011-08-22 12:59:46 -0700162 control = android_get_control_and_arguments(&argc, &argv);
163 shutdown(control, SHUT_WR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800164#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800165
166 srandom(time(NULL));
167
168 if (pipe(signals) == -1) {
169 log_print(FATAL, "Pipe() %s", strerror(errno));
170 exit(SYSTEM_ERROR);
171 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800172 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
173 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800174
Chia-chi Yeha7776542009-06-19 16:36:32 +0800175 timeout = initialize(argc, argv);
176
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800177 signal(SIGHUP, interrupt);
178 signal(SIGINT, interrupt);
179 signal(SIGTERM, interrupt);
180 signal(SIGCHLD, interrupt);
181 signal(SIGPIPE, SIG_IGN);
182 atexit(stop_pppd);
183
Chia-chi Yeh02696122011-08-22 12:59:46 -0700184 pollfds[0].fd = the_socket;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800185 pollfds[0].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700186 pollfds[1].fd = signals[0];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800187 pollfds[1].events = POLLIN;
Chia-chi Yeh02696122011-08-22 12:59:46 -0700188 pollfds[2].fd = control;
189 pollfds[2].events = 0;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800190
191 while (timeout >= 0) {
Chia-chi Yeh02696122011-08-22 12:59:46 -0700192 if (poll(pollfds, 3, timeout ? timeout : -1) == -1 && errno != EINTR) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800193 log_print(FATAL, "Poll() %s", strerror(errno));
194 exit(SYSTEM_ERROR);
195 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700196 if (pollfds[1].revents) {
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800197 break;
198 }
Chia-chi Yeh02696122011-08-22 12:59:46 -0700199 if (pollfds[2].revents) {
200 interrupt(SIGTERM);
201 }
Chia-chi Yeh35c31502011-12-08 16:35:09 -0800202#ifdef ANDROID_CHANGES
203 if (!access("/data/misc/vpn/abort", F_OK)) {
204 interrupt(SIGTERM);
205 }
206#endif
207 timeout = pollfds[0].revents ?
208 the_protocol->process() : the_protocol->timeout();
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800209 }
210
211 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800212 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800213 } else {
214 int signal;
215 read(signals[0], &signal, sizeof(int));
216 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800217 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700218 && WIFEXITED(status)) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800219 status = WEXITSTATUS(status);
220 log_print(INFO, "Pppd is terminated (status = %d)", status);
221 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800222 pppd_pid = 0;
223 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800224 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800225 }
226 }
227
228 stop_pppd();
229 the_protocol->shutdown();
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800230 log_print(INFO, "Mtpd is terminated (status = %d)", status);
231 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800232}
233
234void log_print(int level, char *format, ...)
235{
236 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800237#ifdef ANDROID_CHANGES
238 static int levels[5] = {
239 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
240 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
241 };
242 va_list ap;
243 va_start(ap, format);
244 __android_log_vprint(levels[level], "mtpd", format, ap);
245 va_end(ap);
246#else
247 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800248 va_list ap;
249 fprintf(stderr, "%c: ", levels[level]);
250 va_start(ap, format);
251 vfprintf(stderr, format, ap);
252 va_end(ap);
253 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800254#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800255 }
256}
257
258void create_socket(int family, int type, char *server, char *port)
259{
260 struct addrinfo hints = {
261 .ai_flags = AI_NUMERICSERV,
262 .ai_family = family,
263 .ai_socktype = type,
264 };
265 struct addrinfo *records;
266 struct addrinfo *r;
267 int error;
268
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700269 log_print(INFO, "Connecting to %s port %s via %s", server, port, interface);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800270
271 error = getaddrinfo(server, port, &hints, &records);
272 if (error) {
273 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
Chia-chi Yehec2b0392011-07-13 19:38:14 -0700274 strerror(errno) : gai_strerror(error));
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800275 exit(NETWORK_ERROR);
276 }
277
278 for (r = records; r; r = r->ai_next) {
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700279 int s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
280 if (!setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, interface,
281 strlen(interface)) && !connect(s, r->ai_addr, r->ai_addrlen)) {
282 the_socket = s;
283 break;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800284 }
Chia-chi Yeh3afd73f2011-07-13 18:40:09 -0700285 close(s);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800286 }
287
288 freeaddrinfo(records);
289
290 if (the_socket == -1) {
291 log_print(FATAL, "Connect() %s", strerror(errno));
292 exit(NETWORK_ERROR);
293 }
294
295 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
296 log_print(INFO, "Connection established (socket = %d)", the_socket);
297}
298
299void start_pppd(int pppox)
300{
301 if (pppd_pid) {
302 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
303 close(pppox);
304 return;
305 }
306
307 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
308
309 pppd_pid = fork();
310 if (pppd_pid < 0) {
311 log_print(FATAL, "Fork() %s", strerror(errno));
312 exit(SYSTEM_ERROR);
313 }
314
315 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800316 char *args[pppd_argc + 5];
317 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800318
319 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800320 args[0] = "pppd";
321 args[1] = "nodetach";
322 args[2] = "pppox";
323 args[3] = number;
324 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
325 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800326
Chia-chi Yeh4a721df2009-12-15 03:53:47 +0800327#ifdef ANDROID_CHANGES
328 {
329 char envargs[65536];
330 char *tail = envargs;
331 int i;
332 /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
333 for (i = 0; args[i]; ++i) {
334 char *p = args[i];
335 do {
336 *tail++ = 'A' + ((*p >> 4) & 0x0F);
337 *tail++ = 'A' + (*p & 0x0F);
338 } while (*p++);
339 }
340 *tail = 0;
341 setenv("envargs", envargs, 1);
342 args[1] = NULL;
343 }
344#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800345 execvp("pppd", args);
346 log_print(FATAL, "Exec() %s", strerror(errno));
347 exit(1); /* Pretending a fatal error in pppd. */
348 }
349
350 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
351 close(pppox);
352}