📄 relay.c
字号:
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.***********************************************************************/voidrelayHandlePADO(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); /* Set destination address to MAC address in relay ID */ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN); /* Set source address to MAC address of interface */ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN); /* Send the PADO to the proper client */ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);}/***********************************************************************%FUNCTION: relayHandlePADR*%ARGUMENTS:* iface -- interface on which packet was received* packet -- the PADR packet*%RETURNS:* Nothing*%DESCRIPTION:* Receives and processes a PADR packet.***********************************************************************/voidrelayHandlePADR(PPPoEInterface const *iface, PPPoEPacket *packet, int size){ PPPoETag tag; unsigned char *loc; int ifIndex; int cliIndex; /* Can a client legally be behind this interface? */ if (!iface->clientOK) { syslog(LOG_ERR, "PADR 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; } cliIndex = iface - Interfaces; /* Source address must be unicast */ if (NOT_UNICAST(packet->ethHdr.h_source)) { syslog(LOG_ERR, "PADR 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, "PADR 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, "PADR 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].acOK || iface == &Interfaces[ifIndex]) { syslog(LOG_ERR, "PADR 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, &cliIndex, sizeof(cliIndex)); memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN); /* Set destination address to MAC address in relay ID */ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN); /* Set source address to MAC address of interface */ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN); /* Send the PADR to the proper access concentrator */ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);}/***********************************************************************%FUNCTION: relayHandlePADS*%ARGUMENTS:* iface -- interface on which packet was received* packet -- the PADS packet*%RETURNS:* Nothing*%DESCRIPTION:* Receives and processes a PADS packet.***********************************************************************/voidrelayHandlePADS(PPPoEInterface const *iface, PPPoEPacket *packet, int size){ PPPoETag tag; unsigned char *loc; int ifIndex; int acIndex; PPPoESession *ses = NULL; SessionHash *sh; /* Can a server legally be behind this interface? */ if (!iface->acOK) { syslog(LOG_ERR, "PADS 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, "PADS 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, "PADS 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, "PADS 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, "PADS 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; } /* If session ID is zero, it's the AC respoding with an error. Just relay it; do not create a session */ if (packet->session != htons(0)) { /* Check for existing session */ sh = findSession(packet->ethHdr.h_source, packet->session); if (sh) ses = sh->ses; /* If already an existing session, assume it's a duplicate PADS. Send the frame, but do not create a new session. Is this the right thing to do? Arguably, should send an error to the client and a PADT to the server, because this could happen due to a server crash and reboot. */ if (!ses) { /* Create a new session */ ses = createSession(iface, &Interfaces[ifIndex], packet->ethHdr.h_source, loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session); if (!ses) { /* Can't allocate session -- send error PADS to client and PADT to server */ PPPoETag hostUniq, *hu; if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) { hu = &hostUniq; } else { hu = NULL; } relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex], loc + TAG_HDR_SIZE + sizeof(ifIndex), hu, "RP-PPPoE: Relay: Unable to allocate session"); relaySendError(CODE_PADT, packet->session, iface, packet->ethHdr.h_source, NULL, "RP-PPPoE: Relay: Unable to allocate session"); return; } } /* Replace session number */ packet->session = ses->sesNum; } /* Remove relay-ID tag */ removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE); size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE); /* Set destination address to MAC address in relay ID */ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN); /* Set source address to MAC address of interface */ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN); /* Send the PADS to the proper client */ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);}/***********************************************************************%FUNCTION: relaySendError*%ARGUMENTS:* code -- PPPoE packet code (PADS or PADT, typically)* session -- PPPoE session number* iface -- interface on which to send frame* mac -- Ethernet address to which frame should be sent* hostUniq -- if non-NULL, a hostUniq tag to add to error frame* errMsg -- error message to insert into Generic-Error tag.*%RETURNS:* Nothing*%DESCRIPTION:* Sends either a PADS or PADT packet with a Generic-Error tag and an* error message.***********************************************************************/voidrelaySendError(unsigned char code, UINT16_t session, PPPoEInterface const *iface, unsigned char const *mac, PPPoETag const *hostUniq, char const *errMsg){ PPPoEPacket packet; PPPoETag errTag; int size; memcpy(packet.ethHdr.h_source, iface->mac, ETH_ALEN); memcpy(packet.ethHdr.h_dest, mac, ETH_ALEN); packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); packet.type = 1; packet.ver = 1; packet.code = code; packet.session = session; packet.length = htons(0); if (hostUniq) { if (addTag(&packet, hostUniq) < 0) return; } errTag.type = htons(TAG_GENERIC_ERROR); errTag.length = htons(strlen(errMsg)); strcpy((char *) errTag.payload, errMsg); if (addTag(&packet, &errTag) < 0) return; size = ntohs(packet.length) + HDR_SIZE; if (code == CODE_PADT) { sendPacket(NULL, iface->discoverySock, &packet, size); } else { sendPacket(NULL, iface->sessionSock, &packet, size); }}/***********************************************************************%FUNCTION: alarmHandler*%ARGUMENTS:* sig -- signal number*%RETURNS:* Nothing*%DESCRIPTION:* SIGALRM handler. Increments Epoch; if necessary, writes a byte of* data to the alarm pipe to trigger the stale-session cleaner.***********************************************************************/voidalarmHandler(int sig){ alarm(1); Epoch++; CleanCounter++; if (CleanCounter == CleanPeriod) { write(CleanPipe[1], "", 1); }}/***********************************************************************%FUNCTION: cleanSessions*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* Goes through active sessions and cleans sessions idle for longer* than IdleTimeout seconds.***********************************************************************/void cleanSessions(void){ PPPoESession *cur, *next; cur = ActiveSessions; while(cur) { next = cur->next; if (Epoch - cur->epoch > IdleTimeout) { /* Send PADT to each peer */ relaySendError(CODE_PADT, cur->acHash->sesNum, cur->acHash->interface, cur->acHash->peerMac, NULL, "RP-PPPoE: Relay: Session exceeded idle timeout"); relaySendError(CODE_PADT, cur->clientHash->sesNum, cur->clientHash->interface, cur->clientHash->peerMac, NULL, "RP-PPPoE: Relay: Session exceeded idle timeout"); freeSession(cur, "Idle Timeout"); } cur = next; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -