📄 pppoe.c
字号:
/* Existing session: "sess:xx:yy:zz:aa:bb:cc" where "sess" is session-ID, and xx:yy:zz:aa:bb:cc is MAC-address of peer */ n = sscanf(optarg, "%u:%2x:%2x:%2x:%2x:%2x:%2x", &s, &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]); if (n != 7) { fprintf(stderr, "Illegal argument to -e: Should be sess:xx:yy:zz:aa:bb:cc\n"); exit(EXIT_FAILURE); } /* Copy MAC address of peer */ for (n=0; n<6; n++) { conn.peerEth[n] = (unsigned char) m[n]; } /* Convert session */ conn.session = htons(s); /* Skip discovery phase! */ conn.skipDiscovery = 1; break; case 'p': pidfile = fopen(optarg, "w"); if (pidfile) { fprintf(pidfile, "%lu\n", (unsigned long) getpid()); fclose(pidfile); } break; case 'S': SET_STRING(conn.serviceName, optarg); break; case 'C': SET_STRING(conn.acName, optarg); break; case 's': conn.synchronous = 1; break; case 'U': conn.useHostUniq = 1; break; case 'D': conn.debugFile = fopen(optarg, "w"); if (!conn.debugFile) { fprintf(stderr, "Could not open %s: %s\n", optarg, strerror(errno)); exit(EXIT_FAILURE); } fprintf(conn.debugFile, "rp-pppoe-%s\n", VERSION); fflush(conn.debugFile); break; case 'T': optInactivityTimeout = (int) strtol(optarg, NULL, 10); if (optInactivityTimeout < 0) { optInactivityTimeout = 0; } break; case 'm': optClampMSS = (int) strtol(optarg, NULL, 10); if (optClampMSS < 536) { fprintf(stderr, "-m: %d is too low (min 536)\n", optClampMSS); exit(EXIT_FAILURE); } if (optClampMSS > 1452) { fprintf(stderr, "-m: %d is too high (max 1452)\n", optClampMSS); exit(EXIT_FAILURE); } break; case 'I': SET_STRING(conn.ifName, optarg); break; case 'V': printf("Roaring Penguin PPPoE Version %s\n", VERSION); exit(EXIT_SUCCESS); case 'A': conn.printACNames = 1; break; case 'h': usage(argv[0]); break; default: usage(argv[0]); } } /* Pick a default interface name */ if (!conn.ifName) {#ifdef USE_BPF fprintf(stderr, "No interface specified (-I option)\n"); exit(EXIT_FAILURE);#else SET_STRING(conn.ifName, DEFAULT_IF);#endif } /* Set signal handlers: send PADT on TERM, HUP and INT */ if (!conn.printACNames) { signal(SIGTERM, sigPADT); signal(SIGHUP, sigPADT); signal(SIGINT, sigPADT);#ifdef HAVE_N_HDLC if (conn.synchronous) { if (ioctl(0, TIOCSETD, &disc) < 0) { printErr("Unable to set line discipline to N_HDLC -- synchronous mode probably will fail"); } else { syslog(LOG_INFO, "Changed pty line discipline to N_HDLC for synchronous mode"); } /* There is a bug in Linux's select which returns a descriptor * as readable if N_HDLC line discipline is on, even if * it isn't really readable. This return happens only when * select() times out. To avoid blocking forever in read(), * make descriptor 0 non-blocking */ flags = fcntl(0, F_GETFL); if (flags < 0) fatalSys("fcntl(F_GETFL)"); if (fcntl(0, F_SETFL, (long) flags | O_NONBLOCK) < 0) { fatalSys("fcntl(F_SETFL)"); } }#endif } if (optFloodDiscovery) { for (n=0; n < optFloodDiscovery; n++) { if (conn.printACNames) { fprintf(stderr, "Sending discovery flood %d\n", n+1); } discovery(&conn); conn.discoveryState = STATE_SENT_PADI; close(conn.discoverySocket); } exit(EXIT_SUCCESS); } discovery(&conn); if (optSkipSession) { printf("%u:%02x:%02x:%02x:%02x:%02x:%02x\n", ntohs(conn.session), conn.peerEth[0], conn.peerEth[1], conn.peerEth[2], conn.peerEth[3], conn.peerEth[4], conn.peerEth[5]); exit(EXIT_SUCCESS); } session(&conn); return 0;}/***********************************************************************%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); sendPADT(Connection, "RP-PPPoE: System call error"); 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){ char buf[1024]; printErr(str); sprintf(buf, "RP-PPPoE: %.256s", str); sendPADT(Connection, buf); exit(EXIT_FAILURE);}/***********************************************************************%FUNCTION: asyncReadFromEth*%ARGUMENTS:* conn -- PPPoE connection info* sock -- Ethernet socket* clampMss -- if non-zero, do MSS-clamping*%RETURNS:* Nothing*%DESCRIPTION:* Reads a packet from the Ethernet interface and sends it to async PPP* device.***********************************************************************/voidasyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss){ PPPoEPacket packet; int len; int plen; int i; unsigned char pppBuf[4096]; unsigned char *ptr = pppBuf; unsigned char c; UINT16_t fcs; unsigned char header[2] /* = {FRAME_ADDR, FRAME_CTRL}*/ ; unsigned char tail[2];#ifdef USE_BPF int type;#endif header[0] = FRAME_ADDR; header[1] = FRAME_CTRL; if (receivePacket(sock, &packet, &len) < 0) { return; } /* Check length */ if (ntohs(packet.length) + HDR_SIZE > len) { syslog(LOG_ERR, "Bogus PPPoE length field (%u)", (unsigned int) ntohs(packet.length)); return; } if (conn->debugFile) { dumpPacket(conn->debugFile, &packet, "RCVD"); fprintf(conn->debugFile, "\n"); fflush(conn->debugFile); }#ifdef USE_BPF /* Make sure this is a session packet before processing further */ type = etherType(&packet); if (type == Eth_PPPOE_Discovery) { sessionDiscoveryPacket(&packet); } else if (type != Eth_PPPOE_Session) { return; }#endif /* Sanity check */ if (packet.code != CODE_SESS) { syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code); return; } if (packet.ver != 1) { syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver); return; } if (packet.type != 1) { syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type); return; } if (memcmp(packet.ethHdr.h_dest, conn->myEth, ETH_ALEN)) { return; } if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) { /* Not for us -- must be another session. This is not an error, so don't log anything. */ return; } if (packet.session != conn->session) { /* Not for us -- must be another session. This is not an error, so don't log anything. */ return; } plen = ntohs(packet.length); if (plen + HDR_SIZE > len) { syslog(LOG_ERR, "Bogus length field in session packet %d (%d)", (int) plen, (int) len); return; } /* Clamp MSS */ if (clampMss) { clampMSS(&packet, "incoming", clampMss); } /* Compute FCS */ fcs = pppFCS16(PPPINITFCS16, header, 2); fcs = pppFCS16(fcs, packet.payload, plen) ^ 0xffff; tail[0] = fcs & 0x00ff; tail[1] = (fcs >> 8) & 0x00ff; /* Build a buffer to send to PPP */ *ptr++ = FRAME_FLAG; *ptr++ = FRAME_ADDR; *ptr++ = FRAME_ESC; *ptr++ = FRAME_CTRL ^ FRAME_ENC; for (i=0; i<plen; i++) { c = packet.payload[i]; if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) { *ptr++ = FRAME_ESC; *ptr++ = c ^ FRAME_ENC; } else { *ptr++ = c; } } for (i=0; i<2; i++) { c = tail[i]; if (c == FRAME_FLAG || c == FRAME_ADDR || c == FRAME_ESC || c < 0x20) { *ptr++ = FRAME_ESC; *ptr++ = c ^ FRAME_ENC; } else { *ptr++ = c; } } *ptr++ = FRAME_FLAG; /* Ship it out */ if (write(1, pppBuf, (ptr-pppBuf)) < 0) { fatalSys("asyncReadFromEth: write"); }}/***********************************************************************%FUNCTION: syncReadFromEth*%ARGUMENTS:* conn -- PPPoE connection info* sock -- Ethernet socket* clampMss -- if true, clamp MSS.*%RETURNS:* Nothing*%DESCRIPTION:* Reads a packet from the Ethernet interface and sends it to sync PPP* device.***********************************************************************/voidsyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss){ PPPoEPacket packet; int len; int plen; struct iovec vec[2]; unsigned char dummy[2];#ifdef USE_BPF int type;#endif if (receivePacket(sock, &packet, &len) < 0) { return; } /* Check length */ if (ntohs(packet.length) + HDR_SIZE > len) { syslog(LOG_ERR, "Bogus PPPoE length field (%u)", (unsigned int) ntohs(packet.length)); return; } if (conn->debugFile) { dumpPacket(conn->debugFile, &packet, "RCVD"); fprintf(conn->debugFile, "\n"); fflush(conn->debugFile); }#ifdef USE_BPF /* Make sure this is a session packet before processing further */ type = etherType(&packet); if (type == Eth_PPPOE_Discovery) { sessionDiscoveryPacket(&packet); } else if (type != Eth_PPPOE_Session) { return; }#endif /* Sanity check */ if (packet.code != CODE_SESS) { syslog(LOG_ERR, "Unexpected packet code %d", (int) packet.code); return; } if (packet.ver != 1) { syslog(LOG_ERR, "Unexpected packet version %d", (int) packet.ver); return; } if (packet.type != 1) { syslog(LOG_ERR, "Unexpected packet type %d", (int) packet.type); return; } if (memcmp(packet.ethHdr.h_dest, conn->myEth, ETH_ALEN)) { /* Not for us -- must be another session. This is not an error, so don't log anything. */ return; } if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) { /* Not for us -- must be another session. This is not an error, so don't log anything. */ return; } if (packet.session != conn->session) { /* Not for us -- must be another session. This is not an error, so don't log anything. */ return; } plen = ntohs(packet.length); if (plen + HDR_SIZE > len) { syslog(LOG_ERR, "Bogus length field in session packet %d (%d)", (int) plen, (int) len); return; } /* Clamp MSS */ if (clampMss) { clampMSS(&packet, "incoming", clampMss); } /* Ship it out */ vec[0].iov_base = (void *) dummy; dummy[0] = FRAME_ADDR; dummy[1] = FRAME_CTRL; vec[0].iov_len = 2; vec[1].iov_base = (void *) packet.payload; vec[1].iov_len = plen; if (writev(1, vec, 2) < 0) { fatalSys("syncReadFromEth: write"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -