diff options
author | nico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-12-16 12:00:19 +0000 |
---|---|---|
committer | nico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2005-12-16 12:00:19 +0000 |
commit | 6f35f0363b0500981f09ea008859259815005f5c (patch) | |
tree | ba5321a96352b8e70b75d3760f7a05307feeeeef /package/l2tpd/patches | |
parent | 447f925ff9e0bca059a62ca97a142da70a38f880 (diff) |
port l2tpd fixes from changeset:2696 to trunk.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@2697 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/l2tpd/patches')
-rw-r--r-- | package/l2tpd/patches/01-debian-2.patch (renamed from package/l2tpd/patches/debian-2.patch) | 0 | ||||
-rw-r--r-- | package/l2tpd/patches/02-debian-2-pty-rev.patch | 21 | ||||
-rw-r--r-- | package/l2tpd/patches/03-jacco-pty.patch | 1194 |
3 files changed, 1215 insertions, 0 deletions
diff --git a/package/l2tpd/patches/debian-2.patch b/package/l2tpd/patches/01-debian-2.patch index 8a6e204c4..8a6e204c4 100644 --- a/package/l2tpd/patches/debian-2.patch +++ b/package/l2tpd/patches/01-debian-2.patch diff --git a/package/l2tpd/patches/02-debian-2-pty-rev.patch b/package/l2tpd/patches/02-debian-2-pty-rev.patch new file mode 100644 index 000000000..135e17e18 --- /dev/null +++ b/package/l2tpd/patches/02-debian-2-pty-rev.patch @@ -0,0 +1,21 @@ +diff -ruN l2tpd-0.70pre-old/l2tpd.c l2tpd-0.70pre-new/l2tpd.c +--- l2tpd-0.70pre-old/l2tpd.c 2005-12-16 12:02:02.000000000 +0100 ++++ l2tpd-0.70pre-new/l2tpd.c 2005-12-16 12:14:24.000000000 +0100 +@@ -336,17 +336,10 @@ + tcgetattr (c->fd, &ptyconf); + *(c->oldptyconf) = ptyconf; + ptyconf.c_cflag &= ~(ICANON | ECHO); +- ptyconf.c_lflag &= ~ECHO; + tcsetattr (c->fd, TCSANOW, &ptyconf); + + snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b); + fd2 = open (tty, O_RDWR); +- if(!fd2) +- log(LOG_WARN, "unable to open tty %s", tty); +- +- /* XXX JEF: CHECK ME */ +- stropt[pos++] = strdup(tty); +- stropt[pos] = NULL; + + #ifdef USE_KERNEL + } diff --git a/package/l2tpd/patches/03-jacco-pty.patch b/package/l2tpd/patches/03-jacco-pty.patch new file mode 100644 index 000000000..67169b8ea --- /dev/null +++ b/package/l2tpd/patches/03-jacco-pty.patch @@ -0,0 +1,1194 @@ +diff -ruN l2tpd-0.70pre-old/l2tpd.c l2tpd-0.70pre-new/l2tpd.c +--- l2tpd-0.70pre-old/l2tpd.c 2005-12-16 12:34:12.000000000 +0100 ++++ l2tpd-0.70pre-new/l2tpd.c 2005-12-16 12:34:54.000000000 +0100 +@@ -16,6 +16,7 @@ + */ + + #include <stdlib.h> ++#include <sys/types.h> + #include <sys/utsname.h> + #include <sys/stat.h> + #include <sys/wait.h> +@@ -274,8 +275,8 @@ + + int start_pppd (struct call *c, struct ppp_opts *opts) + { +- char a, b; +- char tty[80]; ++ /* char a, b; */ ++ char *tty; + char *stropt[80]; + struct ppp_opts *p; + #ifdef USE_KERNEL +@@ -324,12 +325,45 @@ + else + { + #endif +- if ((c->fd = getPtyMaster (&a, &b)) < 0) ++ c->fd = open("/dev/ptmx", O_RDWR); ++ if (c->fd == -1) ++ { ++ log (LOG_WARN, "%s: unable to open /dev/ptmx to allocate pty\n", ++ __FUNCTION__); ++ return -EINVAL; ++ } else ++ { ++ if (grantpt(c->fd)) ++ { ++ log (LOG_WARN, "%s: unable to grantpt() on pty\n", ++ __FUNCTION__); ++ close(c->fd); ++ return -EINVAL; ++ } ++ if (unlockpt(c->fd)) ++ { ++ log (LOG_WARN, "%s: unable to unlockpt() on pty\n", ++ __FUNCTION__); ++ close(c->fd); ++ return -EINVAL; ++ } ++ tty = ptsname(c->fd); ++ if (tty == NULL) ++ { ++ log (LOG_WARN, "%s: unable to obtain name of slave tty\n", ++ __FUNCTION__); ++ close(c->fd); ++ return -EINVAL; ++ } ++ } ++ ++ ++ /* if ((c->fd = getPtyMaster (&a, &b)) < 0) + { + log (LOG_WARN, "%s: unable to allocate pty, abandoning!\n", + __FUNCTION__); + return -EINVAL; +- } ++ } */ + + /* set fd opened above to not echo so we don't see read our own packets + back of the file descriptor that we just wrote them to */ +@@ -338,8 +372,14 @@ + ptyconf.c_cflag &= ~(ICANON | ECHO); + tcsetattr (c->fd, TCSANOW, &ptyconf); + +- snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b); ++/* snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b); */ + fd2 = open (tty, O_RDWR); ++ if (fd2 == -1) ++ { ++ log (LOG_WARN, "%s: unable to open slave tty %s\n", __FUNCTION__, tty); ++ close(c->fd); ++ return -EINVAL; ++ } + + #ifdef USE_KERNEL + } +diff -ruN l2tpd-0.70pre-old/l2tpd.c.orig l2tpd-0.70pre-new/l2tpd.c.orig +--- l2tpd-0.70pre-old/l2tpd.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ l2tpd-0.70pre-new/l2tpd.c.orig 2005-12-16 12:14:24.000000000 +0100 +@@ -0,0 +1,1104 @@ ++/* ++ * $Id$ ++ * ++ * Layer Two Tunnelling Protocol Daemon ++ * Copyright (C) 1998 Adtran, Inc. ++ * Copyright (C) 2002 Jeff McAdams ++ * ++ * Mark Spencer ++ * ++ * This software is distributed under the terms ++ * of the GPL, which you should have received ++ * along with this source. ++ * ++ * Main Daemon source. ++ * ++ */ ++ ++#include <stdlib.h> ++#include <sys/utsname.h> ++#include <sys/stat.h> ++#include <sys/wait.h> ++#include <stdio.h> ++#include <errno.h> ++#include <unistd.h> ++#include <time.h> ++#if (__GLIBC__ < 2) ++# if defined(FREEBSD) ++# include <sys/signal.h> ++# elif defined(LINUX) ++# include <bsd/signal.h> ++# elif defined(SOLARIS) ++# include <signal.h> ++# endif ++#else ++# include <signal.h> ++#endif ++#include <netdb.h> ++#include <string.h> ++#include <fcntl.h> ++#include <netinet/in.h> ++#include <arpa/inet.h> ++#ifdef USE_KERNEL ++#include <sys/ioctl.h> ++#endif ++#include "l2tp.h" ++ ++struct tunnel_list tunnels; ++int max_tunnels = DEF_MAX_TUNNELS; ++struct utsname uts; ++int ppd = 1; /* Packet processing delay */ ++int control_fd; /* descriptor of control area */ ++char *args; ++ ++char *dial_no_tmp; /* jz: Dialnumber for Outgoing Call */ ++int switch_io = 0; /* jz: Switch for Incoming or Outgoing Call */ ++ ++void init_tunnel_list (struct tunnel_list *t) ++{ ++ t->head = NULL; ++ t->count = 0; ++ t->calls = 0; ++} ++ ++/* Now sends to syslog instead - MvO */ ++void show_status (void) ++{ ++ struct schedule_entry *se; ++ struct tunnel *t; ++ struct call *c; ++ struct lns *tlns; ++ struct lac *tlac; ++ struct host *h; ++ int s = 0; ++ log (LOG_WARN, "====== l2tpd statistics ========\n"); ++ log (LOG_WARN, " Scheduler entries:\n"); ++ se = events; ++ while (se) ++ { ++ s++; ++ t = (struct tunnel *) se->data; ++ tlac = (struct lac *) se->data; ++ c = (struct call *) se->data; ++ if (se->func == &hello) ++ { ++ log (LOG_WARN, "%d: HELLO to %d\n", s, t->tid); ++ } ++ else if (se->func == &magic_lac_dial) ++ { ++ log (LOG_WARN, "%d: Magic dial on %s\n", s, tlac->entname); ++ } ++ else if (se->func == &send_zlb) ++ { ++ log (LOG_WARN, "%d: Send payload ZLB on call %d:%d\n", s, ++ c->container->tid, c->cid); ++ } ++ else if (se->func == &dethrottle) ++ { ++ log (LOG_WARN, "%d: Dethrottle call %d:%d\n", s, c->container->tid, ++ c->cid); ++ } ++ else ++ log (LOG_WARN, "%d: Unknown event\n", s); ++ se = se->next; ++ }; ++ log (LOG_WARN, "Total Events scheduled: %d\n", s); ++ log (LOG_WARN, "Number of tunnels open: %d\n", tunnels.count); ++ t = tunnels.head; ++ while (t) ++ { ++ log (LOG_WARN, "Tunnel %s, ID = %d (local), %d (remote) to %s:%d\n" ++ " control_seq_num = %d, control_rec_seq_num = %d,\n" ++ " cLr = %d\n", ++ (t->lac ? t->lac->entname : (t->lns ? t->lns->entname : "")), ++ t->ourtid, t->tid, IPADDY (t->peer.sin_addr), ++ ntohs (t->peer.sin_port), t->control_seq_num, ++ t->control_rec_seq_num, t->cLr); ++ c = t->call_head; ++ while (c) ++ { ++ log (LOG_WARN, ++ "Call %s, ID = %d (local), %d (remote), serno = %u,\n" ++ " data_seq_num = %d, data_rec_seq_num = %d,\n" ++ " pLr = %d, tx = %u bytes (%u), rx= %u bytes (%u)\n", ++ (c->lac ? c->lac-> ++ entname : (c->lns ? c->lns->entname : "")), c->ourcid, ++ c->cid, c->serno, c->data_seq_num, c->data_rec_seq_num, ++ c->pLr, c->tx_bytes, c->tx_pkts, c->rx_bytes, c->rx_pkts); ++ c = c->next; ++ } ++ t = t->next; ++ } ++ log (LOG_WARN, "==========Config File===========\n"); ++ tlns = lnslist; ++ while (tlns) ++ { ++ log (LOG_WARN, "LNS entry %s\n", ++ tlns->entname[0] ? tlns->entname : "(unnamed)"); ++ tlns = tlns->next; ++ }; ++ tlac = laclist; ++ while (tlac) ++ { ++ log (LOG_WARN, "LAC entry %s, LNS is/are:", ++ tlac->entname[0] ? tlac->entname : "(unnamed)"); ++ h = tlac->lns; ++ if (h) ++ { ++ while (h) ++ { ++ log (LOG_WARN, " %s", h->hostname); ++ h = h->next; ++ } ++ } ++ else ++ log (LOG_WARN, " [none]"); ++ log (LOG_WARN, "\n"); ++ tlac = tlac->next; ++ }; ++ log (LOG_WARN, "================================\n"); ++} ++ ++void null_handler(int sig) ++{ ++ /* FIXME ++ * A sighup is received when a call is terminated, unknown origine .. ++ * I catch it and ll looks good, but .. ++ */ ++} ++ ++void status_handler (int sig) ++{ ++ show_status (); ++} ++ ++void child_handler (int signal) ++{ ++ /* ++ * Oops, somebody we launched was killed. ++ * It's time to reap them and close that call. ++ * But first, we have to find out what PID died. ++ * unfortunately, pppd will ++ */ ++ struct tunnel *t; ++ struct call *c; ++ pid_t pid; ++ int status; ++ t = tunnels.head; ++ /* Keep looping until all are cleared */ ++ for(;;) ++ { ++ pid = waitpid (-1, &status, WNOHANG); ++ if (pid < 1) ++ { ++ /* ++ * Oh well, nobody there. Maybe we reaped it ++ * somewhere else already ++ */ ++ return; ++ } ++ while (t) ++ { ++ c = t->call_head; ++ while (c) ++ { ++ if (c->pppd == pid) ++ { ++ if ( WIFEXITED( status ) ) ++ { ++ log (LOG_DEBUG, "%s : pppd exited for call %d with code %d\n", __FUNCTION__, ++ c->cid, WEXITSTATUS( status ) ); ++ } ++ else if( WIFSIGNALED( status ) ) ++ { ++ log (LOG_DEBUG, "%s : pppd terminated for call %d by signal %d\n", __FUNCTION__, ++ c->cid, WTERMSIG( status ) ); ++ } ++ else ++ { ++ log (LOG_DEBUG, "%s : pppd exited for call %d for unknown reason\n", __FUNCTION__, ++ c->cid ); ++ } ++ c->needclose = -1; ++ /* ++ * OK...pppd died, we can go ahead and close the pty for ++ * it ++ */ ++ close (c->fd); ++ c->fd = -1; ++ return; ++ } ++ c = c->next; ++ } ++ t = t->next; ++ } ++ } ++} ++ ++void death_handler (int signal) ++{ ++ /* ++ * If we get here, somebody terminated us with a kill or a control-c. ++ * we call call_close on each tunnel twice to get a StopCCN out ++ * for each one (we can't pause to make sure it's received. ++ * Then we close the connections ++ */ ++ struct tunnel *st, *st2; ++ int sec; ++ log (LOG_CRIT, "%s: Fatal signal %d received\n", __FUNCTION__, signal); ++ st = tunnels.head; ++ while (st) ++ { ++ st2 = st->next; ++ strcpy (st->self->errormsg, "Server closing"); ++ sec = st->self->closing; ++ if (st->lac) ++ st->lac->redial = 0; ++ call_close (st->self); ++ if (!sec) ++ { ++ st->self->closing = -1; ++ call_close (st->self); ++ } ++ st = st2; ++ } ++ ++ /* erase pid file */ ++ unlink (gconfig.pidfile); ++ ++ /* erase control pipe */ ++ unlink(CONTROL_PIPE); ++ ++ exit (1); ++} ++ ++int start_pppd (struct call *c, struct ppp_opts *opts) ++{ ++ char a, b; ++ char tty[80]; ++ char *stropt[80]; ++ struct ppp_opts *p; ++#ifdef USE_KERNEL ++ struct l2tp_call_opts co; ++#endif ++ int pos = 1; ++ int fd2; ++#ifdef DEBUG_PPPD ++ int x; ++#endif ++ struct termios ptyconf; ++ char *str; ++ p = opts; ++ stropt[0] = strdup (PPPD); ++ while (p) ++ { ++ stropt[pos] = (char *) malloc (strlen (p->option) + 1); ++ strncpy (stropt[pos], p->option, strlen (p->option) + 1); ++ pos++; ++ p = p->next; ++ } ++ stropt[pos] = NULL; ++ if (c->pppd > 0) ++ { ++ log (LOG_WARN, "%s: PPP already started on call!\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ if (c->fd > -1) ++ { ++ log (LOG_WARN, "%s: file descriptor already assigned!\n", ++ __FUNCTION__); ++ return -EINVAL; ++ } ++#ifdef USE_KERNEL ++ if (kernel_support) ++ { ++ co.ourtid = c->container->ourtid; ++ co.ourcid = c->ourcid; ++ ioctl (server_socket, L2TPIOCGETCALLOPTS, &co); ++ stropt[pos++] = strdup ("channel"); ++ stropt[pos] = (char *) malloc (10); ++ snprintf (stropt[pos], 10, "%d", co.id); ++ pos++; ++ stropt[pos] = NULL; ++ } ++ else ++ { ++#endif ++ if ((c->fd = getPtyMaster (&a, &b)) < 0) ++ { ++ log (LOG_WARN, "%s: unable to allocate pty, abandoning!\n", ++ __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* set fd opened above to not echo so we don't see read our own packets ++ back of the file descriptor that we just wrote them to */ ++ tcgetattr (c->fd, &ptyconf); ++ *(c->oldptyconf) = ptyconf; ++ ptyconf.c_cflag &= ~(ICANON | ECHO); ++ tcsetattr (c->fd, TCSANOW, &ptyconf); ++ ++ snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b); ++ fd2 = open (tty, O_RDWR); ++ ++#ifdef USE_KERNEL ++ } ++#endif ++ str = stropt[0]; ++#ifdef DEBUG_PPPD ++ log (LOG_DEBUG, "%s: I'm running: ", __FUNCTION__); ++ for (x = 0; stropt[x]; x++) ++ { ++ log (LOG_DEBUG, "\"%s\" ", stropt[x]); ++ }; ++ log (LOG_DEBUG, "\n"); ++#endif ++ c->pppd = fork (); ++ if (c->pppd < 0) ++ { ++ log (LOG_WARN, "%s: unable to fork(), abandoning!\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ else if (!c->pppd) ++ { ++ struct call *sc; ++ struct tunnel *st; ++ ++ close (0); ++ close (1); ++ close (2); ++#ifdef USE_KERNEL ++ if (!kernel_support && (fd2 < 0)) ++#else ++ if (fd2 < 0) ++#endif ++ { ++ log (LOG_WARN, "%s: Unable to open %s to launch pppd!\n", ++ __FUNCTION__, tty); ++ exit (1); ++ } ++ dup2 (fd2, 0); ++ dup2 (fd2, 1); ++ ++ ++ /* close all the calls pty fds */ ++ st = tunnels.head; ++ while (st) ++ { ++ sc = st->call_head; ++ while (sc) ++ { ++ close (sc->fd); ++ sc = sc->next; ++ } ++ st = st->next; ++ } ++ ++ /* close the UDP socket fd */ ++ close (server_socket); ++ ++ /* close the control pipe fd */ ++ close (control_fd); ++ ++ if( c->dialing[0] ) ++ { ++ setenv( "CALLER_ID", c->dialing, 1 ); ++ } ++ execv (PPPD, stropt); ++ log (LOG_WARN, "%s: Exec of %s failed!\n", __FUNCTION__, PPPD); ++ exit (1); ++ }; ++ close (fd2); ++ pos = 0; ++ while (stropt[pos]) ++ { ++ free (stropt[pos]); ++ pos++; ++ }; ++ return 0; ++} ++ ++void destroy_tunnel (struct tunnel *t) ++{ ++ /* ++ * Immediately destroy a tunnel (and all its calls) ++ * and free its resources. This may be called ++ * by the tunnel itself,so it needs to be ++ * "suicide safe" ++ */ ++ ++ struct call *c, *me; ++ struct tunnel *p; ++ struct timeval tv; ++ if (!t) ++ return; ++ ++ /* ++ * Save ourselves until the very ++ * end, since we might be calling this ourselves. ++ * We must divorce ourself from the tunnel ++ * structure, however, to avoid recursion ++ * because of the logic of the destroy_call ++ */ ++ me = t->self; ++ ++ /* ++ * Destroy all the member calls ++ */ ++ c = t->call_head; ++ while (c) ++ { ++ destroy_call (c); ++ c = c->next; ++ }; ++ /* ++ * Remove ourselves from the list of tunnels ++ */ ++ ++ if (tunnels.head == t) ++ { ++ tunnels.head = t->next; ++ tunnels.count--; ++ } ++ else ++ { ++ p = tunnels.head; ++ if (p) ++ { ++ while (p->next && (p->next != t)) ++ p = p->next; ++ if (p->next) ++ { ++ p->next = t->next; ++ tunnels.count--; ++ } ++ else ++ { ++ log (LOG_WARN, ++ "%s: unable to locate tunnel in tunnel list\n", ++ __FUNCTION__); ++ } ++ } ++ else ++ { ++ log (LOG_WARN, "%s: tunnel list is empty!\n", __FUNCTION__); ++ } ++ } ++ if (t->lac) ++ { ++ t->lac->t = NULL; ++ if (t->lac->redial && (t->lac->rtimeout > 0) && !t->lac->rsched && ++ t->lac->active) ++ { ++ log (LOG_LOG, "%s: Will redial in %d seconds\n", __FUNCTION__, ++ t->lac->rtimeout); ++ tv.tv_sec = t->lac->rtimeout; ++ tv.tv_usec = 0; ++ t->lac->rsched = schedule (tv, magic_lac_dial, t->lac); ++ } ++ } ++ /* XXX L2TP/IPSec: remove relevant SAs here? NTB 20011010 ++ * XXX But what if another tunnel is using same SA? ++ */ ++ if (t->lns) ++ t->lns->t = NULL; ++ free (t); ++ free (me); ++} ++ ++struct tunnel *l2tp_call (char *host, int port, struct lac *lac, ++ struct lns *lns) ++{ ++ /* ++ * Establish a tunnel from us to host ++ * on port port ++ */ ++ struct call *tmp = NULL; ++ struct hostent *hp; ++ unsigned int addr; ++ port = htons (port); ++ hp = gethostbyname (host); ++ if (!hp) ++ { ++ log (LOG_WARN, "%s: gethostbyname() failed for %s.\n", __FUNCTION__, ++ host); ++ return NULL; ++ } ++ bcopy (hp->h_addr, &addr, hp->h_length); ++ /* Force creation of a new tunnel ++ and set it's tid to 0 to cause ++ negotiation to occur */ ++ /* XXX L2TP/IPSec: Set up SA to addr:port here? NTB 20011010 ++ */ ++ tmp = get_call (0, 0, addr, port); ++ if (!tmp) ++ { ++ log (LOG_WARN, "%s: Unable to create tunnel to %s.\n", __FUNCTION__, ++ host); ++ return NULL; ++ } ++ tmp->container->tid = 0; ++ tmp->container->lac = lac; ++ tmp->container->lns = lns; ++ tmp->lac = lac; ++ tmp->lns = lns; ++ if (lac) ++ lac->t = tmp->container; ++ if (lns) ++ lns->t = tmp->container; ++ /* ++ * Since our state is 0, we will establish a tunnel now ++ */ ++ log (LOG_LOG, "%s:Connecting to host %s, port %d\n", __FUNCTION__, host, ++ ntohs (port)); ++ control_finish (tmp->container, tmp); ++ return tmp->container; ++} ++ ++void magic_lac_tunnel (void *data) ++{ ++ struct lac *lac; ++ lac = (struct lac *) data; ++ if (!lac) ++ { ++ log (LOG_WARN, "%s: magic_lac_tunnel: called on NULL lac!\n", ++ __FUNCTION__); ++ return; ++ } ++ if (lac->lns) ++ { ++ /* FIXME: I should try different LNS's if I get failures */ ++ l2tp_call (lac->lns->hostname, lac->lns->port, lac, NULL); ++ return; ++ } ++ else if (deflac && deflac->lns) ++ { ++ l2tp_call (deflac->lns->hostname, deflac->lns->port, lac, NULL); ++ return; ++ } ++ else ++ { ++ log (LOG_WARN, "%s: Unable to find hostname to dial for '%s'\n", ++ __FUNCTION__, lac->entname); ++ return; ++ } ++} ++ ++struct call *lac_call (int tid, struct lac *lac, struct lns *lns) ++{ ++ struct tunnel *t = tunnels.head; ++ struct call *tmp; ++ while (t) ++ { ++ if (t->ourtid == tid) ++ { ++ tmp = new_call (t); ++ if (!tmp) ++ { ++ log (LOG_WARN, "%s: unable to create new call\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ tmp->next = t->call_head; ++ t->call_head = tmp; ++ t->count++; ++ tmp->cid = 0; ++ tmp->lac = lac; ++ tmp->lns = lns; ++ if (lac) ++ lac->c = tmp; ++ log (LOG_LOG, "%s: Calling on tunnel %d\n", __FUNCTION__, tid); ++ strcpy (tmp->dial_no, dial_no_tmp); /* jz: copy dialnumber to tmp->dial_no */ ++ control_finish (t, tmp); ++ return tmp; ++ } ++ t = t->next; ++ }; ++ log (LOG_DEBUG, "%s: No such tunnel %d to generate call.\n", __FUNCTION__, ++ tid); ++ return NULL; ++} ++ ++void magic_lac_dial (void *data) ++{ ++ struct lac *lac; ++ lac = (struct lac *) data; ++ ++ if (!lac) ++ { ++ log (LOG_WARN, "%s : called on NULL lac!\n", __FUNCTION__); ++ return; ++ } ++ if (!lac->active) ++ { ++ log (LOG_DEBUG, "%s: LAC %s not active", __FUNCTION__, lac->entname); ++ return; ++ } ++ lac->rsched = NULL; ++ lac->rtries++; ++ if (lac->rmax && (lac->rtries > lac->rmax)) ++ { ++ log (LOG_LOG, "%s: maximum retries exceeded.\n", __FUNCTION__); ++ return; ++ } ++ if (!lac->t) ++ { ++#ifdef DEGUG_MAGIC ++ log (LOG_DEBUG, "%s : tunnel not up! Connecting!\n", __FUNCTION__); ++#endif ++ magic_lac_tunnel (lac); ++ return; ++ } ++ lac_call (lac->t->ourtid, lac, NULL); ++} ++ ++void lac_hangup (int cid) ++{ ++ struct tunnel *t = tunnels.head; ++ struct call *tmp; ++ while (t) ++ { ++ tmp = t->call_head; ++ while (tmp) ++ { ++ if (tmp->ourcid == cid) ++ { ++ log (LOG_LOG, ++ "%s :Hanging up call %d, Local: %d, Remote: %d\n", ++ __FUNCTION__, tmp->serno, tmp->ourcid, tmp->cid); ++ strcpy (tmp->errormsg, "Goodbye!"); ++/* tmp->needclose = -1; */ ++ kill (tmp->pppd, SIGTERM); ++ return; ++ } ++ tmp = tmp->next; ++ } ++ t = t->next; ++ }; ++ log (LOG_DEBUG, "%s : No such call %d to hang up.\n", __FUNCTION__, cid); ++ return; ++} ++ ++void lac_disconnect (int tid) ++{ ++ struct tunnel *t = tunnels.head; ++ while (t) ++ { ++ if (t->ourtid == tid) ++ { ++ log (LOG_LOG, ++ "%s: Disconnecting from %s, Local: %d, Remote: %d\n", ++ __FUNCTION__, IPADDY (t->peer.sin_addr), t->ourtid, t->tid); ++ t->self->needclose = -1; ++ strcpy (t->self->errormsg, "Goodbye!"); ++ call_close (t->self); ++ return; ++ } ++ t = t->next; ++ }; ++ log (LOG_DEBUG, "%s: No such tunnel %d to hang up.\n", __FUNCTION__, tid); ++ return; ++} ++ ++struct tunnel *new_tunnel () ++{ ++ struct tunnel *tmp = malloc (sizeof (struct tunnel)); ++ char entropy_buf[2] = "\0"; ++ if (!tmp) ++ return NULL; ++ tmp->control_seq_num = 0; ++ tmp->control_rec_seq_num = 0; ++ tmp->cLr = 0; ++ tmp->call_head = NULL; ++ tmp->next = NULL; ++ tmp->debug = -1; ++ tmp->tid = -1; ++ tmp->hello = NULL; ++#ifndef TESTING ++/* while(get_call((tmp->ourtid = rand() & 0xFFFF),0,0,0)); */ ++#ifdef USE_KERNEL ++ if (kernel_support) ++ tmp->ourtid = ioctl (server_socket, L2TPIOCADDTUNNEL, 0); ++ else ++#endif ++/* tmp->ourtid = rand () & 0xFFFF; */ ++ /* get_entropy((char *)&tmp->ourtid, 2); */ ++ get_entropy(entropy_buf, 2); ++ { ++ int *temp; ++ temp = (int *)entropy_buf; ++ tmp->ourtid = *temp & 0xFFFF; ++#ifdef DEBUG_ENTROPY ++ log(LOG_DEBUG, "ourtid = %u, entropy_buf = %hx\n", tmp->ourtid, *temp); ++#endif ++ } ++#else ++ tmp->ourtid = 0x6227; ++#endif ++ tmp->nego = 0; ++ tmp->count = 0; ++ tmp->state = 0; /* Nothing */ ++ tmp->peer.sin_family = AF_INET; ++ tmp->peer.sin_port = 0; ++ bzero (&(tmp->peer.sin_addr), sizeof (tmp->peer.sin_addr)); ++ tmp->sanity = -1; ++ tmp->qtid = -1; ++ tmp->ourfc = ASYNC_FRAMING | SYNC_FRAMING; ++ tmp->ourbc = 0; ++ tmp->ourtb = (((_u64) rand ()) << 32) | ((_u64) rand ()); ++ tmp->fc = -1; /* These really need to be specified by the peer */ ++ tmp->bc = -1; /* And we want to know if they forgot */ ++ tmp->hostname[0] = 0; ++ tmp->vendor[0] = 0; ++ tmp->secret[0] = 0; ++ if (!(tmp->self = new_call (tmp))) ++ { ++ free (tmp); ++ return NULL; ++ }; ++ tmp->ourrws = DEFAULT_RWS_SIZE; ++ tmp->self->ourfbit = FBIT; ++ tmp->lac = NULL; ++ tmp->lns = NULL; ++ tmp->chal_us.state = 0; ++ tmp->chal_us.secret[0] = 0; ++ memset (tmp->chal_us.reply, 0, MD_SIG_SIZE); ++ tmp->chal_them.state = 0; ++ tmp->chal_them.secret[0] = 0; ++ memset (tmp->chal_them.reply, 0, MD_SIG_SIZE); ++ tmp->chal_them.vector = (unsigned char *) malloc (VECTOR_SIZE); ++ tmp->chal_us.vector = NULL; ++ tmp->hbit = 0; ++ return tmp; ++} ++ ++void do_control () ++{ ++ char buf[1024]; ++ char *host, *tunstr, *callstr, *tmpstr; ++ struct lac *lac; ++ int call; ++ int tunl; ++ int cnt = -1; ++ while (cnt) ++ { ++ cnt = read (control_fd, buf, sizeof (buf)); ++ if (cnt > 0) ++ { ++ if (buf[cnt - 1] == '\n') ++ buf[--cnt] = 0; ++#ifdef DEBUG_CONTROL ++ log (LOG_DEBUG, "%s: Got message \"%s\" (%d bytes long)\n", ++ __FUNCTION__, buf, cnt); ++#endif ++ switch (buf[0]) ++ { ++ case 't': ++ host = strchr (buf, ' '); ++ if(!host) ++ goto out; ++ host++; ++#ifdef DEBUG_CONTROL ++ log (LOG_DEBUG, "%s: Attempting to tunnel to %s\n", ++ __FUNCTION__, host); ++#endif ++ l2tp_call (host, UDP_LISTEN_PORT, NULL, NULL); ++ break; ++ case 'c': /* option 'c' for incoming call */ ++ case 'o': /* option 'o' for outgoing call */ ++ tunstr = strchr (buf, ' '); ++ if(!tunstr) ++ goto out; ++ tunstr++; ++ ++ if(buf[0] == 'c') ++ switch_io = 1; /* Switch for Incoming Calls */ ++ else { ++ switch_io = 0; /* Switch for Outgoing Calls */ ++ tmpstr = strchr(tunstr, ' '); ++ if(!tmpstr) ++ goto out; ++ strncpy(dial_no_tmp,tmpstr, sizeof(*dial_no_tmp)); ++ } ++ ++ lac = laclist; ++ while (lac) ++ { ++ if (!strcasecmp (lac->entname, tunstr)) ++ { ++ lac->active = -1; ++ lac->rtries = 0; ++ if (!lac->c) ++ magic_lac_dial (lac); ++ else ++ log (LOG_DEBUG, ++ "%s: Session '%s' already active!\n", ++ __FUNCTION__, lac->entname); ++ break; ++ } ++ lac = lac->next; ++ } ++ if (lac) ++ break; ++ tunl = atoi (tunstr); ++ if (!tunl) ++ { ++ log (LOG_DEBUG, "%s: No such tunnel '%s'\n", __FUNCTION__, ++ tunstr); ++ break; ++ } ++#ifdef DEBUG_CONTROL ++ log (LOG_DEBUG, "%s: Attempting to call on tunnel %d\n", ++ __FUNCTION__, tunl); ++#endif ++ lac_call (tunl, NULL, NULL); ++ break; ++ case 'h': ++ callstr = strchr (buf, ' '); ++ if(!callstr) ++ goto out; ++ callstr++; ++ ++ call = atoi (callstr); ++#ifdef DEBUG_CONTROL ++ log (LOG_DEBUG, "%s: Attempting to call %d\n", __FUNCTION__, ++ call); ++#endif ++ lac_hangup (call); ++ break; ++ case 'd': ++ tunstr = strchr (buf, ' '); ++ if(!tunstr) ++ goto out; ++ tunstr++; ++ ++ lac = laclist; ++ while (lac) ++ { ++ if (!strcasecmp (lac->entname, tunstr)) ++ { ++ lac->active = 0; ++ lac->rtries = 0; ++ if (lac->t) ++ lac_disconnect (lac->t->ourtid); ++ else ++ log (LOG_DEBUG, "%s: Session '%s' not up\n", ++ __FUNCTION__, lac->entname); ++ break; ++ } ++ lac = lac->next; ++ } ++ if (lac) ++ break; ++ tunl = atoi (tunstr); ++ if (!tunl) ++ { ++ log (LOG_DEBUG, "%s: No such tunnel '%s'\n", __FUNCTION__, ++ tunstr); ++ break; ++ } ++#ifdef DEBUG_CONTROL ++ log (LOG_DEBUG, "%s: Attempting to disconnect tunnel %d\n", ++ __FUNCTION__, tunl); ++#endif ++ lac_disconnect (tunl); ++ break; ++ case 's': ++ show_status (); ++ break; ++ default: ++ log (LOG_DEBUG, "%s: Unknown command %c\n", __FUNCTION__, ++ buf[0]); ++ } ++ } ++ } ++ ++out: ++ /* Otherwise select goes nuts */ ++ close (control_fd); ++ control_fd = open (CONTROL_PIPE, O_RDONLY | O_NONBLOCK, 0600); ++} ++ ++void usage(void) { ++ printf("Usage: l2tpd -D -c [config file] -s [secret file] -p [pid file]\n"); ++ printf("\n"); ++ exit(1); ++} ++ ++void init_args(int argc, char *argv[]) { ++ int i=0; ++ gconfig.daemon=1; ++ memset(gconfig.altauthfile,0,STRLEN); ++ memset(gconfig.altconfigfile,0,STRLEN); ++ memset(gconfig.authfile,0,STRLEN); ++ memset(gconfig.configfile,0,STRLEN); ++ memset(gconfig.pidfile,0,STRLEN); ++ strncpy(gconfig.altauthfile,ALT_DEFAULT_AUTH_FILE, ++ sizeof(gconfig.altauthfile) - 1); ++ strncpy(gconfig.altconfigfile,ALT_DEFAULT_CONFIG_FILE, ++ sizeof(gconfig.altconfigfile) - 1); ++ strncpy(gconfig.authfile,DEFAULT_AUTH_FILE, ++ sizeof(gconfig.authfile) - 1); ++ strncpy(gconfig.configfile,DEFAULT_CONFIG_FILE, ++ sizeof(gconfig.configfile) - 1); ++ strncpy(gconfig.pidfile,DEFAULT_PID_FILE, ++ sizeof(gconfig.pidfile) - 1); ++ for (i = 1; i < argc; i++) { ++ if(! strncmp(argv[i],"-c",2)) { ++ if(++i == argc) ++ usage(); ++ else ++ strncpy(gconfig.configfile,argv[i], ++ sizeof(gconfig.configfile) - 1); ++ } ++ else if (! strncmp(argv[i],"-D",2)) { ++ gconfig.daemon=0; ++ } ++ else if (! strncmp(argv[i],"-s",2)) { ++ if(++i == argc) ++ usage(); ++ else ++ strncpy(gconfig.authfile,argv[i], ++ sizeof(gconfig.authfile) - 1); ++ } ++ else if (! strncmp(argv[i],"-p",2)) { ++ if(++i == argc) ++ usage(); ++ else ++ strncpy(gconfig.pidfile,argv[i], ++ sizeof(gconfig.pidfile) - 1); ++ } ++ else { ++ usage(); ++ } ++ } ++} ++ ++ ++void daemonize() { ++ int pid=0; ++ int i,l; ++ char buf[STRLEN]; ++ ++ if((pid = fork()) < 0) { ++ log(LOG_LOG, "%s: Unable to fork ()\n",__FUNCTION__); ++ close(server_socket); ++ exit(1); ++ } ++ else if (pid) ++ exit(0); ++ ++ ++ close(0); ++ close(1); ++ close(2); ++ dup2(open("/dev/null", O_RDONLY), 0); ++ dup2(open("/dev/null", O_RDONLY), 1); ++ dup2(open("/dev/null", O_RDONLY), 2); ++ ++ /* Read previous pid file. */ ++ if((i = open(gconfig.pidfile,O_RDONLY)) > 0) { ++ l=read(i,buf,sizeof(buf)-1); ++ if (l >= 0) { ++ buf[l] = '\0'; ++ pid = atoi(buf); ++ } ++ close(i); ++ ++ /* if pid is read and process exist exit */ ++ if(pid && !kill(pid, 0)) { ++ log(LOG_LOG, "%s: There's already a l2tpd server running.\n", ++ __FUNCTION__); ++ close(server_socket); ++ exit(1); ++ } ++ ++ /* remove stalled pid file */ ++ unlink(gconfig.pidfile); ++ } ++ ++ pid = setsid(); ++ ++ /* create new pid file */ ++ if ((i = open (gconfig.pidfile, O_WRONLY | O_CREAT, 0644)) >= 0) { ++ snprintf (buf, sizeof(buf), "%d", (int)getpid()); ++ write (i, buf, strlen(buf)); ++ close (i); ++ } ++ else { ++ log(LOG_LOG, "%s: could not write pid file %s error %d", ++ __FUNCTION__, gconfig.pidfile, i); ++ close(server_socket); ++ exit(1); ++ } ++} ++ ++ ++void init (int argc,char *argv[]) ++{ ++ struct lac *lac; ++ struct in_addr listenaddr; ++ ++ init_args (argc,argv); ++ srand( time(NULL) ); ++ rand_source = 0; ++ init_addr (); ++ if (init_config ()) ++ { ++ log (LOG_CRIT, "%s: Unable to load config file\n", __FUNCTION__); ++ exit (1); ++ } ++ if (uname (&uts)) ++ { ++ log (LOG_CRIT, "%s : Unable to determine host system\n", ++ __FUNCTION__); ++ exit (1); ++ } ++ init_tunnel_list (&tunnels); ++ if (init_network ()) ++ exit (1); ++ if (gconfig.daemon) ++ daemonize (); ++ signal (SIGTERM, &death_handler); ++ signal (SIGINT, &death_handler); ++ signal (SIGCHLD, &child_handler); ++ signal (SIGUSR1, &status_handler); ++ signal (SIGHUP, &null_handler); ++ init_scheduler (); ++ mkfifo (CONTROL_PIPE, 0600); ++ control_fd = open (CONTROL_PIPE, O_RDONLY | O_NONBLOCK, 0600); ++ if (control_fd < 0) ++ { ++ log (LOG_CRIT, "%s: Unable to open " CONTROL_PIPE " for reading.", ++ __FUNCTION__); ++ exit (1); ++ } ++ log (LOG_LOG, "l2tpd version " SERVER_VERSION " started on %s PID:%d\n", ++ hostname, getpid ()); ++ listenaddr.s_addr = gconfig.listenaddr; ++ log (LOG_LOG, "%s version %s on a %s, listening on IP address %s, port %d\n", uts.sysname, ++ uts.release, uts.machine, inet_ntoa(listenaddr), gconfig.port); ++ lac = laclist; ++ while (lac) ++ { ++ if (lac->autodial) ++ { ++#ifdef DEBUG_MAGIC ++ log (LOG_DEBUG, "%s: Autodialing '%s'\n", __FUNCTION__, ++ lac->entname[0] ? lac->entname : "(unnamed)"); ++#endif ++ lac->active = -1; ++ switch_io = 1; /* If we're a LAC, autodials will be ICRQ's */ ++ magic_lac_dial (lac); ++ } ++ lac = lac->next; ++ } ++} ++ ++int main (int argc, char *argv[]) ++{ ++ init(argc,argv); ++ dial_no_tmp = calloc (128, sizeof (char)); ++ network_thread (); ++ return 0; ++} |