📄 pppoe-server.c
字号:
/************************************************************************* pppoe-server.c** Implementation of a user-space PPPoE server** Copyright (C) 2000 Roaring Penguin Software Inc.** This program may be distributed according to the terms of the GNU* General Public License, version 2 or (at your option) any later version.** $Id: pppoe-server.c,v 1.91 2005/08/10 00:25:21 dfs Exp $** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: pppoe-server.c,v 1.91 2005/08/10 00:25:21 dfs Exp $";#include "config.h"#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)#define _POSIX_SOURCE 1 /* For sigaction defines */#endif#define _BSD_SOURCE 1 /* for gethostname */#include "pppoe-server.h"#include "md5.h"#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#include <errno.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#ifdef HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#include <time.h>#include <signal.h>#ifdef HAVE_LICENSE#include "license.h"#include "licensed-only/servfuncs.h"static struct License const *ServerLicense;static struct License const *ClusterLicense;#else#define control_session_started(x) (void) 0#define control_session_terminated(x) (void) 0#define control_exit() (void) 0#define realpeerip peerip#endif#ifdef HAVE_L2TPextern PppoeSessionFunctionTable L2TPSessionFunctionTable;extern void pppoe_to_l2tp_add_interface(EventSelector *es, Interface *interface);#endifstatic void InterfaceHandler(EventSelector *es, int fd, unsigned int flags, void *data);static void startPPPD(ClientSession *sess);static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest, int errorTag, char *errorMsg);#define CHECK_ROOM(cursor, start, len) \do {\ if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \ syslog(LOG_ERR, "Would create too-long packet"); \ return; \ } \} while(0)static void PppoeStopSession(ClientSession *ses, char const *reason);static int PppoeSessionIsActive(ClientSession *ses);/* Service-Names we advertise */#define MAX_SERVICE_NAMES 64static int NumServiceNames = 0;static char const *ServiceNames[MAX_SERVICE_NAMES];PppoeSessionFunctionTable DefaultSessionFunctionTable = { PppoeStopSession, PppoeSessionIsActive, NULL};/* An array of client sessions */ClientSession *Sessions = NULL;ClientSession *FreeSessions = NULL;ClientSession *LastFreeSession = NULL;ClientSession *BusySessions = NULL;/* Interfaces we're listening on */Interface interfaces[MAX_INTERFACES];int NumInterfaces = 0;/* The number of session slots */size_t NumSessionSlots;/* Number of active sessions */size_t NumActiveSessions = 0;/* Offset of first session */size_t SessOffset = 0;/* Event Selector */EventSelector *event_selector;/* Use Linux kernel-mode PPPoE? */static int UseLinuxKernelModePPPoE = 0;static int Debug = 0;static int CheckPoolSyntax = 0;/* Synchronous mode */static int Synchronous = 0;/* Random seed for cookie generation */#define SEED_LEN 16#define MD5_LEN 16#define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */static unsigned char CookieSeed[SEED_LEN];#define MAXLINE 512/* Default interface if no -I option given */#define DEFAULT_IF "eth0"/* Access concentrator name */char *ACName = NULL;/* Options to pass to pppoe process */char PppoeOptions[SMALLBUF] = "";/* Our local IP address */unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1}; /* Counter optionally STARTS here */unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here *//* Do we increment local IP for each connection? */int IncrLocalIP = 0;/* Do we randomize session numbers? */int RandomizeSessionNumbers = 0;/* Do we pass the "unit" option to pppd? (2.4 or greater) */int PassUnitOptionToPPPD = 0;static PPPoETag hostUniq;static PPPoETag relayId;static PPPoETag receivedCookie;static PPPoETag requestedService;#define HOSTNAMELEN 256/***********************************************************************%FUNCTION: childHandler*%ARGUMENTS:* pid -- pid of child* status -- exit status* ses -- which session terminated*%RETURNS:* Nothing*%DESCRIPTION:* Called synchronously when a child dies. Remove from busy list.***********************************************************************/static voidchildHandler(pid_t pid, int status, void *s){ ClientSession *session = s; /* Temporary structure for sending PADT's. */ PPPoEConnection conn;#ifdef HAVE_L2TP /* We're acting as LAC, so when child exits, become a PPPoE <-> L2TP relay */ if (session->flags & FLAG_ACT_AS_LAC) { syslog(LOG_INFO, "Session %d for client " "%02x:%02x:%02x:%02x:%02x:%02x handed off to LNS %s", ntohs(session->sess), session->eth[0], session->eth[1], session->eth[2], session->eth[3], session->eth[4], session->eth[5], inet_ntoa(session->tunnel_endpoint.sin_addr)); session->pid = 0; session->funcs = &L2TPSessionFunctionTable; return; }#endif memset(&conn, 0, sizeof(conn)); conn.useHostUniq = 0; syslog(LOG_INFO, "Session %d closed for client " "%02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s", ntohs(session->sess), session->eth[0], session->eth[1], session->eth[2], session->eth[3], session->eth[4], session->eth[5], (int) session->realpeerip[0], (int) session->realpeerip[1], (int) session->realpeerip[2], (int) session->realpeerip[3], session->ethif->name); memcpy(conn.myEth, session->ethif->mac, ETH_ALEN); conn.discoverySocket = session->ethif->sock; conn.session = session->sess; memcpy(conn.peerEth, session->eth, ETH_ALEN); if (!(session->flags & FLAG_SENT_PADT)) { if (session->flags & FLAG_RECVD_PADT) { sendPADT(&conn, "RP-PPPoE: Received PADT from peer"); } else { sendPADT(&conn, "RP-PPPoE: Child pppd process terminated"); } session->flags |= FLAG_SENT_PADT; } session->serviceName = ""; control_session_terminated(session); if (pppoe_free_session(session) < 0) { return; }}/***********************************************************************%FUNCTION: incrementIPAddress (static)*%ARGUMENTS:* addr -- a 4-byte array representing IP address*%RETURNS:* Nothing*%DESCRIPTION:* Increments addr in-place***********************************************************************/static voidincrementIPAddress(unsigned char ip[IPV4ALEN]){ ip[3]++; if (!ip[3]) { ip[2]++; if (!ip[2]) { ip[1]++; if (!ip[1]) { ip[0]++; } } }}/***********************************************************************%FUNCTION: killAllSessions*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* Kills all pppd processes (and hence all PPPoE sessions)***********************************************************************/voidkillAllSessions(void){ ClientSession *sess = BusySessions; while(sess) { sess->funcs->stop(sess, "Shutting Down"); sess = sess->next; }#ifdef HAVE_L2TP pppoe_close_l2tp_tunnels();#endif}/***********************************************************************%FUNCTION: parseAddressPool*%ARGUMENTS:* fname -- name of file containing IP address pool.* install -- if true, install IP addresses in sessions.*%RETURNS:* Number of valid IP addresses found.*%DESCRIPTION:* Reads a list of IP addresses from a file.***********************************************************************/static intparseAddressPool(char const *fname, int install){ FILE *fp = fopen(fname, "r"); int numAddrs = 0; unsigned int a, b, c, d; unsigned int e, f, g, h; char line[MAXLINE]; if (!fp) { sysErr("Cannot open address pool file"); exit(1); } while (!feof(fp)) { if (!fgets(line, MAXLINE, fp)) { break; } if ((sscanf(line, "%u.%u.%u.%u:%u.%u.%u.%u", &a, &b, &c, &d, &e, &f, &g, &h) == 8) && a < 256 && b < 256 && c < 256 && d < 256 && e < 256 && f < 256 && g < 256 && h < 256) { /* Both specified (local:remote) */ if (install) { Sessions[numAddrs].myip[0] = (unsigned char) a; Sessions[numAddrs].myip[1] = (unsigned char) b; Sessions[numAddrs].myip[2] = (unsigned char) c; Sessions[numAddrs].myip[3] = (unsigned char) d; Sessions[numAddrs].peerip[0] = (unsigned char) e; Sessions[numAddrs].peerip[1] = (unsigned char) f; Sessions[numAddrs].peerip[2] = (unsigned char) g; Sessions[numAddrs].peerip[3] = (unsigned char) h;#ifdef HAVE_LICENSE memcpy(Sessions[numAddrs].realpeerip, Sessions[numAddrs].peerip, IPV4ALEN);#endif } numAddrs++; } else if ((sscanf(line, "%u.%u.%u.%u-%u", &a, &b, &c, &d, &e) == 5) && a < 256 && b < 256 && c < 256 && d < 256 && e < 256) { /* Remote specied as a.b.c.d-e. Example: 1.2.3.4-8 yields: 1.2.3.4, 1.2.3.5, 1.2.3.6, 1.2.3.7, 1.2.3.8 */ /* Swap d and e so that e >= d */ if (e < d) { f = d; d = e; e = f; } if (install) { while (d <= e) { Sessions[numAddrs].peerip[0] = (unsigned char) a; Sessions[numAddrs].peerip[1] = (unsigned char) b; Sessions[numAddrs].peerip[2] = (unsigned char) c; Sessions[numAddrs].peerip[3] = (unsigned char) d;#ifdef HAVE_LICENSE memcpy(Sessions[numAddrs].realpeerip, Sessions[numAddrs].peerip, IPV4ALEN);#endif d++; numAddrs++; } } else { numAddrs += (e-d) + 1; } } else if ((sscanf(line, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) && a < 256 && b < 256 && c < 256 && d < 256) { /* Only remote specified */ if (install) { Sessions[numAddrs].peerip[0] = (unsigned char) a; Sessions[numAddrs].peerip[1] = (unsigned char) b; Sessions[numAddrs].peerip[2] = (unsigned char) c; Sessions[numAddrs].peerip[3] = (unsigned char) d;#ifdef HAVE_LICENSE memcpy(Sessions[numAddrs].realpeerip, Sessions[numAddrs].peerip, IPV4ALEN);#endif } numAddrs++; } } fclose(fp); if (!numAddrs) { rp_fatal("No valid ip addresses found in pool file"); } return numAddrs;}/***********************************************************************%FUNCTION: parsePADITags*%ARGUMENTS:* type -- tag type* len -- tag length* data -- tag data* extra -- extra user data.*%RETURNS:* Nothing*%DESCRIPTION:* Picks interesting tags out of a PADI packet***********************************************************************/voidparsePADITags(UINT16_t type, UINT16_t len, unsigned char *data, void *extra){ switch(type) { case TAG_SERVICE_NAME: /* Copy requested service name */ requestedService.type = htons(type); requestedService.length = htons(len); memcpy(requestedService.payload, data, len); break; case TAG_RELAY_SESSION_ID: relayId.type = htons(type); relayId.length = htons(len); memcpy(relayId.payload, data, len); break; case TAG_HOST_UNIQ: hostUniq.type = htons(type); hostUniq.length = htons(len); memcpy(hostUniq.payload, data, len); break; }}/***********************************************************************%FUNCTION: parsePADRTags*%ARGUMENTS:* type -- tag type* len -- tag length* data -- tag data* extra -- extra user data.*%RETURNS:* Nothing*%DESCRIPTION:* Picks interesting tags out of a PADR packet***********************************************************************/voidparsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data, void *extra){ switch(type) { case TAG_RELAY_SESSION_ID: relayId.type = htons(type); relayId.length = htons(len); memcpy(relayId.payload, data, len); break; case TAG_HOST_UNIQ: hostUniq.type = htons(type); hostUniq.length = htons(len); memcpy(hostUniq.payload, data, len); break; case TAG_AC_COOKIE: receivedCookie.type = htons(type); receivedCookie.length = htons(len); memcpy(receivedCookie.payload, data, len); break; case TAG_SERVICE_NAME: requestedService.type = htons(type); requestedService.length = htons(len); memcpy(requestedService.payload, data, len); break; }}/***********************************************************************%FUNCTION: fatalSys*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message plus the errno value to stderr and syslog and exits.***********************************************************************/voidfatalSys(char const *str){ char buf[SMALLBUF]; snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno)); printErr(buf); control_exit(); exit(EXIT_FAILURE);}/***********************************************************************%FUNCTION: sysErr*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message plus the errno value to syslog.***********************************************************************/voidsysErr(char const *str){ char buf[1024]; sprintf(buf, "%.256s: %.256s", str, strerror(errno)); printErr(buf);}/***********************************************************************%FUNCTION: rp_fatal*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message to stderr and syslog and exits.***********************************************************************/voidrp_fatal(char const *str){ printErr(str); control_exit(); exit(EXIT_FAILURE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -