fix outgoing QOS prios
[tomato.git] / release / src / router / pptp-client / pptp.c
blob124d25bf8085f2cc10de3b97da410e69d1b17d7a
1 /* pptp.c ... client shell to launch call managers, data handlers, and
2 * the pppd from the command line.
3 * C. Scott Ananian <cananian@alumni.princeton.edu>
5 * $Id: pptp.c,v 1.44 2006/02/13 03:06:25 quozl Exp $
6 */
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #if defined(__FreeBSD__)
11 #include <libutil.h>
12 #elif defined(__NetBSD__) || defined(__OpenBSD__)
13 #include <util.h>
14 #elif defined(__APPLE__)
15 #include <util.h>
16 #else
17 #include <pty.h>
18 #endif
19 #ifdef USER_PPP
20 #include <fcntl.h>
21 #endif
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <sys/un.h>
25 #include <net/route.h>
26 #include <sys/ioctl.h>
27 #include <netdb.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <syslog.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <setjmp.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37 #include <sys/param.h>
38 #if defined(__APPLE__)
39 #include "getopt.h"
40 #else
41 #include <getopt.h>
42 #endif
43 #include <limits.h>
44 #ifndef N_HDLC
45 #include <linux/termios.h>
46 #endif
47 #include "config.h"
48 #include "pptp_callmgr.h"
49 #include "pptp_gre.h"
50 #include "version.h"
51 #if defined(__linux__)
52 #include <linux/prctl.h>
53 #else
54 #include "inststr.h"
55 #endif
56 #include "util.h"
57 #include "pptp_quirks.h"
58 #include "pqueue.h"
59 #include "pptp_options.h"
61 #ifndef PPPD_BINARY
62 #define PPPD_BINARY "pppd"
63 #endif
65 #define sin_addr(s) (((struct sockaddr_in *)(s))->sin_addr)
67 int syncppp = 0;
68 int log_level = 0;
69 int disable_buffer = 0;
71 struct in_addr get_ip_address(char *name);
72 int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp, int pty_fd, int gre_fd);
73 void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp);
74 int get_call_id(int sock, pid_t gre, pid_t pppd,
75 u_int16_t *call_id, u_int16_t *peer_call_id);
76 void launch_pppd(char *ttydev, int argc, char **argv);
78 static int route_add(const struct in_addr inetaddr, struct rtentry *rt);
79 static int route_del(struct rtentry *rt);
81 /*** print usage and exit *****************************************************/
82 void usage(char *progname)
84 fprintf(stderr,
85 "%s\n"
86 "Usage:\n"
87 " %s <hostname> [<pptp options>] [[--] <pppd options>]\n"
88 "\n"
89 "Or using pppd's pty option: \n"
90 " pppd pty \"%s <hostname> --nolaunchpppd <pptp options>\"\n"
91 "\n"
92 "Available pptp options:\n"
93 " --version Display version number and exit\n"
94 " --phone <number> Pass <number> to remote host as phone number\n"
95 " --nolaunchpppd Do not launch pppd, for use as a pppd pty\n"
96 " --quirks <quirk> Work around a buggy PPTP implementation\n"
97 " Currently recognised values are BEZEQ_ISRAEL only\n"
98 " --debug Run in foreground (for debugging with gdb)\n"
99 " --sync Enable Synchronous HDLC (pppd must use it too)\n"
100 " --timeout <secs> Time to wait for reordered packets (0.01 to 10 secs)\n"
101 " --nobuffer Disable packet buffering and reordering completely\n"
102 " --idle-wait Time to wait before sending echo request\n"
103 " --max-echo-wait Time to wait before giving up on lack of reply\n"
104 " --logstring <name> Use <name> instead of 'anon' in syslog messages\n"
105 " --localbind <addr> Bind to specified IP address instead of wildcard\n"
106 " --loglevel <level> Sets the debugging level (0=low, 1=default, 2=high)\n"
107 " --no-host-route Disable adding host route to server",
109 version, progname, progname);
110 log("%s called with wrong arguments, program not started.", progname);
111 exit(1);
114 struct in_addr localbind = { INADDR_NONE };
115 static int signaled = 0;
117 /*** do nothing signal handler ************************************************/
118 void do_nothing(int sig)
120 /* do nothing signal handler. Better than SIG_IGN. */
121 signaled = sig;
124 sigjmp_buf env;
126 /*** signal handler ***********************************************************/
127 void sighandler(int sig)
129 siglongjmp(env, 1);
132 /*** report statistics signal handler (SIGUSR1) *******************************/
133 void sigstats(int sig)
135 syslog(LOG_NOTICE, "GRE statistics:\n");
136 #define LOG(name,value) syslog(LOG_NOTICE, name "\n", stats .value)
137 LOG("rx accepted = %d", rx_accepted);
138 LOG("rx lost = %d", rx_lost);
139 LOG("rx under win = %d", rx_underwin);
140 LOG("rx over win = %d", rx_overwin);
141 LOG("rx buffered = %d", rx_buffered);
142 LOG("rx OS errors = %d", rx_errors);
143 LOG("rx truncated = %d", rx_truncated);
144 LOG("rx invalid = %d", rx_invalid);
145 LOG("rx acks = %d", rx_acks);
146 LOG("tx sent = %d", tx_sent);
147 LOG("tx failed = %d", tx_failed);
148 LOG("tx short = %d", tx_short);
149 LOG("tx acks = %d", tx_acks);
150 LOG("tx oversize = %d", tx_oversize);
151 LOG("round trip = %d usecs", rtt);
152 #undef LOG
155 /*** main *********************************************************************/
156 /* TODO: redesign to avoid longjmp/setjmp. Several variables here
157 have a volatile qualifier to silence warnings from gcc < 3.0.
158 Remove the volatile qualifiers if longjmp/setjmp are removed.
160 int main(int argc, char **argv, char **envp)
162 struct in_addr inetaddr;
163 struct rtentry rt;
164 volatile int callmgr_sock = -1;
165 char ttydev[PATH_MAX];
166 int pty_fd, tty_fd, gre_fd, rc;
167 volatile pid_t parent_pid, child_pid;
168 u_int16_t call_id, peer_call_id;
169 char buf[128];
170 int pppdargc;
171 char **pppdargv;
172 char phonenrbuf[65]; /* maximum length of field plus one for the trailing
173 * '\0' */
174 char * volatile phonenr = NULL;
175 volatile int launchpppd = 1, debug = 0, add_host_route = 1;
177 int disc = N_HDLC;
179 while(1){
180 /* structure with all recognised options for pptp */
181 static struct option long_options[] = {
182 {"phone", 1, 0, 0},
183 {"nolaunchpppd", 0, 0, 0},
184 {"quirks", 1, 0, 0},
185 {"debug", 0, 0, 0},
186 {"sync", 0, 0, 0},
187 {"timeout", 1, 0, 0},
188 {"logstring", 1, 0, 0},
189 {"localbind", 1, 0, 0},
190 {"loglevel", 1, 0, 0},
191 {"nobuffer", 0, 0, 0},
192 {"idle-wait", 1, 0, 0},
193 {"max-echo-wait", 1, 0, 0},
194 {"version", 0, 0, 0},
195 {"no-host-route", 0, 0, 0},
196 {0, 0, 0, 0}
198 int option_index = 0;
199 int c;
200 c = getopt_long (argc, argv, "", long_options, &option_index);
201 if (c == -1) break; /* no more options */
202 switch (c) {
203 case 0:
204 if (option_index == 0) { /* --phone specified */
205 /* copy it to a buffer, as the argv's will be overwritten
206 * by inststr() */
207 strncpy(phonenrbuf,optarg,sizeof(phonenrbuf));
208 phonenrbuf[sizeof(phonenrbuf) - 1] = '\0';
209 phonenr = phonenrbuf;
210 } else if (option_index == 1) {/* --nolaunchpppd specified */
211 launchpppd = 0;
212 } else if (option_index == 2) {/* --quirks specified */
213 if (set_quirk_index(find_quirk(optarg)))
214 usage(argv[0]);
215 } else if (option_index == 3) {/* --debug */
216 debug = 1;
217 } else if (option_index == 4) {/* --sync specified */
218 syncppp = 1;
219 } else if (option_index == 5) {/* --timeout */
220 float new_packet_timeout = atof(optarg);
221 if (new_packet_timeout < 0.0099 ||
222 new_packet_timeout > 10) {
223 fprintf(stderr, "Packet timeout %s (%f) out of range: "
224 "should be between 0.01 and 10 seconds\n",
225 optarg, new_packet_timeout);
226 log("Packet timeout %s (%f) out of range: should be"
227 "between 0.01 and 10 seconds", optarg,
228 new_packet_timeout);
229 exit(2);
230 } else {
231 packet_timeout_usecs = new_packet_timeout * 1000000;
233 } else if (option_index == 6) {/* --logstring */
234 log_string = strdup(optarg);
235 } else if (option_index == 7) {/* --localbind */
236 if (inet_pton(AF_INET, optarg, (void *) &localbind) < 1) {
237 fprintf(stderr, "Local bind address %s invalid\n",
238 optarg);
239 log("Local bind address %s invalid\n", optarg);
240 exit(2);
242 } else if (option_index == 8) { /* --loglevel */
243 log_level = atoi(optarg);
244 if (log_level < 0 || log_level > 2)
245 usage(argv[0]);
246 } else if (option_index == 9) { /* --nobuffer */
247 disable_buffer = 1;
248 } else if (option_index == 10) { /* --idle-wait */
249 int x = atoi(optarg);
250 if (x < 0) {
251 fprintf(stderr, "--idle-wait must not be negative\n");
252 log("--idle-wait must not be negative\n");
253 exit(2);
254 } else {
255 idle_wait = x;
257 } else if (option_index == 11) { /* --max-echo-wait */
258 int x = atoi(optarg);
259 if (x < 0) {
260 fprintf(stderr, "--max-echo-wait must not be negative\n");
261 log("--max-echo-wait must not be negative\n");
262 exit(2);
263 } else {
264 max_echo_wait = x;
266 fprintf(stderr, "--max-echo-wait ignored, not yet implemented\n");
267 } else if (option_index == 12) { /* --version */
268 fprintf(stdout, "%s\n", version);
269 exit(0);
270 } else if (option_index == 13) { /* --no-host-route */
271 add_host_route = 0;
273 break;
274 case '?': /* unrecognised option */
275 /* fall through */
276 default:
277 usage(argv[0]);
279 if (c == -1) break; /* no more options for pptp */
282 /* at least one argument is required */
283 if (argc <= optind)
284 usage(argv[0]);
286 /* Get IP address for the hostname in argv[1] */
287 inetaddr = get_ip_address(argv[optind]);
288 optind++;
290 /* Find the ppp options, extract phone number */
291 pppdargc = argc - optind;
292 pppdargv = argv + optind;
293 log("The synchronous pptp option is %sactivated\n", syncppp ? "" : "NOT ");
295 if (add_host_route) {
296 /* Add a route to inetaddr */
297 memset(&rt, 0, sizeof(rt));
298 route_add(inetaddr, &rt);
301 /* Now we have the peer address, bind the GRE socket early,
302 before starting pppd. This prevents the ICMP Unreachable bug
303 documented in <1026868263.2855.67.camel@jander> */
304 gre_fd = pptp_gre_bind(inetaddr);
305 if (gre_fd < 0) {
306 close(callmgr_sock);
307 fatal("Cannot bind GRE socket, aborting.");
310 /* Find an open pty/tty pair. */
311 if(launchpppd){
312 rc = openpty (&pty_fd, &tty_fd, ttydev, NULL, NULL);
313 if (rc < 0) {
314 close(callmgr_sock);
315 fatal("Could not find free pty.");
318 /* fork and wait. */
319 signal(SIGUSR1, do_nothing); /* don't die */
320 signal(SIGCHLD, do_nothing); /* don't ignore SIGCHLD */
321 parent_pid = getpid();
322 switch (child_pid = fork()) {
323 case -1:
324 fatal("Could not fork pppd process");
325 case 0: /* I'm the child! */
326 close (tty_fd);
327 signal(SIGUSR1, SIG_DFL);
328 child_pid = getpid();
329 break;
330 default: /* parent */
331 close (pty_fd);
333 * There is still a very small race condition here. If a signal
334 * occurs after signaled is checked but before pause is called,
335 * things will hang.
337 if (!signaled) {
338 pause(); /* wait for the signal */
341 if (signaled == SIGCHLD)
342 fatal("Child process died");
344 launch_pppd(ttydev, pppdargc, pppdargv); /* launch pppd */
345 perror("Error");
346 fatal("Could not launch pppd");
348 } else { /* ! launchpppd */
349 pty_fd = tty_fd = STDIN_FILENO;
350 /* close unused file descriptor, that is redirected to the pty */
351 close(STDOUT_FILENO);
352 child_pid = getpid();
353 parent_pid = 0; /* don't kill pppd */
356 do {
358 * Open connection to call manager (Launch call manager if necessary.)
360 callmgr_sock = open_callmgr(inetaddr, phonenr, argc, argv, envp,
361 pty_fd, gre_fd);
362 /* Exchange PIDs, get call ID */
363 } while (get_call_id(callmgr_sock, parent_pid, child_pid,
364 &call_id, &peer_call_id) < 0);
366 /* Send signal to wake up pppd task */
367 if (launchpppd) {
368 kill(parent_pid, SIGUSR1);
369 sleep(2);
370 /* become a daemon */
371 if (!debug && daemon(0, 0) != 0) {
372 perror("daemon");
374 } else {
375 /* re-open stderr as /dev/null to release it */
376 file2fd("/dev/null", "wb", STDERR_FILENO);
379 snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s",
380 ttyname(tty_fd));
381 #ifdef PR_SET_NAME
382 rc = prctl(PR_SET_NAME, "pptpgw", 0, 0, 0);
383 if (rc != 0) perror("prctl");
384 #endif
385 inststr(argc, argv, envp, buf);
386 if (sigsetjmp(env, 1)!= 0) goto shutdown;
388 signal(SIGINT, sighandler);
389 signal(SIGTERM, sighandler);
390 signal(SIGKILL, sighandler);
391 signal(SIGCHLD, sighandler);
392 signal(SIGUSR1, sigstats);
394 if (syncppp) {
395 if (ioctl(pty_fd, TIOCSETD, &disc) < 0) {
396 fatal("Unable to set line discipline to N_HDLC");
397 } else {
398 log("Changed pty line discipline to N_HDLC for synchronous mode");
402 /* Do GRE copy until close. */
403 pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd);
405 shutdown:
406 /* on close, kill all. */
407 if(launchpppd)
408 kill(parent_pid, SIGTERM);
409 close(pty_fd);
410 close(callmgr_sock);
412 if (add_host_route) {
413 route_del(&rt); // don't delete, as otherwise it would try to use pppX in demand mode (since 1.9.2.7-9)
416 exit(0);
419 /*** get the ipaddress coming from the command line ***************************/
420 struct in_addr get_ip_address(char *name)
422 struct in_addr retval;
423 struct hostent *host = gethostbyname(name);
424 if (host == NULL) {
425 if (h_errno == HOST_NOT_FOUND)
426 fatal("gethostbyname '%s': HOST NOT FOUND", name);
427 else if (h_errno == NO_ADDRESS)
428 fatal("gethostbyname '%s': NO IP ADDRESS", name);
429 else
430 fatal("gethostbyname '%s': name server error", name);
432 if (host->h_addrtype != AF_INET)
433 fatal("Host '%s' has non-internet address", name);
434 memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr));
435 return retval;
438 /*** start the call manager ***************************************************/
439 int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char **argv,
440 char **envp, int pty_fd, int gre_fd)
442 /* Try to open unix domain socket to call manager. */
443 struct sockaddr_un where;
444 const int NUM_TRIES = 3;
445 int i, fd;
446 pid_t pid;
447 int status;
448 /* Open socket */
449 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
450 fatal("Could not create unix domain socket: %s", strerror(errno));
452 /* Make address */
453 callmgr_name_unixsock(&where, inetaddr, localbind);
454 for (i = 0; i < NUM_TRIES; i++) {
455 if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) {
456 /* couldn't connect. We'll have to launch this guy. */
458 unlink (where.sun_path);
460 /* fork and launch call manager process */
461 switch (pid = fork()) {
462 case -1: /* failure */
463 fatal("fork() to launch call manager failed.");
464 case 0: /* child */
466 close (fd);
467 /* close the pty and gre in the call manager */
468 close(pty_fd);
469 close(gre_fd);
470 launch_callmgr(inetaddr, phonenr, argc, argv, envp);
472 default: /* parent */
473 waitpid(pid, &status, 0);
474 if (status!= 0)
475 fatal("Call manager exited with error %d", status);
476 break;
478 sleep(1);
480 else return fd;
482 close(fd);
483 fatal("Could not launch call manager after %d tries.", i);
484 return -1; /* make gcc happy */
487 /*** call the call manager main ***********************************************/
488 void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,
489 char**argv,char**envp)
491 char *my_argv[3] = { argv[0], inet_ntoa(inetaddr), phonenr };
492 char buf[128];
493 snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]);
494 inststr(argc, argv, envp, buf);
495 exit(callmgr_main(3, my_argv, envp));
498 /*** exchange data with the call manager *************************************/
499 /* XXX need better error checking XXX */
500 int get_call_id(int sock, pid_t gre, pid_t pppd,
501 u_int16_t *call_id, u_int16_t *peer_call_id)
503 u_int16_t m_call_id, m_peer_call_id;
504 /* write pid's to socket */
505 /* don't bother with network byte order, because pid's are meaningless
506 * outside the local host.
508 int rc;
509 rc = write(sock, &gre, sizeof(gre));
510 if (rc != sizeof(gre))
511 return -1;
512 rc = write(sock, &pppd, sizeof(pppd));
513 if (rc != sizeof(pppd))
514 return -1;
515 rc = read(sock, &m_call_id, sizeof(m_call_id));
516 if (rc != sizeof(m_call_id))
517 return -1;
518 rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id));
519 if (rc != sizeof(m_peer_call_id))
520 return -1;
522 * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX
523 * (Rhialto: I am assuming for now that timeouts are not relevant
524 * here, because the read and write calls would return -1 (fail) when
525 * the peer goes away during the process. We know it is (or was)
526 * running because the connect() call succeeded.)
527 * (James: on the other hand, if the route to the peer goes away, we
528 * wouldn't get told by read() or write() for quite some time.)
530 *call_id = m_call_id;
531 *peer_call_id = m_peer_call_id;
532 return 0;
535 /*** execvp pppd **************************************************************/
536 void launch_pppd(char *ttydev, int argc, char **argv)
538 char *new_argv[argc + 4];/* XXX if not using GCC, hard code a limit here. */
539 int i = 0, j;
540 new_argv[i++] = PPPD_BINARY;
541 #ifdef USER_PPP
542 new_argv[i++] = "-direct";
543 /* ppp expects to have stdin connected to ttydev */
544 if ((j = open(ttydev, O_RDWR)) == -1)
545 fatal("Cannot open %s: %s", ttydev, strerror(errno));
546 if (dup2(j, 0) == -1)
547 fatal("dup2 failed: %s", strerror(errno));
548 close(j);
549 #else
550 new_argv[i++] = ttydev;
551 new_argv[i++] = "38400";
552 #endif
553 for (j = 0; j < argc; j++)
554 new_argv[i++] = argv[j];
555 new_argv[i] = NULL;
556 execvp(new_argv[0], new_argv);
559 /*** route manipulation *******************************************************/
561 static int
562 route_ctrl(int ctrl, struct rtentry *rt)
564 int s;
566 /* Open a raw socket to the kernel */
567 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || ioctl(s, ctrl, rt) < 0)
568 warn("route_ctrl: %s", strerror(errno));
569 else errno = 0;
571 close(s);
572 return errno;
575 static int
576 route_del(struct rtentry *rt)
578 if (rt->rt_dev) {
579 route_ctrl(SIOCDELRT, rt);
580 free(rt->rt_dev), rt->rt_dev = NULL;
583 return 0;
586 static int
587 route_add(const struct in_addr inetaddr, struct rtentry *rt)
589 char buf[256], dev[64];
590 int metric, flags;
591 u_int32_t dest, mask;
593 FILE *f = fopen("/proc/net/route", "r");
594 if (f == NULL) {
595 warn("/proc/net/route: %s", strerror(errno));
596 return -1;
599 while (fgets(buf, sizeof(buf), f))
601 if (sscanf(buf, "%63s %x %x %X %*s %*s %d %x", dev, &dest,
602 &sin_addr(&rt->rt_gateway).s_addr, &flags, &metric, &mask) != 6)
603 continue;
604 if ((flags & RTF_UP) == RTF_UP && (inetaddr.s_addr & mask) == dest &&
605 (dest || strncmp(dev, "ppp", 3)) /* avoid default via pppX to avoid on-demand loops*/)
607 rt->rt_metric = metric;
608 rt->rt_gateway.sa_family = AF_INET;
609 break;
613 fclose(f);
615 /* check for no route */
616 if (rt->rt_gateway.sa_family != AF_INET)
618 /* warn("route_add: no route to host"); */
619 return -1;
622 /* check for existing route to this host,
623 add if missing based on the existing routes */
624 if (flags & RTF_HOST) {
625 /* warn("route_add: not adding existing route"); */
626 return -1;
629 sin_addr(&rt->rt_dst) = inetaddr;
630 rt->rt_dst.sa_family = AF_INET;
632 sin_addr(&rt->rt_genmask).s_addr = INADDR_BROADCAST;
633 rt->rt_genmask.sa_family = AF_INET;
635 rt->rt_flags = RTF_UP | RTF_HOST;
636 if (flags & RTF_GATEWAY)
637 rt->rt_flags |= RTF_GATEWAY;
639 rt->rt_metric++;
640 rt->rt_dev = strdup(dev);
642 if (!rt->rt_dev)
644 warn("route_add: no memory");
645 return -1;
648 if (!route_ctrl(SIOCADDRT, rt))
649 return 0;
651 free(rt->rt_dev), rt->rt_dev = NULL;
653 return -1;