📄 relay.c
字号:
memcpy(cliHash->peerMac, cliMac, ETH_ALEN); cliHash->sesNum = sess->sesNum; cliHash->ses = sess; addHash(acHash); addHash(cliHash); /* Log */ syslog(LOG_INFO, "Opened session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d)", acHash->peerMac[0], acHash->peerMac[1], acHash->peerMac[2], acHash->peerMac[3], acHash->peerMac[4], acHash->peerMac[5], acHash->interface->name, ntohs(acHash->sesNum), cliHash->peerMac[0], cliHash->peerMac[1], cliHash->peerMac[2], cliHash->peerMac[3], cliHash->peerMac[4], cliHash->peerMac[5], cliHash->interface->name, ntohs(cliHash->sesNum)); return sess;}/***********************************************************************%FUNCTION: freeSession*%ARGUMENTS:* ses -- session to free* msg -- extra message to log on syslog.*%RETURNS:* Nothing*%DESCRIPTION:* Frees data used by a PPPoE session -- adds hashes and session back* to the free list***********************************************************************/voidfreeSession(PPPoESession *ses, char const *msg){ syslog(LOG_INFO, "Closed session: server=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d), client=%02x:%02x:%02x:%02x:%02x:%02x(%s:%d): %s", ses->acHash->peerMac[0], ses->acHash->peerMac[1], ses->acHash->peerMac[2], ses->acHash->peerMac[3], ses->acHash->peerMac[4], ses->acHash->peerMac[5], ses->acHash->interface->name, ntohs(ses->acHash->sesNum), ses->clientHash->peerMac[0], ses->clientHash->peerMac[1], ses->clientHash->peerMac[2], ses->clientHash->peerMac[3], ses->clientHash->peerMac[4], ses->clientHash->peerMac[5], ses->clientHash->interface->name, ntohs(ses->clientHash->sesNum), msg); /* Unlink from active sessions */ if (ses->prev) { ses->prev->next = ses->next; } else { ActiveSessions = ses->next; } if (ses->next) { ses->next->prev = ses->prev; } /* Link onto free list -- this is a singly-linked list, so we do not care about prev */ ses->next = FreeSessions; FreeSessions = ses; unhash(ses->acHash); unhash(ses->clientHash); NumSessions--;}/***********************************************************************%FUNCTION: unhash*%ARGUMENTS:* sh -- session hash to free*%RETURNS:* Nothing*%DESCRIPTION:* Frees a session hash -- takes it out of hash table and puts it on* free list.***********************************************************************/voidunhash(SessionHash *sh){ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE; if (sh->prev) { sh->prev->next = sh->next; } else { Buckets[b] = sh->next; } if (sh->next) { sh->next->prev = sh->prev; } /* Add to free list (singly-linked) */ sh->next = FreeHashes; FreeHashes = sh;}/***********************************************************************%FUNCTION: addHash*%ARGUMENTS:* sh -- a session hash*%RETURNS:* Nothing*%DESCRIPTION:* Adds a SessionHash to the hash table***********************************************************************/voidaddHash(SessionHash *sh){ unsigned int b = hash(sh->peerMac, sh->sesNum) % HASHTAB_SIZE; sh->next = Buckets[b]; sh->prev = NULL; if (sh->next) { sh->next->prev = sh; } Buckets[b] = sh;}/***********************************************************************%FUNCTION: hash*%ARGUMENTS:* mac -- an Ethernet address* sesNum -- a session number*%RETURNS:* A hash value combining Ethernet address with session number.* Currently very simplistic; we may need to experiment with different* hash values.***********************************************************************/unsigned inthash(unsigned char const *mac, UINT16_t sesNum){ unsigned int ans1 = ((unsigned int) mac[0]) | (((unsigned int) mac[1]) << 8) | (((unsigned int) mac[2]) << 16) | (((unsigned int) mac[3]) << 24); unsigned int ans2 = ((unsigned int) sesNum) | (((unsigned int) mac[4]) << 16) | (((unsigned int) mac[5]) << 24); return ans1 ^ ans2;}/***********************************************************************%FUNCTION: findSession*%ARGUMENTS:* mac -- an Ethernet address* sesNum -- a session number*%RETURNS:* The session hash for peer address "mac", session number sesNum***********************************************************************/SessionHash *findSession(unsigned char const *mac, UINT16_t sesNum){ unsigned int b = hash(mac, sesNum) % HASHTAB_SIZE; SessionHash *sh = Buckets[b]; while(sh) { if (!memcmp(mac, sh->peerMac, ETH_ALEN) && sesNum == sh->sesNum) { return sh; } sh = sh->next; } return NULL;}/***********************************************************************%FUNCTION: fatalSys*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message plus the errno value to stderr and syslog and exits.***********************************************************************/voidfatalSys(char const *str){ char buf[1024]; sprintf(buf, "%.256s: %.256s", str, strerror(errno)); printErr(buf); exit(EXIT_FAILURE);}/***********************************************************************%FUNCTION: sysErr*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message plus the errno value to syslog.***********************************************************************/voidsysErr(char const *str){ char buf[1024]; sprintf(buf, "%.256s: %.256s", str, strerror(errno)); printErr(buf);}/***********************************************************************%FUNCTION: rp_fatal*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message to stderr and syslog and exits.***********************************************************************/voidrp_fatal(char const *str){ printErr(str); exit(EXIT_FAILURE);}/***********************************************************************%FUNCTION: relayLoop*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* Runs the relay loop. This function never returns***********************************************************************/voidrelayLoop(){ fd_set readable, readableCopy; int maxFD; int i, r; int sock; /* Build the select set */ FD_ZERO(&readable); maxFD = 0; for (i=0; i<NumInterfaces; i++) { sock = Interfaces[i].discoverySock; if (sock > maxFD) maxFD = sock; FD_SET(sock, &readable); sock = Interfaces[i].sessionSock; if (sock > maxFD) maxFD = sock; FD_SET(sock, &readable); if (CleanPipe[0] > maxFD) maxFD = CleanPipe[0]; FD_SET(CleanPipe[0], &readable); } maxFD++; for(;;) { readableCopy = readable; for(;;) { r = select(maxFD, &readableCopy, NULL, NULL, NULL); if (r >= 0 || errno != EINTR) break; } if (r < 0) { sysErr("select (relayLoop)"); continue; } /* Handle session packets first */ for (i=0; i<NumInterfaces; i++) { 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.***********************************************************************/voidrelayGotDiscoveryPacket(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.***********************************************************************/voidrelayGotSessionPacket(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.***********************************************************************/voidrelayHandlePADT(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.***********************************************************************/voidrelayHandlePADI(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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -