📄 pppoe.c
字号:
// 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 HUP; ignore TERM and INT if (!conn.printACNames) { signal(SIGTERM, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGHUP, sigPADT);#ifdef HAVE_N_HDLC if (conn.synchronous) { if (ioctl(0, TIOCSETD, &disc) < 0) { printErr("Unable to set line discipline to N_HDLC. Make sure your kernel supports the N_HDLC line discipline, or do not use the SYNCHRONOUS option. Quitting."); exit(EXIT_FAILURE); } 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: Session %d: %.256s", str, (int) ntohs(Connection->session), strerror(errno)); printErr(buf); sendPADTf(Connection, "RP-PPPoE: System call error: %s", strerror(errno)); 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); sendPADTf(Connection, "RP-PPPoE: Session %d: %.256s", (int) ntohs(Connection->session), str); 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 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]; unsigned char buf[2000];#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"); } */ buf[0]=FRAME_ADDR; buf[1]=FRAME_CTRL; memcpy((void*)&buf[2],(void*)packet.payload,plen); if (write(1,(void*)buf,plen+2) < 0) { fatalSys("syncReadFromEth: write"); } }//守护进程初始化void init_daemon(void){ int pid; int i; if(pid=fork()) exit(0);//是父进程,结束父进程 else if(pid< 0) exit(1);//fork失败,退出, 是第一子进程,后台继续执行 setsid(); //第一子进程成为新的会话组长和进程组长 //并与控制终端分离 if(pid=fork()) exit(0);//是第一子进程,结束第一子进程 else if(pid< 0) exit(1);//fork失败,退出, 是第二子进程,继续, 第二子进程不再是会话组长 //关闭打开的文件描述符 for(i=0;i< NOFILE;++i) close(i); chdir("/tmp"); //改变工作目录到/tmp umask(0); //重设文件创建掩模 return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -