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

📄 pppoe-server.c

📁 PPPoE在Linux上的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Syslog an error */
	break;
    }
}

/**********************************************************************
*%FUNCTION: sendErrorPADS
*%ARGUMENTS:
* sock -- socket to write to
* source -- source Ethernet address
* dest -- destination Ethernet address
* errorTag -- error tag
* errorMsg -- error message
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Sends a PADS packet with an error message
***********************************************************************/
void
sendErrorPADS(int sock,
	      unsigned char *source,
	      unsigned char *dest,
	      int errorTag,
	      char *errorMsg)
{
    PPPoEPacket pads;
    unsigned char *cursor = pads.payload;
    UINT16_t plen;
    PPPoETag err;
    int elen = strlen(errorMsg);

    memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
    memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
    pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
    pads.ver = 1;
    pads.type = 1;
    pads.code = CODE_PADS;

    pads.session = htons(0);
    plen = 0;

    err.type = htons(errorTag);
    err.length = htons(elen);

    memcpy(err.payload, errorMsg, elen);
    memcpy(cursor, &err, TAG_HDR_SIZE+elen);
    cursor += TAG_HDR_SIZE + elen;
    plen += TAG_HDR_SIZE + elen;

    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));
}


/**********************************************************************
*%FUNCTION: startPPPDUserMode
*%ARGUMENTS:
* session -- client session record
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Starts PPPD for user-mode PPPoE
***********************************************************************/
void
startPPPDUserMode(ClientSession *session)
{
    /* Leave some room */
    char *argv[32];

    char buffer[SMALLBUF];

    int c = 0;

    argv[c++] = "pppd";
    argv[c++] = "pty";

    /* Let's hope service-name does not have ' in it... */
    snprintf(buffer, SMALLBUF, "%s -n -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s -S '%s'",
	     PPPOE_PATH, session->ethif->name,
	     ntohs(session->sess),
	     session->eth[0], session->eth[1], session->eth[2],
	     session->eth[3], session->eth[4], session->eth[5],
	     session->serviceName,
	     PppoeOptions);
    argv[c++] = strdup(buffer);
    if (!argv[c-1]) {
	/* TODO: Send a PADT */
	exit(EXIT_FAILURE);
    }

    argv[c++] = "file";
    argv[c++] = PPPOE_SERVER_OPTIONS;

    snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
	    (int) session->myip[0], (int) session->myip[1],
	    (int) session->myip[2], (int) session->myip[3],
	    (int) session->peerip[0], (int) session->peerip[1],
	    (int) session->peerip[2], (int) session->peerip[3]);
    syslog(LOG_INFO,
	   "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
	   ntohs(session->sess),
	   session->eth[0], session->eth[1], session->eth[2],
	   session->eth[3], session->eth[4], session->eth[5],
	   (int) session->peerip[0], (int) session->peerip[1],
	   (int) session->peerip[2], (int) session->peerip[3],
	   session->ethif->name,
	   session->serviceName);
    argv[c++] = strdup(buffer);
    if (!argv[c-1]) {
	/* TODO: Send a PADT */
	exit(EXIT_FAILURE);
    }
    argv[c++] = "nodetach";
    argv[c++] = "noaccomp";
    argv[c++] = "nobsdcomp";
    argv[c++] = "nodeflate";
    argv[c++] = "nopcomp";
    argv[c++] = "novj";
    argv[c++] = "novjccomp";
    argv[c++] = "default-asyncmap";
    if (Synchronous) {
	argv[c++] = "sync";
    }
    if (PassUnitOptionToPPPD) {
	argv[c++] = "unit";
	sprintf(buffer, "%d", ntohs(session->sess) - 1 - SessOffset);
	argv[c++] = buffer;
    }
    argv[c++] = NULL;

    execv(PPPD_PATH, argv);
    exit(EXIT_FAILURE);
}

/**********************************************************************
*%FUNCTION: startPPPDLinuxKernelMode
*%ARGUMENTS:
* session -- client session record
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Starts PPPD for kernel-mode PPPoE on Linux
***********************************************************************/
void
startPPPDLinuxKernelMode(ClientSession *session)
{
    /* Leave some room */
    char *argv[32];

    int c = 0;

    char buffer[SMALLBUF];

    argv[c++] = "pppd";
    argv[c++] = "plugin";
    argv[c++] = PLUGIN_PATH;
    argv[c++] = session->ethif->name;
    snprintf(buffer, SMALLBUF, "%d:%02x:%02x:%02x:%02x:%02x:%02x",
	     ntohs(session->sess),
	     session->eth[0], session->eth[1], session->eth[2],
	     session->eth[3], session->eth[4], session->eth[5]);
    argv[c++] = "rp_pppoe_sess";
    argv[c++] = strdup(buffer);
    if (!argv[c-1]) {
	/* TODO: Send a PADT */
	exit(EXIT_FAILURE);
    }
    argv[c++] = "rp_pppoe_service";
    argv[c++] = (char *) session->serviceName;
    argv[c++] = "file";
    argv[c++] = PPPOE_SERVER_OPTIONS;

    snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
	    (int) session->myip[0], (int) session->myip[1],
	    (int) session->myip[2], (int) session->myip[3],
	    (int) session->peerip[0], (int) session->peerip[1],
	    (int) session->peerip[2], (int) session->peerip[3]);
    syslog(LOG_INFO,
	   "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
	   ntohs(session->sess),
	   session->eth[0], session->eth[1], session->eth[2],
	   session->eth[3], session->eth[4], session->eth[5],
	   (int) session->peerip[0], (int) session->peerip[1],
	   (int) session->peerip[2], (int) session->peerip[3],
	   session->ethif->name,
	   session->serviceName);
    argv[c++] = strdup(buffer);
    if (!argv[c-1]) {
	/* TODO: Send a PADT */
	exit(EXIT_FAILURE);
    }
    argv[c++] = "nodetach";
    argv[c++] = "noaccomp";
    argv[c++] = "nobsdcomp";
    argv[c++] = "nodeflate";
    argv[c++] = "nopcomp";
    argv[c++] = "novj";
    argv[c++] = "novjccomp";
    argv[c++] = "default-asyncmap";
    if (PassUnitOptionToPPPD) {
	argv[c++] = "unit";
	sprintf(buffer, "%d", ntohs(session->sess) - 1 - SessOffset);
	argv[c++] = buffer;
    }
    argv[c++] = NULL;
    execv(PPPD_PATH, argv);
    exit(EXIT_FAILURE);
}

/**********************************************************************
*%FUNCTION: startPPPD
*%ARGUMENTS:
* session -- client session record
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Starts PPPD
***********************************************************************/
void
startPPPD(ClientSession *session)
{
    if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
    else startPPPDUserMode(session);
}

/**********************************************************************
* %FUNCTION: InterfaceHandler
* %ARGUMENTS:
*  es -- event selector (ignored)
*  fd -- file descriptor which is readable
*  flags -- ignored
*  data -- Pointer to the Interface structure
* %RETURNS:
*  Nothing
* %DESCRIPTION:
*  Handles a packet ready at an interface
***********************************************************************/
void
InterfaceHandler(EventSelector *es,
		 int fd,
		 unsigned int flags,
		 void *data)
{
    serverProcessPacket((Interface *) data);
}

/**********************************************************************
* %FUNCTION: PppoeStopSession
* %ARGUMENTS:
*  ses -- the session
*  reason -- reason session is being stopped.
* %RETURNS:
*  Nothing
* %DESCRIPTION:
*  Kills pppd.
***********************************************************************/
static void
PppoeStopSession(ClientSession *ses,
		 char const *reason)
{
    /* Temporary structure for sending PADT's. */
    PPPoEConnection conn;

    memset(&conn, 0, sizeof(conn));
    conn.useHostUniq = 0;

    memcpy(conn.myEth, ses->ethif->mac, ETH_ALEN);
    conn.discoverySocket = ses->ethif->sock;
    conn.session = ses->sess;
    memcpy(conn.peerEth, ses->eth, ETH_ALEN);
    sendPADT(&conn, reason);
    ses->flags |= FLAG_SENT_PADT;

    if (ses->pid) {
	kill(ses->pid, SIGTERM);
    }
    ses->funcs = &DefaultSessionFunctionTable;
}

/**********************************************************************
* %FUNCTION: PppoeSessionIsActive
* %ARGUMENTS:
*  ses -- the session
* %RETURNS:
*  True if session is active, false if not.
***********************************************************************/
static int
PppoeSessionIsActive(ClientSession *ses)
{
    return (ses->pid != 0);
}

#ifdef HAVE_LICENSE
/**********************************************************************
* %FUNCTION: getFreeMem
* %ARGUMENTS:
*  None
* %RETURNS:
*  The amount of free RAM in kilobytes, or -1 if it could not be
*  determined
* %DESCRIPTION:
*  Reads Linux-specific /proc/meminfo file and extracts free RAM
***********************************************************************/
int
getFreeMem(void)
{
    char buf[512];
    int memfree=0, buffers=0, cached=0;
    FILE *fp = fopen("/proc/meminfo", "r");
    if (!fp) return -1;

    while (fgets(buf, sizeof(buf), fp)) {
	if (!strncmp(buf, "MemFree:", 8)) {
	    if (sscanf(buf, "MemFree: %d", &memfree) != 1) {
		fclose(fp);
		return -1;
	    }
	} else if (!strncmp(buf, "Buffers:", 8)) {
	    if (sscanf(buf, "Buffers: %d", &buffers) != 1) {
		fclose(fp);
		return -1;
	    }
	} else if (!strncmp(buf, "Cached:", 7)) {
	    if (sscanf(buf, "Cached: %d", &cached) != 1) {
		fclose(fp);
		return -1;
	    }
	}
    }
    fclose(fp);
    /* return memfree + buffers + cached; */
    return memfree;
}
#endif

/**********************************************************************
* %FUNCTION: pppoe_alloc_session
* %ARGUMENTS:
*  None
* %RETURNS:
*  NULL if no session is available, otherwise a ClientSession structure.
* %DESCRIPTION:
*  Allocates a ClientSession structure and removes from free list, puts
*  on busy list
***********************************************************************/
ClientSession *
pppoe_alloc_session(void)
{
    ClientSession *ses = FreeSessions;
    if (!ses) return NULL;

    /* Remove from free sessions list */
    if (ses == LastFreeSession) {
	LastFreeSession = NULL;
    }
    FreeSessions = ses->next;

    /* Put on busy sessions list */
    ses->next = BusySessions;
    BusySessions = ses;

    /* Initialize fields to sane values */
    ses->funcs = &DefaultSessionFunctionTable;
    ses->pid = 0;
    ses->ethif = NULL;
    memset(ses->eth, 0, ETH_ALEN);
    ses->flags = 0;
    ses->startTime = time(NULL);
    ses->serviceName = "";
#ifdef HAVE_LICENSE
    memset(ses->user, 0, MAX_USERNAME_LEN+1);
    memset(ses->realm, 0, MAX_USERNAME_LEN+1);
    memset(ses->realpeerip, 0, IPV4ALEN);
#endif
#ifdef HAVE_L2TP
    ses->l2tp_ses = NULL;
#endif
    NumActiveSessions++;
    return ses;
}

/**********************************************************************
* %FUNCTION: pppoe_free_session
* %ARGUMENTS:
*  ses -- session to free
* %RETURNS:
*  0 if OK, -1 if error
* %DESCRIPTION:
*  Places a ClientSession on the free list.
***********************************************************************/
int
pppoe_free_session(ClientSession *ses)
{
    ClientSession *cur, *prev;

    cur = BusySessions;
    prev = NULL;
    while (cur) {
	if (ses == cur) break;
	prev = cur;
	cur = cur->next;
    }

    if (!cur) {
	syslog(LOG_ERR, "pppoe_free_session: Could not find session %p on busy list", (void *) ses);
	return -1;
    }

    /* Remove from busy sessions list */
    if (prev) {
	prev->next = ses->next;
    } else {
	BusySessions = ses->next;
    }

    /* Add to end of free sessions */
    ses->next = NULL;
    if (LastFreeSession) {
	LastFreeSession->next = ses;
	LastFreeSession = ses;
    } else {
	FreeSessions = ses;
	LastFreeSession = ses;
    }

    /* Initialize fields to sane values */
    ses->funcs = &DefaultSessionFunctionTable;
    ses->pid = 0;
    ses->flags = 0;
#ifdef HAVE_L2TP
    ses->l2tp_ses = NULL;
#endif
    NumActiveSessions--;
    return 0;
}

/**********************************************************************
* %FUNCTION: sendHURLorMOTM
* %ARGUMENTS:
*  conn -- PPPoE connection
*  url -- a URL, which *MUST* begin with "http://" or it won't be sent, or
*         a message.
*  tag -- one of TAG_HURL or TAG_MOTM
* %RETURNS:
*  Nothing
* %DESCRIPTION:
*  Sends a PADM packet contaning a HURL or MOTM tag to the victim...er, peer.
***********************************************************************/
void
sendHURLorMOTM(PPPoEConnection *conn, char const *url, UINT16_t tag)
{
    PPPoEPacket packet;
    PPPoETag hurl;
    size_t elen;
    unsigned char *cursor = packet.payload;
    UINT16_t plen = 0;

    if (!conn->session) return;
    if (conn->discoverySocket < 0) return;

    if (tag == TAG_HURL) {
	if (strncmp(url, "http://", 7)) {
	    syslog(LOG_WARNING, "sendHURL(%s): URL must begin with http://", url);
	    return;
	}
    } else {
	tag = TAG_MOTM;
    }

    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_Discovery);
    packet.ver = 1;
    packet.type = 1;
    packet.code = CODE_PADM;
    packet.session = conn->session;

    elen = strlen(url);
    if (elen > 256) {
	syslog(LOG_WARNING, "MOTM or HURL too long: %d", (int) elen);
	return;
    }

    hurl.type = htons(tag);
    hurl.length = htons(elen);
    strcpy(hurl.payload, url);
    memcpy(cursor, &hurl, elen + TAG_HDR_SIZE);
    cursor += elen + TAG_HDR_SIZE;
    plen += elen + TAG_HDR_SIZE;

    packet.length = htons(plen);

    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
    if (conn->debugFile) {
	dumpPacket(conn->debugFile, &packet, "SENT");
	fprintf(conn->debugFile, "\n");
	fflush(conn->debugFile);
    }
}

⌨️ 快捷键说明

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