📄 pppoe-server.c
字号:
/* 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 + -