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

📄 pppoe.c

📁 基于LINUX环境下的PPPOE协议源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************************* pppoe.c ** Implementation of user-space PPPoE redirector for Linux.** Copyright (C) 2000-2001 by 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.************************************************************************/static char const RCSID[] ="$Id: pppoe.c,v 1.1 2002/03/15 23:37:31 m4 Exp $";#include <features.h>#include "pppoe.h"#include <stdlib.h>#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#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#ifdef USE_LINUX_PACKET#include <sys/ioctl.h>#include <fcntl.h>#endif#include <signal.h>#ifdef HAVE_N_HDLC#ifndef N_HDLC#include <linux/termios.h>#endif#endif/* Default interface if no -I option given */#define DEFAULT_IF "eth0"/* Global variables -- options */int optInactivityTimeout = 0;	/* Inactivity timeout */int optClampMSS          = 0;	/* Clamp MSS to this value */int optSkipSession       = 0;	/* Perform discovery, print session info				   and exit */int optFloodDiscovery    = 0;   /* Flood server with discovery requests.				   USED FOR STRESS-TESTING ONLY.  DO NOT				   USE THE -F OPTION AGAINST A REAL ISP */PPPoEConnection *Connection = NULL; /* Must be global -- used				       in signal handler *//************************************************************************%FUNCTION: sendSessionPacket*%ARGUMENTS:* conn -- PPPoE connection* packet -- the packet to send* len -- length of data to send*%RETURNS:* Nothing*%DESCRIPTION:* Transmits a session packet to the peer.***********************************************************************/voidsendSessionPacket(PPPoEConnection *conn, PPPoEPacket *packet, int len){    packet->length = htons(len);    if (optClampMSS) {	clampMSS(packet, "outgoing", optClampMSS);    }    if (sendPacket(conn, conn->sessionSocket, packet, len + HDR_SIZE) < 0) {	exit(EXIT_FAILURE);    }    if (conn->debugFile) {	dumpPacket(conn->debugFile, packet, "SENT");	fprintf(conn->debugFile, "\n");	fflush(conn->debugFile);    }}#ifdef USE_BPF/***********************************************************************%FUNCTION: sessionDiscoveryPacket*%ARGUMENTS:* packet -- the discovery packet that was received*%RETURNS:* Nothing*%DESCRIPTION:* We got a discovery packet during the session stage.  This most likely* means a PADT.** The BSD version uses a single socket for both discovery and session* packets.  When a packet comes in over the wire once we are in* session mode, either syncReadFromEth() or asyncReadFromEth() will* have already read the packet and determined it to be a discovery* packet before passing it here.***********************************************************************/voidsessionDiscoveryPacket(PPPoEPacket *packet){    /* Sanity check */    if (packet->code != CODE_PADT) {	return;    }    /* It's a PADT, all right.  Is it for us? */    if (packet->session != Connection->session) {	/* Nope, ignore it */	return;    }    if (memcmp(packet->ethHdr.h_dest, Connection->myEth, ETH_ALEN)) {	return;    }    if (memcmp(packet->ethHdr.h_source, Connection->peerEth, ETH_ALEN)) {	return;    }    syslog(LOG_INFO,	   "Session terminated -- received PADT from peer");    parsePacket(packet, parseLogErrs, NULL);    exit(EXIT_SUCCESS);}#else/***********************************************************************%FUNCTION: sessionDiscoveryPacket*%ARGUMENTS:* conn -- PPPoE connection*%RETURNS:* Nothing*%DESCRIPTION:* We got a discovery packet during the session stage.  This most likely* means a PADT.***********************************************************************/voidsessionDiscoveryPacket(PPPoEConnection *conn){    PPPoEPacket packet;    int len;    if (receivePacket(conn->discoverySocket, &packet, &len) < 0) {	return;    }    /* Check length */    if (ntohs(packet.length) + HDR_SIZE > len) {	syslog(LOG_ERR, "Bogus PPPoE length field (%u)",	       (unsigned int) ntohs(packet.length));	return;    }    if (packet.code != CODE_PADT) {	/* Not PADT; ignore it */	return;    }    /* It's a PADT, all right.  Is it for us? */    if (packet.session != conn->session) {	/* Nope, ignore it */	return;    }    if (memcmp(packet.ethHdr.h_dest, conn->myEth, ETH_ALEN)) {	return;    }    if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) {	return;    }    if (conn->debugFile) {	dumpPacket(conn->debugFile, &packet, "RCVD");	fprintf(conn->debugFile, "\n");	fflush(conn->debugFile);    }    syslog(LOG_INFO,	   "Session terminated -- received PADT from peer");    parsePacket(&packet, parseLogErrs, NULL);    exit(EXIT_SUCCESS);}#endif /* USE_BPF *//***********************************************************************%FUNCTION: session*%ARGUMENTS:* conn -- PPPoE connection info*%RETURNS:* Nothing*%DESCRIPTION:* Handles the "session" phase of PPPoE***********************************************************************/voidsession(PPPoEConnection *conn){    fd_set readable;    PPPoEPacket packet;    struct timeval tv;    struct timeval *tvp = NULL;    int maxFD = 0;    int r;    /* Open a session socket */    conn->sessionSocket = openInterface(conn->ifName, Eth_PPPOE_Session, conn->myEth);    /* Prepare for select() */    if (conn->sessionSocket > maxFD)   maxFD = conn->sessionSocket;    if (conn->discoverySocket > maxFD) maxFD = conn->discoverySocket;    maxFD++;    /* Fill in the constant fields of the packet to save time */    memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);    packet.ethHdr.h_proto = htons(Eth_PPPOE_Session);    packet.ver = 1;    packet.type = 1;    packet.code = CODE_SESS;    packet.session = conn->session;    initPPP();#ifdef USE_BPF    /* check for buffered session data */    while (BPF_BUFFER_HAS_DATA) {	if (conn->synchronous) {	    syncReadFromEth(conn, conn->sessionSocket, optClampMSS);	} else {	    asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);	}    }#endif    for (;;) {	if (optInactivityTimeout > 0) {	    tv.tv_sec = optInactivityTimeout;	    tv.tv_usec = 0;	    tvp = &tv;	}	FD_ZERO(&readable);	FD_SET(0, &readable);     /* ppp packets come from stdin */	if (conn->discoverySocket >= 0) {	    FD_SET(conn->discoverySocket, &readable);	}	FD_SET(conn->sessionSocket, &readable);	while(1) {	    r = select(maxFD, &readable, NULL, NULL, tvp);	    if (r >= 0 || errno != EINTR) break;	}	if (r < 0) {	    fatalSys("select (session)");	}	if (r == 0) { /* Inactivity timeout */	    syslog(LOG_ERR, "Inactivity timeout... something wicked happened");	    sendPADT(conn, "RP-PPPoE: Inactivity timeout");	    exit(EXIT_FAILURE);	}	/* Handle ready sockets */	if (FD_ISSET(0, &readable)) {	    if (conn->synchronous) {		syncReadFromPPP(conn, &packet);	    } else {		asyncReadFromPPP(conn, &packet);	    }	}	if (FD_ISSET(conn->sessionSocket, &readable)) {	    do {		if (conn->synchronous) {		    syncReadFromEth(conn, conn->sessionSocket, optClampMSS);		} else {		    asyncReadFromEth(conn, conn->sessionSocket, optClampMSS);		}	    } while (BPF_BUFFER_HAS_DATA);	}#ifndef USE_BPF		/* BSD uses a single socket, see *syncReadFromEth() */	/* for calls to sessionDiscoveryPacket() */	if (conn->discoverySocket >= 0) {	    if (FD_ISSET(conn->discoverySocket, &readable)) {		sessionDiscoveryPacket(conn);	    }	}#endif    }}/************************************************************************%FUNCTION: sigPADT*%ARGUMENTS:* src -- signal received*%RETURNS:* Nothing*%DESCRIPTION:* If an established session exists send PADT to terminate from session*  from our end***********************************************************************/voidsigPADT(int src){  syslog(LOG_DEBUG,"Received signal %d.",(int)src);  sendPADT(Connection, "RP-PPPoE: Received signal");  exit(EXIT_SUCCESS);}/***********************************************************************%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");#ifdef USE_BPF    fprintf(stderr, "   -I if_name     -- Specify interface (REQUIRED)\n");#else    fprintf(stderr, "   -I if_name     -- Specify interface (default %s).\n",	    DEFAULT_IF);#endif    fprintf(stderr, "   -T timeout     -- Specify inactivity timeout in seconds.\n");    fprintf(stderr, "   -D filename    -- Log debugging information in filename.\n");    fprintf(stderr, "   -V             -- Print version and exit.\n");    fprintf(stderr, "   -A             -- Print access concentrator names and exit.\n");    fprintf(stderr, "   -S name        -- Set desired service name.\n");    fprintf(stderr, "   -C name        -- Set desired access concentrator name.\n");    fprintf(stderr, "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n");    fprintf(stderr, "   -s             -- Use synchronous PPP encapsulation.\n");    fprintf(stderr, "   -m MSS         -- Clamp incoming and outgoing MSS options.\n");    fprintf(stderr, "   -p pidfile     -- Write process-ID to pidfile.\n");    fprintf(stderr, "   -e sess:mac    -- Skip discovery phase; use existing session.\n");    fprintf(stderr, "   -n             -- Do not open discovery socket.\n");    fprintf(stderr, "   -k             -- Kill a session with PADT (requires -e)\n");    fprintf(stderr, "   -d             -- Perform discovery, print session info and exit.\n");    fprintf(stderr, "   -f disc:sess   -- Set Ethernet frame types (hex).\n");    fprintf(stderr, "   -h             -- Print usage information.\n\n");    fprintf(stderr, "PPPoE Version %s, Copyright (C) 2001 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 -- count and values of command-line arguments*%RETURNS:* Nothing*%DESCRIPTION:* Main program***********************************************************************/intmain(int argc, char *argv[]){    int opt;    int n;    unsigned int m[6];		/* MAC address in -e option */    unsigned int s;		/* Temporary to hold session */    FILE *pidfile;    unsigned int discoveryType, sessionType;    PPPoEConnection conn;#ifdef HAVE_N_HDLC    int disc = N_HDLC;    long flags;#endif    /* Initialize connection info */    memset(&conn, 0, sizeof(conn));    conn.discoverySocket = -1;    conn.sessionSocket = -1;    /* For signal handler */    Connection = &conn;#ifdef	MACDUX    /* Initialize syslog */    openlog("pppoe", LOG_PID, LOG_DAEMON);#endif    while((opt = getopt(argc, argv, "I:VAT:D:hS:C:Usm:np:e:kdf:F:")) != -1) {	switch(opt) {	case 'F':	    if (sscanf(optarg, "%d", &optFloodDiscovery) != 1) {		fprintf(stderr, "Illegal argument to -F: Should be -F numFloods\n");		exit(EXIT_FAILURE);	    }	    if (optFloodDiscovery < 1) optFloodDiscovery = 1;	    fprintf(stderr, "WARNING: DISCOVERY FLOOD IS MEANT FOR STRESS-TESTING\n");	    fprintf(stderr, "A PPPOE SERVER WHICH YOU OWN.  DO NOT USE IT AGAINST\n");	    fprintf(stderr, "A REAL ISP.  YOU HAVE 5 SECONDS TO ABORT.\n");	    sleep(5);	    break;	case 'f':	    if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {		fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");		exit(EXIT_FAILURE);	    }	    Eth_PPPOE_Discovery = (UINT16_t) discoveryType;	    Eth_PPPOE_Session   = (UINT16_t) sessionType;	    break;	case 'd':	    optSkipSession = 1;	    break;	case 'k':	    conn.killSession = 1;	    break;	case 'n':	    /* Do not even open a discovery socket -- used when invoked 	       by pppoe-server */	    conn.noDiscoverySocket = 1;	    break;	case 'e':

⌨️ 快捷键说明

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