📄 l2tpd.c
字号:
/* * 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>#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;}void show_status (int fd){ struct schedule_entry *se; struct tunnel *t; struct call *c; struct lns *tlns; struct lac *tlac; struct host *h; int s = 0; int fd2 = dup (fd); FILE *f = fdopen (fd2, "a"); if (!f) { log (LOG_WARN, "show_status: fdopen() failed on fd %d\n", fd); return; } fprintf (f, "====== l2tpd statistics ========\n"); fprintf (f, " 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) { fprintf (f, "%d: HELLO to %d\n", s, t->tid); } else if (se->func == &magic_lac_dial) { fprintf (f, "%d: Magic dial on %s\n", s, tlac->entname); } else if (se->func == &send_zlb) { fprintf (f, "%d: Send payload ZLB on call %d:%d\n", s, c->container->tid, c->cid); } else if (se->func == &dethrottle) { fprintf (f, "%d: Dethrottle call %d:%d\n", s, c->container->tid, c->cid); } else fprintf (f, "%d: Unknown event\n", s); se = se->next; }; fprintf (f, "Total Events scheduled: %d\n", s); fprintf (f, "Number of tunnels open: %d\n", tunnels.count); fprintf (f, "Highest file descriptor: %d\n", fd2); t = tunnels.head; while (t) { fprintf (f, "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) { fprintf (f, "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; } fprintf (f, "==========Config File===========\n"); tlns = lnslist; while (tlns) { fprintf (f, "LNS entry %s\n", tlns->entname[0] ? tlns->entname : "(unnamed)"); tlns = tlns->next; }; tlac = laclist; while (tlac) { fprintf (f, "LAC entry %s, LNS is/are:", tlac->entname[0] ? tlac->entname : "(unnamed)"); h = tlac->lns; if (h) { while (h) { fprintf (f, " %s", h->hostname); h = h->next; } } else fprintf (f, " [none]"); fprintf (f, "\n"); tlac = tlac->next; }; fprintf (f, "================================\n"); fclose (f); close (fd2);}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 (1);}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; 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) { log (LOG_DEBUG, "%s : pppd died for call %d\n", __FUNCTION__, c->cid); c->needclose = -1; /* * OK...pppd died, we can go ahead and close the pty for * it */ close (c->fd); 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); 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -