⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 relay.c

📁 linux下的拨号程序rp-pppoe.3.7
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************************************* relay.c** Implementation of PPPoE relay** Copyright (C) 2001-2005 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.** LIC: GPL** $Id: relay.c,v 1.27 2005/08/10 00:25:21 dfs Exp $************************************************************************/static char const RCSID[] ="$Id: relay.c,v 1.27 2005/08/10 00:25:21 dfs Exp $";#define _GNU_SOURCE 1 /* For SA_RESTART */#include "relay.h"#include <signal.h>#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include <stdlib.h>#include <string.h>#include <errno.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_UIO_H#include <sys/uio.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif/* Interfaces (max MAX_INTERFACES) */PPPoEInterface Interfaces[MAX_INTERFACES];int NumInterfaces;/* Relay info */int NumSessions;int MaxSessions;PPPoESession *AllSessions;PPPoESession *FreeSessions;PPPoESession *ActiveSessions;SessionHash *AllHashes;SessionHash *FreeHashes;SessionHash *Buckets[HASHTAB_SIZE];volatile unsigned int Epoch = 0;volatile unsigned int CleanCounter = 0;/* How often to clean up stale sessions? */#define MIN_CLEAN_PERIOD 30  /* Minimum period to run cleaner */#define TIMEOUT_DIVISOR 20   /* How often to run cleaner per timeout period */unsigned int CleanPeriod = MIN_CLEAN_PERIOD;/* How long a session can be idle before it is cleaned up? */unsigned int IdleTimeout = MIN_CLEAN_PERIOD * TIMEOUT_DIVISOR;/* Pipe for breaking select() to initiate periodic cleaning */int CleanPipe[2];/* Our relay: if_index followed by peer_mac */#define MY_RELAY_TAG_LEN (sizeof(int) + ETH_ALEN)/* Hack for daemonizing */#define CLOSEFD 64/***********************************************************************%FUNCTION: keepDescriptor*%ARGUMENTS:* fd -- a file descriptor*%RETURNS:* 1 if descriptor should NOT be closed during daemonizing; 0 otherwise.***********************************************************************/static intkeepDescriptor(int fd){    int i;    if (fd == CleanPipe[0] || fd == CleanPipe[1]) return 1;    for (i=0; i<NumInterfaces; i++) {	if (fd == Interfaces[i].discoverySock ||	    fd == Interfaces[i].sessionSock) return 1;    }    return 0;}/***********************************************************************%FUNCTION: addTag*%ARGUMENTS:* packet -- a PPPoE packet* tag -- tag to add*%RETURNS:* -1 if no room in packet; number of bytes added otherwise.*%DESCRIPTION:* Inserts a tag as the first tag in a PPPoE packet.***********************************************************************/intaddTag(PPPoEPacket *packet, PPPoETag const *tag){    return insertBytes(packet, packet->payload, tag,		       ntohs(tag->length) + TAG_HDR_SIZE);}/***********************************************************************%FUNCTION: insertBytes*%ARGUMENTS:* packet -- a PPPoE packet* loc -- location at which to insert bytes of data* bytes -- the data to insert* len -- length of data to insert*%RETURNS:* -1 if no room in packet; len otherwise.*%DESCRIPTION:* Inserts "len" bytes of data at location "loc" in "packet", moving all* other data up to make room.***********************************************************************/intinsertBytes(PPPoEPacket *packet,	    unsigned char *loc,	    void const *bytes,	    int len){    int toMove;    int plen = ntohs(packet->length);    /* Sanity checks */    if (loc < packet->payload ||	loc > packet->payload + plen ||	len + plen > MAX_PPPOE_PAYLOAD) {	return -1;    }    toMove = (packet->payload + plen) - loc;    memmove(loc+len, loc, toMove);    memcpy(loc, bytes, len);    packet->length = htons(plen + len);    return len;}/***********************************************************************%FUNCTION: removeBytes*%ARGUMENTS:* packet -- a PPPoE packet* loc -- location at which to remove bytes of data* len -- length of data to remove*%RETURNS:* -1 if there was a problem, len otherwise*%DESCRIPTION:* Removes "len" bytes of data from location "loc" in "packet", moving all* other data down to close the gap***********************************************************************/intremoveBytes(PPPoEPacket *packet,	    unsigned char *loc,	    int len){    int toMove;    int plen = ntohs(packet->length);    /* Sanity checks */    if (len < 0 || len > plen ||	loc < packet->payload ||	loc + len > packet->payload + plen) {	return -1;    }    toMove = ((packet->payload + plen) - loc) - len;    memmove(loc, loc+len, toMove);    packet->length = htons(plen - len);    return len;}/***********************************************************************%FUNCTION: usage*%ARGUMENTS:* argv0 -- program name*%RETURNS:* Nothing*%DESCRIPTION:* Prints usage information and exits.***********************************************************************/voidusage(char const *argv0){    fprintf(stderr, "Usage: %s [options]\n", argv0);    fprintf(stderr, "Options:\n");    fprintf(stderr, "   -S if_name     -- Specify interface for PPPoE Server\n");    fprintf(stderr, "   -C if_name     -- Specify interface for PPPoE Client\n");    fprintf(stderr, "   -B if_name     -- Specify interface for both clients and server\n");    fprintf(stderr, "   -n nsess       -- Maxmimum number of sessions to relay\n");    fprintf(stderr, "   -i timeout     -- Idle timeout in seconds (0 = no timeout)\n");    fprintf(stderr, "   -F             -- Do not fork into background\n");    fprintf(stderr, "   -h             -- Print this help message\n");    fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2001-2005 Roaring Penguin Software Inc.\n", VERSION);    fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");    fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");    fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");    fprintf(stderr, "http://www.roaringpenguin.com\n");    exit(EXIT_SUCCESS);}/***********************************************************************%FUNCTION: main*%ARGUMENTS:* argc, argv -- usual suspects*%RETURNS:* EXIT_SUCCESS or EXIT_FAILURE*%DESCRIPTION:* Main program.  Options:* -C ifname           -- Use interface for PPPoE clients* -S ifname           -- Use interface for PPPoE servers* -B ifname           -- Use interface for both clients and servers* -n sessions         -- Maximum of "n" sessions***********************************************************************/intmain(int argc, char *argv[]){    int opt;    int nsess = DEFAULT_SESSIONS;    struct sigaction sa;    int beDaemon = 1;    if (getuid() != geteuid() ||	getgid() != getegid()) {	fprintf(stderr, "SECURITY WARNING: pppoe-relay will NOT run suid or sgid.  Fix your installation.\n");	exit(1);    }    openlog("pppoe-relay", LOG_PID, LOG_DAEMON);    while((opt = getopt(argc, argv, "hC:S:B:n:i:F")) != -1) {	switch(opt) {	case 'h':	    usage(argv[0]);	    break;	case 'F':	    beDaemon = 0;	    break;	case 'C':	    addInterface(optarg, 1, 0);	    break;	case 'S':	    addInterface(optarg, 0, 1);	    break;	case 'B':	    addInterface(optarg, 1, 1);	    break;	case 'i':	    if (sscanf(optarg, "%u", &IdleTimeout) != 1) {		fprintf(stderr, "Illegal argument to -i: should be -i timeout\n");		exit(EXIT_FAILURE);	    }	    CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;	    if (CleanPeriod < MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;	    break;	case 'n':	    if (sscanf(optarg, "%d", &nsess) != 1) {		fprintf(stderr, "Illegal argument to -n: should be -n #sessions\n");		exit(EXIT_FAILURE);	    }	    if (nsess < 1 || nsess > 65534) {		fprintf(stderr, "Illegal argument to -n: must range from 1 to 65534\n");		exit(EXIT_FAILURE);	    }	    break;	default:	    usage(argv[0]);	}    }#ifdef USE_LINUX_PACKET#ifndef HAVE_STRUCT_SOCKADDR_LL    fprintf(stderr, "The PPPoE relay does not work on Linux 2.0 kernels.\n");    exit(EXIT_FAILURE);#endif#endif    /* Check that at least two interfaces were defined */    if (NumInterfaces < 2) {	fprintf(stderr, "%s: Must define at least two interfaces\n",		argv[0]);	exit(EXIT_FAILURE);    }    /* Make a pipe for the cleaner */    if (pipe(CleanPipe) < 0) {	fatalSys("pipe");    }    /* Set up alarm handler */    sa.sa_handler = alarmHandler;    sigemptyset(&sa.sa_mask);    sa.sa_flags = SA_RESTART;    if (sigaction(SIGALRM, &sa, NULL) < 0) {	fatalSys("sigaction");    }    /* Allocate memory for sessions, etc. */    initRelay(nsess);    /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */    if (beDaemon) {	int i;	i = fork();	if (i < 0) {	    fatalSys("fork");	} else if (i != 0) {	    /* parent */	    exit(0);	}	setsid();	signal(SIGHUP, SIG_IGN);	i = fork();	if (i < 0) {	    fatalSys("fork");	} else if (i != 0) {	    exit(0);	}	chdir("/");	closelog();	for (i=0; i<CLOSEFD; i++) {	    if (!keepDescriptor(i)) {		close(i);	    }	}	/* We nuked our syslog descriptor... */	openlog("pppoe-relay", LOG_PID, LOG_DAEMON);    }    /* Kick off SIGALRM if there is an idle timeout */    if (IdleTimeout) alarm(1);    /* Enter the relay loop */    relayLoop();    /* Shouldn't ever get here... */    return EXIT_FAILURE;}/***********************************************************************%FUNCTION: addInterface*%ARGUMENTS:* ifname -- interface name* clientOK -- true if this interface should relay PADI, PADR packets.* acOK -- true if this interface should relay PADO, PADS packets.*%RETURNS:* Nothing*%DESCRIPTION:* Opens an interface; sets up discovery and session sockets.***********************************************************************/voidaddInterface(char const *ifname,	     int clientOK,	     int acOK){    PPPoEInterface *i;    int j;    for (j=0; j<NumInterfaces; j++) {	if (!strncmp(Interfaces[j].name, ifname, IFNAMSIZ)) {	    fprintf(stderr, "Interface %s specified more than once.\n", ifname);	    exit(EXIT_FAILURE);	}    }    if (NumInterfaces >= MAX_INTERFACES) {	fprintf(stderr, "Too many interfaces (%d max)\n",		MAX_INTERFACES);	exit(EXIT_FAILURE);    }    i = &Interfaces[NumInterfaces++];    strncpy(i->name, ifname, IFNAMSIZ);    i->name[IFNAMSIZ] = 0;    i->discoverySock = openInterface(ifname, Eth_PPPOE_Discovery, i->mac);    i->sessionSock   = openInterface(ifname, Eth_PPPOE_Session,   NULL);    i->clientOK = clientOK;    i->acOK = acOK;}/***********************************************************************%FUNCTION: initRelay*%ARGUMENTS:* nsess -- maximum allowable number of sessions*%RETURNS:* Nothing*%DESCRIPTION:* Initializes relay hash table and session tables.***********************************************************************/voidinitRelay(int nsess){    int i;    NumSessions = 0;    MaxSessions = nsess;    AllSessions = calloc(MaxSessions, sizeof(PPPoESession));    if (!AllSessions) {	rp_fatal("Unable to allocate memory for PPPoE session table");    }    AllHashes = calloc(MaxSessions*2, sizeof(SessionHash));    if (!AllHashes) {	rp_fatal("Unable to allocate memory for PPPoE hash table");    }    /* Initialize sessions in a linked list */    AllSessions[0].prev = NULL;    if (MaxSessions > 1) {	AllSessions[0].next = &AllSessions[1];    } else {	AllSessions[0].next = NULL;    }    for (i=1; i<MaxSessions-1; i++) {	AllSessions[i].prev = &AllSessions[i-1];	AllSessions[i].next = &AllSessions[i+1];    }    if (MaxSessions > 1) {	AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2];	AllSessions[MaxSessions-1].next = NULL;    }    FreeSessions = AllSessions;    ActiveSessions = NULL;    /* Initialize session numbers which we hand out */    for (i=0; i<MaxSessions; i++) {	AllSessions[i].sesNum = htons((UINT16_t) i+1);    }    /* Initialize hashes in a linked list */    AllHashes[0].prev = NULL;    AllHashes[0].next = &AllHashes[1];    for (i=1; i<2*MaxSessions-1; i++) {	AllHashes[i].prev = &AllHashes[i-1];	AllHashes[i].next = &AllHashes[i+1];    }    AllHashes[2*MaxSessions-1].prev = &AllHashes[2*MaxSessions-2];    AllHashes[2*MaxSessions-1].next = NULL;    FreeHashes = AllHashes;}/***********************************************************************%FUNCTION: createSession*%ARGUMENTS:* ac -- Ethernet interface on access-concentrator side* cli -- Ethernet interface on client side* acMac -- Access concentrator's MAC address* cliMac -- Client's MAC address* acSess -- Access concentrator's session ID.*%RETURNS:* PPPoESession structure; NULL if one could not be allocated*%DESCRIPTION:* Initializes relay hash table and session tables.***********************************************************************/PPPoESession *createSession(PPPoEInterface const *ac,	      PPPoEInterface const *cli,	      unsigned char const *acMac,	      unsigned char const *cliMac,	      UINT16_t acSes){    PPPoESession *sess;    SessionHash *acHash, *cliHash;    if (NumSessions >= MaxSessions) {	printErr("Maximum number of sessions reached -- cannot create new session");	return NULL;    }    /* Grab a free session */    sess = FreeSessions;    FreeSessions = sess->next;    NumSessions++;    /* Link it to the active list */    sess->next = ActiveSessions;    if (sess->next) {	sess->next->prev = sess;    }    ActiveSessions = sess;    sess->prev = NULL;    sess->epoch = Epoch;    /* Get two hash entries */    acHash = FreeHashes;    cliHash = acHash->next;    FreeHashes = cliHash->next;    acHash->peer = cliHash;    cliHash->peer = acHash;    sess->acHash = acHash;    sess->clientHash = cliHash;    acHash->interface = ac;    cliHash->interface = cli;    memcpy(acHash->peerMac, acMac, ETH_ALEN);    acHash->sesNum = acSes;    acHash->ses = sess;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -