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