📄 relay.c
字号:
if (FD_ISSET(Interfaces[i].sessionSock, &readableCopy)) {
relayGotSessionPacket(&Interfaces[i]);
}
}
/* Now handle discovery packets */
for (i=0; i<NumInterfaces; i++) {
if (FD_ISSET(Interfaces[i].discoverySock, &readableCopy)) {
relayGotDiscoveryPacket(&Interfaces[i]);
}
}
/* Handle the session-cleaning process */
if (FD_ISSET(CleanPipe[0], &readableCopy)) {
char dummy;
CleanCounter = 0;
read(CleanPipe[0], &dummy, 1);
if (IdleTimeout) cleanSessions();
}
}
}
/**********************************************************************
*%FUNCTION: relayGotDiscoveryPacket
*%ARGUMENTS:
* iface -- interface on which packet is waiting
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a discovery packet.
***********************************************************************/
void
relayGotDiscoveryPacket(PPPoEInterface const *iface)
{
PPPoEPacket packet;
int size;
if (receivePacket(iface->discoverySock, &packet, &size) < 0) {
return;
}
/* Ignore unknown code/version */
if (packet.ver != 1 || packet.type != 1) {
return;
}
/* Validate length */
if (ntohs(packet.length) + HDR_SIZE > size) {
syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
(unsigned int) ntohs(packet.length));
return;
}
/* Drop Ethernet frame padding */
if (size > ntohs(packet.length) + HDR_SIZE) {
size = ntohs(packet.length) + HDR_SIZE;
}
switch(packet.code) {
case CODE_PADT:
relayHandlePADT(iface, &packet, size);
break;
case CODE_PADI:
relayHandlePADI(iface, &packet, size);
break;
case CODE_PADO:
relayHandlePADO(iface, &packet, size);
break;
case CODE_PADR:
relayHandlePADR(iface, &packet, size);
break;
case CODE_PADS:
relayHandlePADS(iface, &packet, size);
break;
default:
syslog(LOG_ERR, "Discovery packet on %s with unknown code %d",
iface->name, (int) packet.code);
}
}
/**********************************************************************
*%FUNCTION: relayGotSessionPacket
*%ARGUMENTS:
* iface -- interface on which packet is waiting
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a session packet.
***********************************************************************/
void
relayGotSessionPacket(PPPoEInterface const *iface)
{
PPPoEPacket packet;
int size;
SessionHash *sh;
PPPoESession *ses;
if (receivePacket(iface->sessionSock, &packet, &size) < 0) {
return;
}
/* Ignore unknown code/version */
if (packet.ver != 1 || packet.type != 1) {
return;
}
/* Must be a session packet */
if (packet.code != CODE_SESS) {
syslog(LOG_ERR, "Session packet with code %d", (int) packet.code);
return;
}
/* Ignore session packets whose destination address isn't ours */
if (memcmp(packet.ethHdr.h_dest, iface->mac, ETH_ALEN)) {
return;
}
/* Validate length */
if (ntohs(packet.length) + HDR_SIZE > size) {
syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
(unsigned int) ntohs(packet.length));
return;
}
/* Drop Ethernet frame padding */
if (size > ntohs(packet.length) + HDR_SIZE) {
size = ntohs(packet.length) + HDR_SIZE;
}
/* We're in business! Find the hash */
sh = findSession(packet.ethHdr.h_source, packet.session);
if (!sh) {
/* Don't log this. Someone could be running the client and the
relay on the same box. */
return;
}
/* Relay it */
ses = sh->ses;
ses->epoch = Epoch;
sh = sh->peer;
packet.session = sh->sesNum;
memcpy(packet.ethHdr.h_source, sh->interface->mac, ETH_ALEN);
memcpy(packet.ethHdr.h_dest, sh->peerMac, ETH_ALEN);
#if 0
fprintf(stderr, "Relaying %02x:%02x:%02x:%02x:%02x:%02x(%s:%d) to %02x:%02x:%02x:%02x:%02x:%02x(%s:%d)\n",
sh->peer->peerMac[0], sh->peer->peerMac[1], sh->peer->peerMac[2],
sh->peer->peerMac[3], sh->peer->peerMac[4], sh->peer->peerMac[5],
sh->peer->interface->name, ntohs(sh->peer->sesNum),
sh->peerMac[0], sh->peerMac[1], sh->peerMac[2],
sh->peerMac[3], sh->peerMac[4], sh->peerMac[5],
sh->interface->name, ntohs(sh->sesNum));
#endif
sendPacket(NULL, sh->interface->sessionSock, &packet, size);
}
/**********************************************************************
*%FUNCTION: relayHandlePADT
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADT packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADT packet.
***********************************************************************/
void
relayHandlePADT(PPPoEInterface const *iface,
PPPoEPacket *packet,
int size)
{
SessionHash *sh;
PPPoESession *ses;
sh = findSession(packet->ethHdr.h_source, packet->session);
if (!sh) {
return;
}
/* Relay the PADT to the peer */
sh = sh->peer;
ses = sh->ses;
packet->session = sh->sesNum;
memcpy(packet->ethHdr.h_source, sh->interface->mac, ETH_ALEN);
memcpy(packet->ethHdr.h_dest, sh->peerMac, ETH_ALEN);
sendPacket(NULL, sh->interface->sessionSock, packet, size);
/* Destroy the session */
freeSession(ses, "Received PADT");
}
/**********************************************************************
*%FUNCTION: relayHandlePADI
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADI packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADI packet.
***********************************************************************/
void
relayHandlePADI(PPPoEInterface const *iface,
PPPoEPacket *packet,
int size)
{
PPPoETag tag;
unsigned char *loc;
int i, r;
int ifIndex;
/* Can a client legally be behind this interface? */
if (!iface->clientOK) {
syslog(LOG_ERR,
"PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
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],
iface->name);
return;
}
/* Source address must be unicast */
if (NOT_UNICAST(packet->ethHdr.h_source)) {
syslog(LOG_ERR,
"PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
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],
iface->name);
return;
}
/* Destination address must be broadcast */
if (NOT_BROADCAST(packet->ethHdr.h_dest)) {
syslog(LOG_ERR,
"PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address",
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],
iface->name);
return;
}
/* Get array index of interface */
ifIndex = iface - Interfaces;
loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
if (!loc) {
tag.type = htons(TAG_RELAY_SESSION_ID);
tag.length = htons(MY_RELAY_TAG_LEN);
memcpy(tag.payload, &ifIndex, sizeof(ifIndex));
memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
/* Add a relay tag if there's room */
r = addTag(packet, &tag);
if (r < 0) return;
size += r;
} else {
/* We do not re-use relay-id tags. Drop the frame. The RFC says the
relay agent SHOULD return a Generic-Error tag, but this does not
make sense for PADI packets. */
return;
}
/* Broadcast the PADI on all AC-capable interfaces except the interface
on which it came */
for (i=0; i < NumInterfaces; i++) {
if (iface == &Interfaces[i]) continue;
if (!Interfaces[i].acOK) continue;
memcpy(packet->ethHdr.h_source, Interfaces[i].mac, ETH_ALEN);
sendPacket(NULL, Interfaces[i].discoverySock, packet, size);
}
}
/**********************************************************************
*%FUNCTION: relayHandlePADO
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADO packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADO packet.
***********************************************************************/
void
relayHandlePADO(PPPoEInterface const *iface,
PPPoEPacket *packet,
int size)
{
PPPoETag tag;
unsigned char *loc;
int ifIndex;
int acIndex;
/* Can a server legally be behind this interface? */
if (!iface->acOK) {
syslog(LOG_ERR,
"PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
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],
iface->name);
return;
}
acIndex = iface - Interfaces;
/* Source address must be unicast */
if (NOT_UNICAST(packet->ethHdr.h_source)) {
syslog(LOG_ERR,
"PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
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],
iface->name);
return;
}
/* Destination address must be interface's MAC address */
if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
return;
}
/* Find relay tag */
loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
if (!loc) {
syslog(LOG_ERR,
"PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
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],
iface->name);
return;
}
/* If it's the wrong length, ignore it */
if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
syslog(LOG_ERR,
"PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
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],
iface->name);
return;
}
/* Extract interface index */
memcpy(&ifIndex, tag.payload, sizeof(ifIndex));
if (ifIndex < 0 || ifIndex >= NumInterfaces ||
!Interfaces[ifIndex].clientOK ||
iface == &Interfaces[ifIndex]) {
syslog(LOG_ERR,
"PADO packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
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],
iface->name);
return;
}
/* Replace Relay-ID tag with opposite-direction tag */
memcpy(loc+TAG_HDR_SIZE, &acIndex, sizeof(acIndex));
memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -