📄 pppoe-server.c
字号:
* argc, argv -- usual suspects*%RETURNS:* Exit status*%DESCRIPTION:* Main program of PPPoE server***********************************************************************/intmain(int argc, char **argv){ FILE *fp; int i, j; int opt; int d[IPV4ALEN]; int beDaemon = 1; int found; unsigned int discoveryType, sessionType; char *addressPoolFname = NULL;#ifdef HAVE_LICENSE int use_clustering = 0;#endif#ifndef HAVE_LINUX_KERNEL_PPPOE char *options = "hI:C:L:R:T:m:FN:f:o:sp:lrudPc:S:1";#else char *options = "hI:C:L:R:T:m:FN:f:o:skp:lrudPc:S:1";#endif if (getuid() != geteuid() || getgid() != getegid()) { fprintf(stderr, "SECURITY WARNING: pppoe-server will NOT run suid or sgid. Fix your installation.\n"); exit(1); } memset(interfaces, 0, sizeof(interfaces)); /* Initialize syslog */ openlog("pppoe-server", LOG_PID, LOG_DAEMON); /* Default number of session slots */ NumSessionSlots = DEFAULT_MAX_SESSIONS; NumActiveSessions = 0; /* Parse command-line options */ while((opt = getopt(argc, argv, options)) != -1) { switch(opt) {#ifdef HAVE_LINUX_KERNEL_PPPOE case 'k': UseLinuxKernelModePPPoE = 1; break;#endif case 'S': if (NumServiceNames == MAX_SERVICE_NAMES) { fprintf(stderr, "Too many '-S' options (%d max)", MAX_SERVICE_NAMES); exit(1); } ServiceNames[NumServiceNames] = strdup(optarg); if (!ServiceNames[NumServiceNames]) { fprintf(stderr, "Out of memory"); exit(1); } NumServiceNames++; break; case 'c':#ifndef HAVE_LICENSE fprintf(stderr, "Clustering capability not available.\n"); exit(1);#else cluster_handle_option(optarg); use_clustering = 1; break;#endif case 'd': Debug = 1; break; case 'P': CheckPoolSyntax = 1; break; case 'u': PassUnitOptionToPPPD = 1; break; case 'r': RandomizeSessionNumbers = 1; break; case 'l': IncrLocalIP = 1; break; case 'p': addressPoolFname = optarg; break; case 's': Synchronous = 1; /* Pass the Synchronous option on to pppoe */ snprintf(PppoeOptions + strlen(PppoeOptions), SMALLBUF-strlen(PppoeOptions), " -s"); break; case 'f': if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) { fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n"); exit(EXIT_FAILURE); } Eth_PPPOE_Discovery = (UINT16_t) discoveryType; Eth_PPPOE_Session = (UINT16_t) sessionType; /* This option gets passed to pppoe */ snprintf(PppoeOptions + strlen(PppoeOptions), SMALLBUF-strlen(PppoeOptions), " -%c %s", opt, optarg); break; case 'F': beDaemon = 0; break; case 'N': if (sscanf(optarg, "%d", &opt) != 1) { usage(argv[0]); exit(EXIT_FAILURE); } if (opt <= 0) { fprintf(stderr, "-N: Value must be positive\n"); exit(EXIT_FAILURE); } NumSessionSlots = opt; break; case 'o': if (sscanf(optarg, "%d", &opt) != 1) { usage(argv[0]); exit(EXIT_FAILURE); } if (opt < 0) { fprintf(stderr, "-o: Value must be non-negative\n"); exit(EXIT_FAILURE); } SessOffset = (size_t) opt; break; case 'I': if (NumInterfaces >= MAX_INTERFACES) { fprintf(stderr, "Too many -I options (max %d)\n", MAX_INTERFACES); exit(EXIT_FAILURE); } found = 0; for (i=0; i<NumInterfaces; i++) { if (!strncmp(interfaces[i].name, optarg, IFNAMSIZ)) { found = 1; break; } } if (!found) { strncpy(interfaces[NumInterfaces].name, optarg, IFNAMSIZ); NumInterfaces++; } break; case 'C': SET_STRING(ACName, optarg); break; case 'L': case 'R': /* Get local/remote IP address */ if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) { usage(argv[0]); exit(EXIT_FAILURE); } for (i=0; i<IPV4ALEN; i++) { if (d[i] < 0 || d[i] > 255) { usage(argv[0]); exit(EXIT_FAILURE); } if (opt == 'L') { LocalIP[i] = (unsigned char) d[i]; } else { RemoteIP[i] = (unsigned char) d[i]; } } break; case 'T': case 'm': /* These just get passed to pppoe */ snprintf(PppoeOptions + strlen(PppoeOptions), SMALLBUF-strlen(PppoeOptions), " -%c %s", opt, optarg); break; case 'h': usage(argv[0]); exit(EXIT_SUCCESS); case '1':#ifdef HAVE_LICENSE MaxSessionsPerUser = 1;#else fprintf(stderr, "-1 option not valid.\n"); exit(1);#endif break; } }#ifdef HAVE_LICENSE License_SetVersion(SERVPOET_VERSION); License_ReadBundleFile("/etc/rp/bundle.txt"); License_ReadFile("/etc/rp/license.txt"); ServerLicense = License_GetFeature("PPPOE-SERVER"); if (!ServerLicense) { fprintf(stderr, "License: GetFeature failed: %s\n", License_ErrorMessage()); exit(1); }#endif#ifdef USE_LINUX_PACKET#ifndef HAVE_STRUCT_SOCKADDR_LL fprintf(stderr, "The PPPoE server does not work on Linux 2.0 kernels.\n"); exit(EXIT_FAILURE);#endif#endif if (!NumInterfaces) { strcpy(interfaces[0].name, DEFAULT_IF); NumInterfaces = 1; } if (!ACName) { ACName = malloc(HOSTNAMELEN); if (gethostname(ACName, HOSTNAMELEN) < 0) { fatalSys("gethostname"); } } /* If address pool filename given, count number of addresses */ if (addressPoolFname) { NumSessionSlots = parseAddressPool(addressPoolFname, 0); if (CheckPoolSyntax) { printf("%d\n", NumSessionSlots); exit(0); } } /* Max 65534 - SessOffset sessions */ if (NumSessionSlots + SessOffset > 65534) { fprintf(stderr, "-N and -o options must add up to at most 65534\n"); exit(EXIT_FAILURE); } /* Allocate memory for sessions */ Sessions = calloc(NumSessionSlots, sizeof(ClientSession)); if (!Sessions) { rp_fatal("Cannot allocate memory for session slots"); } /* Fill in local addresses first (let pool file override later */ for (i=0; i<NumSessionSlots; i++) { memcpy(Sessions[i].myip, LocalIP, sizeof(LocalIP)); if (IncrLocalIP) { incrementIPAddress(LocalIP); } } /* Fill in remote IP addresses from pool (may also overwrite local ips) */ if (addressPoolFname) { (void) parseAddressPool(addressPoolFname, 1); } /* For testing -- generate sequential remote IP addresses */ for (i=0; i<NumSessionSlots; i++) { Sessions[i].pid = 0; Sessions[i].funcs = &DefaultSessionFunctionTable; Sessions[i].sess = htons(i+1+SessOffset); if (!addressPoolFname) { memcpy(Sessions[i].peerip, RemoteIP, sizeof(RemoteIP));#ifdef HAVE_LICENSE memcpy(Sessions[i].realpeerip, RemoteIP, sizeof(RemoteIP));#endif incrementIPAddress(RemoteIP); } } /* Initialize our random cookie. Try /dev/urandom; if that fails, use PID and rand() */ fp = fopen("/dev/urandom", "r"); if (fp) { unsigned int x; fread(&x, 1, sizeof(x), fp); srand(x); fread(&CookieSeed, 1, SEED_LEN, fp); fclose(fp); } else { srand((unsigned int) getpid() * (unsigned int) time(NULL)); CookieSeed[0] = getpid() & 0xFF; CookieSeed[1] = (getpid() >> 8) & 0xFF; for (i=2; i<SEED_LEN; i++) { CookieSeed[i] = (rand() >> (i % 9)) & 0xFF; } } if (RandomizeSessionNumbers) { int *permutation; int tmp; permutation = malloc(sizeof(int) * NumSessionSlots); if (!permutation) { fprintf(stderr, "Could not allocate memory to randomize session numbers\n"); exit(EXIT_FAILURE); } for (i=0; i<NumSessionSlots; i++) { permutation[i] = i; } for (i=0; i<NumSessionSlots-1; i++) { j = i + rand() % (NumSessionSlots - i); if (j != i) { tmp = permutation[j]; permutation[j] = permutation[i]; permutation[i] = tmp; } } /* Link sessions together */ FreeSessions = &Sessions[permutation[0]]; LastFreeSession = &Sessions[permutation[NumSessionSlots-1]]; for (i=0; i<NumSessionSlots-1; i++) { Sessions[permutation[i]].next = &Sessions[permutation[i+1]]; } Sessions[permutation[NumSessionSlots-1]].next = NULL; free(permutation); } else { /* Link sessions together */ FreeSessions = &Sessions[0]; LastFreeSession = &Sessions[NumSessionSlots - 1]; for (i=0; i<NumSessionSlots-1; i++) { Sessions[i].next = &Sessions[i+1]; } Sessions[NumSessionSlots-1].next = NULL; } if (Debug) { /* Dump session array and exit */ ClientSession *ses = FreeSessions; while(ses) { printf("Session %d local %d.%d.%d.%d remote %d.%d.%d.%d\n", ntohs(ses->sess), ses->myip[0], ses->myip[1], ses->myip[2], ses->myip[3], ses->peerip[0], ses->peerip[1], ses->peerip[2], ses->peerip[3]); ses = ses->next; } exit(0); } /* Open all the interfaces */ for (i=0; i<NumInterfaces; i++) { interfaces[i].sock = openInterface(interfaces[i].name, Eth_PPPOE_Discovery, interfaces[i].mac); } /* Ignore SIGPIPE */ signal(SIGPIPE, SIG_IGN); /* Create event selector */ event_selector = Event_CreateSelector(); if (!event_selector) { rp_fatal("Could not create EventSelector -- probably out of memory"); } /* Set signal handlers for SIGTERM and SIGINT */ if (Event_HandleSignal(event_selector, SIGTERM, termHandler) < 0 || Event_HandleSignal(event_selector, SIGINT, termHandler) < 0) { fatalSys("Event_HandleSignal"); } /* Control channel */#ifdef HAVE_LICENSE if (control_init(argc, argv, event_selector)) { rp_fatal("control_init failed"); }#endif /* Create event handler for each interface */ for (i = 0; i<NumInterfaces; i++) { interfaces[i].eh = Event_AddHandler(event_selector, interfaces[i].sock, EVENT_FLAG_READABLE, InterfaceHandler, &interfaces[i]);#ifdef HAVE_L2TP interfaces[i].session_sock = -1;#endif if (!interfaces[i].eh) { rp_fatal("Event_AddHandler failed"); } }#ifdef HAVE_LICENSE if (use_clustering) { ClusterLicense = License_GetFeature("PPPOE-CLUSTER"); if (!ClusterLicense) { fprintf(stderr, "License: GetFeature failed: %s\n", License_ErrorMessage()); exit(1); } if (!License_Expired(ClusterLicense)) { if (cluster_init(event_selector) < 0) { rp_fatal("cluster_init failed"); } } }#endif#ifdef HAVE_L2TP for (i=0; i<NumInterfaces; i++) { pppoe_to_l2tp_add_interface(event_selector, &interfaces[i]); }#endif /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */ if (beDaemon) { i = fork(); if (i < 0) { fatalSys("fork"); } else if (i != 0) { /* parent */ exit(EXIT_SUCCESS); } setsid(); signal(SIGHUP, SIG_IGN); i = fork(); if (i < 0) { fatalSys("fork"); } else if (i != 0) { exit(EXIT_SUCCESS); } chdir("/"); /* Point stdin/stdout/stderr to /dev/null */ for (i=0; i<3; i++) { close(i); } i = open("/dev/null", O_RDWR); if (i >= 0) { dup2(i, 0); dup2(i, 1); dup2(i, 2); if (i > 2) close(i); } } for(;;) { i = Event_HandleEvent(event_selector); if (i < 0) { fatalSys("Event_HandleEvent"); }#ifdef HAVE_LICENSE if (License_Expired(ServerLicense)) { syslog(LOG_INFO, "Server license has expired -- killing all PPPoE sessions"); killAllSessions(); control_exit(); exit(0); }#endif } return 0;}voidserverProcessPacket(Interface *i){ int len; PPPoEPacket packet; int sock = i->sock; 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; } /* Sanity check on packet */ if (packet.ver != 1 || packet.type != 1) { /* Syslog an error */ return; } switch(packet.code) { case CODE_PADI: processPADI(i, &packet, len); break; case CODE_PADR: processPADR(i, &packet, len); break; case CODE_PADT: /* Kill the child */ processPADT(i, &packet, len); break; case CODE_SESS: /* Ignore SESS -- children will handle them */ break; case CODE_PADO: case CODE_PADS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -