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

📄 pppoe-server.c

📁 网上的一个开源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/***********************************************************************%FUNCTION: genCookie*%ARGUMENTS:* peerEthAddr -- peer Ethernet address (6 bytes)* myEthAddr -- my Ethernet address (6 bytes)* seed -- random cookie seed to make things tasty (16 bytes)* cookie -- buffer which is filled with server PID and*           md5 sum of previous items*%RETURNS:* Nothing*%DESCRIPTION:* Forms the md5 sum of peer MAC address, our MAC address and seed, useful* in a PPPoE Cookie tag.***********************************************************************/voidgenCookie(unsigned char const *peerEthAddr,	  unsigned char const *myEthAddr,	  unsigned char const *seed,	  unsigned char *cookie){    struct MD5Context ctx;    pid_t pid = getpid();    MD5Init(&ctx);    MD5Update(&ctx, peerEthAddr, ETH_ALEN);    MD5Update(&ctx, myEthAddr, ETH_ALEN);    MD5Update(&ctx, seed, SEED_LEN);    MD5Final(cookie, &ctx);    memcpy(cookie+MD5_LEN, &pid, sizeof(pid));}/***********************************************************************%FUNCTION: processPADI*%ARGUMENTS:* ethif -- Interface* packet -- PPPoE PADI packet* len -- length of received packet*%RETURNS:* Nothing*%DESCRIPTION:* Sends a PADO packet back to client***********************************************************************/voidprocessPADI(Interface *ethif, PPPoEPacket *packet, int len){    PPPoEPacket pado;    PPPoETag acname;    PPPoETag servname;    PPPoETag cookie;    size_t acname_len;    unsigned char *cursor = pado.payload;    UINT16_t plen;    int sock = ethif->sock;    int i;    int ok = 0;    unsigned char *myAddr = ethif->mac;    /* Ignore PADI's which don't come from a unicast address */    if (NOT_UNICAST(packet->ethHdr.h_source)) {	syslog(LOG_ERR, "PADI packet from non-unicast source address");	return;    }    acname.type = htons(TAG_AC_NAME);    acname_len = strlen(ACName);    acname.length = htons(acname_len);    memcpy(acname.payload, ACName, acname_len);    relayId.type = 0;    hostUniq.type = 0;    requestedService.type = 0;    parsePacket(packet, parsePADITags, NULL);    /* If PADI specified non-default service name, and we do not offer       that service, DO NOT send PADO */    if (requestedService.type) {	int slen = ntohs(requestedService.length);	if (slen) {	    for (i=0; i<NumServiceNames; i++) {		if (slen == strlen(ServiceNames[i]) &&		    !memcmp(ServiceNames[i], &requestedService.payload, slen)) {		    ok = 1;		    break;		}	    }	} else {	    ok = 1;		/* Default service requested */	}    } else {	ok = 1;			/* No Service-Name tag in PADI */    }    if (!ok) {	/* PADI asked for unsupported service */	return;    }    /* Generate a cookie */    cookie.type = htons(TAG_AC_COOKIE);    cookie.length = htons(COOKIE_LEN);    genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);    /* Construct a PADO packet */    memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);    memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);    pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);    pado.ver = 1;    pado.type = 1;    pado.code = CODE_PADO;    pado.session = 0;    plen = TAG_HDR_SIZE + acname_len;    CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);    memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE);    cursor += acname_len + TAG_HDR_SIZE;    /* If no service-names specified on command-line, just send default       zero-length name.  Otherwise, add all service-name tags */    servname.type = htons(TAG_SERVICE_NAME);    if (!NumServiceNames) {	servname.length = 0;	CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);	memcpy(cursor, &servname, TAG_HDR_SIZE);	cursor += TAG_HDR_SIZE;	plen += TAG_HDR_SIZE;    } else {	for (i=0; i<NumServiceNames; i++) {	    int slen = strlen(ServiceNames[i]);	    servname.length = htons(slen);	    CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE+slen);	    memcpy(cursor, &servname, TAG_HDR_SIZE);	    memcpy(cursor+TAG_HDR_SIZE, ServiceNames[i], slen);	    cursor += TAG_HDR_SIZE+slen;	    plen += TAG_HDR_SIZE+slen;	}    }    CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);    memcpy(cursor, &cookie, TAG_HDR_SIZE + COOKIE_LEN);    cursor += TAG_HDR_SIZE + COOKIE_LEN;    plen += TAG_HDR_SIZE + COOKIE_LEN;    if (relayId.type) {	CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);	memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);	cursor += ntohs(relayId.length) + TAG_HDR_SIZE;	plen += ntohs(relayId.length) + TAG_HDR_SIZE;    }    if (hostUniq.type) {	CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);	memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);	cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;	plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;    }    pado.length = htons(plen);    sendPacket(NULL, sock, &pado, (int) (plen + HDR_SIZE));}/***********************************************************************%FUNCTION: processPADT*%ARGUMENTS:* ethif -- interface* packet -- PPPoE PADT packet* len -- length of received packet*%RETURNS:* Nothing*%DESCRIPTION:* Kills session whose session-ID is in PADT packet.***********************************************************************/voidprocessPADT(Interface *ethif, PPPoEPacket *packet, int len){    size_t i;    unsigned char *myAddr = ethif->mac;    /* Ignore PADT's not directed at us */    if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;    /* Get session's index */    i = ntohs(packet->session) - 1 - SessOffset;    if (i >= NumSessionSlots) return;    if (Sessions[i].sess != packet->session) {	syslog(LOG_ERR, "Session index %u doesn't match session number %u",	       (unsigned int) i, (unsigned int) ntohs(packet->session));	return;    }    /* If source MAC does not match, do not kill session */    if (memcmp(packet->ethHdr.h_source, Sessions[i].eth, ETH_ALEN)) {	syslog(LOG_WARNING, "PADT for session %u received from "	       "%02X:%02X:%02X:%02X:%02X:%02X; should be from "	       "%02X:%02X:%02X:%02X:%02X:%02X",	       (unsigned int) ntohs(packet->session),	       packet->ethHdr.h_source[0],	       packet->ethHdr.h_source[1],	       packet->ethHdr.h_source[2],	       packet->ethHdr.h_source[3],	       packet->ethHdr.h_source[4],	       packet->ethHdr.h_source[5],	       Sessions[i].eth[0],	       Sessions[i].eth[1],	       Sessions[i].eth[2],	       Sessions[i].eth[3],	       Sessions[i].eth[4],	       Sessions[i].eth[5]);	return;    }    Sessions[i].flags |= FLAG_RECVD_PADT;    parsePacket(packet, parseLogErrs, NULL);    Sessions[i].funcs->stop(&Sessions[i], "Received PADT");}/***********************************************************************%FUNCTION: processPADR*%ARGUMENTS:* ethif -- Ethernet interface* packet -- PPPoE PADR packet* len -- length of received packet*%RETURNS:* Nothing*%DESCRIPTION:* Sends a PADS packet back to client and starts a PPP session if PADR* packet is OK.***********************************************************************/voidprocessPADR(Interface *ethif, PPPoEPacket *packet, int len){    unsigned char cookieBuffer[COOKIE_LEN];    ClientSession *cliSession;    pid_t child;    PPPoEPacket pads;    unsigned char *cursor = pads.payload;    UINT16_t plen;    int i;    int sock = ethif->sock;    unsigned char *myAddr = ethif->mac;    int slen = 0;    char const *serviceName = NULL;#ifdef HAVE_LICENSE    int freemem;#endif    /* Initialize some globals */    relayId.type = 0;    hostUniq.type = 0;    receivedCookie.type = 0;    requestedService.type = 0;    /* Ignore PADR's not directed at us */    if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;    /* Ignore PADR's from non-unicast addresses */    if (NOT_UNICAST(packet->ethHdr.h_source)) {	syslog(LOG_ERR, "PADR packet from non-unicast source address");	return;    }    parsePacket(packet, parsePADRTags, NULL);    /* Check that everything's cool */    if (!receivedCookie.type) {	/* Drop it -- do not send error PADS */	return;    }    /* Is cookie kosher? */    if (receivedCookie.length != htons(COOKIE_LEN)) {	/* Drop it -- do not send error PADS */	return;    }    genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);    if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {	/* Drop it -- do not send error PADS */	return;    }    /* Check service name */    if (!requestedService.type) {	syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,		      TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");	return;    }    slen = ntohs(requestedService.length);    if (slen) {	/* Check supported services */	for(i=0; i<NumServiceNames; i++) {	    if (slen == strlen(ServiceNames[i]) &&		!memcmp(ServiceNames[i], &requestedService.payload, slen)) {		serviceName = ServiceNames[i];		break;	    }	}	if (!serviceName) {	    syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);	    sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,			  TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");	    return;	}    } else {	serviceName = "";    }#ifdef HAVE_LICENSE    /* Are we licensed for this many sessions? */    if (License_NumLicenses("PPPOE-SESSIONS") <= NumActiveSessions) {	syslog(LOG_ERR, "Insufficient session licenses (%02x:%02x:%02x:%02x:%02x:%02x)",	       (unsigned int) packet->ethHdr.h_source[0],	       (unsigned int) packet->ethHdr.h_source[1],	       (unsigned int) packet->ethHdr.h_source[2],	       (unsigned int) packet->ethHdr.h_source[3],	       (unsigned int) packet->ethHdr.h_source[4],	       (unsigned int) packet->ethHdr.h_source[5]);	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No session licenses available");	return;    }#endif    /* Enough free memory? */#ifdef HAVE_LICENSE    freemem = getFreeMem();    if (freemem < MIN_FREE_MEMORY) {	syslog(LOG_WARNING,	       "Insufficient free memory to create session: Want %d, have %d",	       MIN_FREE_MEMORY, freemem);	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Insufficient free RAM");	return;    }#endif    /* Looks cool... find a slot for the session */    cliSession = pppoe_alloc_session();    if (!cliSession) {	syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",	       (unsigned int) packet->ethHdr.h_source[0],	       (unsigned int) packet->ethHdr.h_source[1],	       (unsigned int) packet->ethHdr.h_source[2],	       (unsigned int) packet->ethHdr.h_source[3],	       (unsigned int) packet->ethHdr.h_source[4],	       (unsigned int) packet->ethHdr.h_source[5]);	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");	return;    }    /* Set up client session peer Ethernet address */    memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);    cliSession->ethif = ethif;    cliSession->flags = 0;    cliSession->funcs = &DefaultSessionFunctionTable;    cliSession->startTime = time(NULL);    cliSession->serviceName = serviceName;    /* Create child process, send PADS packet back */    child = fork();    if (child < 0) {	sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,		      TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");	pppoe_free_session(cliSession);	return;    }    if (child != 0) {	/* In the parent process.  Mark pid in session slot */	cliSession->pid = child;	Event_HandleChildExit(event_selector, child,			      childHandler, cliSession);	control_session_started(cliSession);	return;    }    /* In the child process.  */    /* Close all file descriptors except for socket */    closelog();    for (i=0; i<CLOSEFD; i++) {	if (i != sock) {	    close(i);	}    }    openlog("pppoe-server", LOG_PID, LOG_DAEMON);    /* pppd has a nasty habit of killing all processes in its process group.       Start a new session to stop pppd from killing us! */    setsid();    /* Send PADS and Start pppd */    memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);    memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);    pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);    pads.ver = 1;    pads.type = 1;    pads.code = CODE_PADS;    pads.session = cliSession->sess;    plen = 0;    /* Copy requested service name tag back in.  If requested-service name       length is zero, and we have non-zero services, use first service-name       as default */    if (!slen && NumServiceNames) {	slen = strlen(ServiceNames[0]);	memcpy(&requestedService.payload, ServiceNames[0], slen);	requestedService.length = htons(slen);    }    memcpy(cursor, &requestedService, TAG_HDR_SIZE+slen);    cursor += TAG_HDR_SIZE+slen;    plen += TAG_HDR_SIZE+slen;    if (relayId.type) {	memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);	cursor += ntohs(relayId.length) + TAG_HDR_SIZE;	plen += ntohs(relayId.length) + TAG_HDR_SIZE;    }    if (hostUniq.type) {	memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);	cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;	plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;    }    pads.length = htons(plen);    sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));    /* Close sock; don't need it any more */    close(sock);    startPPPD(cliSession);}/***********************************************************************%FUNCTION: termHandler*%ARGUMENTS:* sig -- signal number*%RETURNS:* Nothing*%DESCRIPTION:* Called by SIGTERM or SIGINT.  Causes all sessions to be killed!***********************************************************************/static voidtermHandler(int sig){    syslog(LOG_INFO,	   "Terminating on signal %d -- killing all PPPoE sessions",	   sig);    killAllSessions();    control_exit();    exit(0);}/***********************************************************************%FUNCTION: usage*%ARGUMENTS:* argv0 -- argv[0] from main*%RETURNS:* Nothing*%DESCRIPTION:* Prints usage instructions***********************************************************************/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, "   -C name        -- Set access concentrator name.\n");    fprintf(stderr, "   -m MSS         -- Clamp incoming and outgoing MSS options.\n");    fprintf(stderr, "   -L ip          -- Set local IP address.\n");    fprintf(stderr, "   -l             -- Increment local IP address for each session.\n");    fprintf(stderr, "   -R ip          -- Set start address of remote IP pool.\n");    fprintf(stderr, "   -S name        -- Advertise specified service-name.\n");    fprintf(stderr, "   -p fname       -- Optain IP address pool from specified file.\n");    fprintf(stderr, "   -N num         -- Allow 'num' concurrent sessions.\n");    fprintf(stderr, "   -o offset      -- Assign session numbers starting at offset+1.\n");    fprintf(stderr, "   -f disc:sess   -- Set Ethernet frame types (hex).\n");    fprintf(stderr, "   -s             -- Use synchronous PPP mode.\n");#ifdef HAVE_LINUX_KERNEL_PPPOE    fprintf(stderr, "   -k             -- Use kernel-mode PPPoE.\n");#endif    fprintf(stderr, "   -u             -- Pass 'unit' option to pppd.\n");    fprintf(stderr, "   -r             -- Randomize session numbers.\n");    fprintf(stderr, "   -d             -- Debug session creation.\n");    fprintf(stderr, "   -P             -- Check pool file for correctness and exit.\n");#ifdef HAVE_LICENSE    fprintf(stderr, "   -c secret:if:port -- Enable clustering on interface 'if'.\n");    fprintf(stderr, "   -1             -- Allow only one session per user.\n");#endif    fprintf(stderr, "   -h             -- Print usage information.\n\n");    fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001-2005 Roaring Penguin Software Inc.\n", VERSION);#ifndef HAVE_LICENSE    fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");    fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");    fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");    fprintf(stderr, "or (at your option) any later version.\n");#endif    fprintf(stderr, "http://www.roaringpenguin.com\n");}/***********************************************************************%FUNCTION: main*%ARGUMENTS:

⌨️ 快捷键说明

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