1/*********************************************************************** 2* 3* pppoe.h 4* 5* Implementation of a user-space PPPoE server 6* 7* Copyright (C) 2000 Roaring Penguin Software Inc. 8* 9* This program may be distributed according to the terms of the GNU 10* General Public License, version 2 or (at your option) any later version. 11* 12* $Id: pppoe-server.c,v 1.1.1.1 2008/10/15 03:31:00 james26_jang Exp $ 13* 14***********************************************************************/ 15 16static char const RCSID[] = 17"$Id: pppoe-server.c,v 1.1.1.1 2008/10/15 03:31:00 james26_jang Exp $"; 18 19#include "config.h" 20 21#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H) 22#define _POSIX_SOURCE 1 /* For sigaction defines */ 23#endif 24 25#define _BSD_SOURCE 1 /* for gethostname */ 26 27#include "pppoe.h" 28#include "md5.h" 29 30#ifdef HAVE_SYSLOG_H 31#include <syslog.h> 32#endif 33 34#include <errno.h> 35#include <string.h> 36#include <stdlib.h> 37 38#ifdef HAVE_UNISTD_H 39#include <unistd.h> 40#endif 41 42#ifdef HAVE_GETOPT_H 43#include <getopt.h> 44#endif 45 46#ifdef HAVE_SYS_WAIT_H 47#include <sys/wait.h> 48#endif 49 50#include <signal.h> 51 52/* Hack for daemonizing */ 53#define CLOSEFD 64 54 55/* Max. 64 sessions by default */ 56#define DEFAULT_MAX_SESSIONS 64 57 58/* A list of client sessions */ 59struct ClientSession *Sessions = NULL; 60 61/* The number of session slots */ 62size_t NumSessionSlots; 63 64/* Socket for client's discovery phases */ 65int Socket = -1; 66 67/* Pipe written on reception of SIGCHLD */ 68int Pipe[2] = {-1, -1}; 69int ReapPending = 0; 70 71/* Synchronous mode */ 72int Synchronous = 0; 73 74/* Random seed for cookie generation */ 75#define SEED_LEN 16 76unsigned char CookieSeed[SEED_LEN]; 77 78/* Default interface if no -I option given */ 79#define DEFAULT_IF "eth0" 80char *IfName = NULL; 81 82/* Access concentrator name */ 83char *ACName = NULL; 84 85/* Options to pass to pppoe process */ 86char PppoeOptions[SMALLBUF] = ""; 87 88/* Our local IP address */ 89unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1}; 90unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */ 91 92struct PPPoETag hostUniq; 93struct PPPoETag relayId; 94struct PPPoETag receivedCookie; 95struct PPPoETag requestedService; 96 97#define HOSTNAMELEN 256 98 99static void startPPPD(struct ClientSession *sess); 100static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest, 101 int errorTag, char *errorMsg); 102 103#define CHECK_ROOM(cursor, start, len) \ 104do {\ 105 if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \ 106 syslog(LOG_ERR, "Would create too-long packet"); \ 107 return; \ 108 } \ 109} while(0) 110 111/********************************************************************** 112*%FUNCTION: parsePADITags 113*%ARGUMENTS: 114* type -- tag type 115* len -- tag length 116* data -- tag data 117* extra -- extra user data. 118*%RETURNS: 119* Nothing 120*%DESCRIPTION: 121* Picks interesting tags out of a PADI packet 122***********************************************************************/ 123void 124parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data, 125 void *extra) 126{ 127 switch(type) { 128 case TAG_SERVICE_NAME: 129 /* Should do something -- currently ignored */ 130 break; 131 case TAG_RELAY_SESSION_ID: 132 relayId.type = htons(type); 133 relayId.length = htons(len); 134 memcpy(relayId.payload, data, len); 135 break; 136 case TAG_HOST_UNIQ: 137 hostUniq.type = htons(type); 138 hostUniq.length = htons(len); 139 memcpy(hostUniq.payload, data, len); 140 break; 141 } 142} 143 144/********************************************************************** 145*%FUNCTION: parsePADRTags 146*%ARGUMENTS: 147* type -- tag type 148* len -- tag length 149* data -- tag data 150* extra -- extra user data. 151*%RETURNS: 152* Nothing 153*%DESCRIPTION: 154* Picks interesting tags out of a PADR packet 155***********************************************************************/ 156void 157parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data, 158 void *extra) 159{ 160 switch(type) { 161 case TAG_RELAY_SESSION_ID: 162 relayId.type = htons(type); 163 relayId.length = htons(len); 164 memcpy(relayId.payload, data, len); 165 break; 166 case TAG_HOST_UNIQ: 167 hostUniq.type = htons(type); 168 hostUniq.length = htons(len); 169 memcpy(hostUniq.payload, data, len); 170 break; 171 case TAG_AC_COOKIE: 172 receivedCookie.type = htons(type); 173 receivedCookie.length = htons(len); 174 memcpy(receivedCookie.payload, data, len); 175 break; 176 case TAG_SERVICE_NAME: 177 requestedService.type = htons(type); 178 requestedService.length = htons(len); 179 memcpy(requestedService.payload, data, len); 180 break; 181 } 182} 183 184/********************************************************************** 185*%FUNCTION: findSession 186*%ARGUMENTS: 187* pid -- PID of child which owns session. If PID is 0, searches for 188* empty session slots. 189*%RETURNS: 190* A pointer to the session, or NULL if no such session found. 191*%DESCRIPTION: 192* Searches for specified session. 193**********************************************************************/ 194struct ClientSession * 195findSession(pid_t pid) 196{ 197 size_t i; 198 for (i=0; i<NumSessionSlots; i++) { 199 if (Sessions[i].pid == pid) { 200 return &Sessions[i]; 201 } 202 } 203 return NULL; 204} 205 206/********************************************************************** 207*%FUNCTION: reapSessions 208*%ARGUMENTS: 209* None 210*%RETURNS: 211* Nothing 212*%DESCRIPTION: 213* Reaps children which have exited and removes their sessions 214**********************************************************************/ 215void 216reapSessions(void) 217{ 218 int status; 219 pid_t pid; 220 struct ClientSession *session; 221 222 /* Clear pipe */ 223 char buf[SMALLBUF]; 224 read(Pipe[0], buf, SMALLBUF); 225 226 while((pid = waitpid(-1, &status, WNOHANG)) > 0) { 227 session = findSession(pid); 228 if (!session) { 229 syslog(LOG_ERR, "Child %d died but couldn't find session!", 230 (int) pid); 231 } else { 232 syslog(LOG_INFO, 233 "Session %d closed for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)", 234 session->sess, 235 session->eth[0], session->eth[1], session->eth[2], 236 session->eth[3], session->eth[4], session->eth[5], 237 (int) session->ip[0], (int) session->ip[1], 238 (int) session->ip[2], (int) session->ip[3]); 239 session->pid = 0; 240 } 241 } 242} 243 244/********************************************************************** 245*%FUNCTION: fatalSys 246*%ARGUMENTS: 247* str -- error message 248*%RETURNS: 249* Nothing 250*%DESCRIPTION: 251* Prints a message plus the errno value to stderr and syslog and exits. 252***********************************************************************/ 253void 254fatalSys(char const *str) 255{ 256 char buf[SMALLBUF]; 257 snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno)); 258 printErr(buf); 259 exit(1); 260} 261 262/********************************************************************** 263*%FUNCTION: fatal 264*%ARGUMENTS: 265* str -- error message 266*%RETURNS: 267* Nothing 268*%DESCRIPTION: 269* Prints a message to stderr and syslog and exits. 270***********************************************************************/ 271void 272fatal(char const *str) 273{ 274 printErr(str); 275 exit(1); 276} 277 278/********************************************************************** 279*%FUNCTION: genCookie 280*%ARGUMENTS: 281* peerEthAddr -- peer Ethernet address (6 bytes) 282* myEthAddr -- my Ethernet address (6 bytes) 283* seed -- random cookie seed to make things tasty (16 bytes) 284* cookie -- 16-byte buffer which is filled with md5 sum of previous items 285*%RETURNS: 286* Nothing 287*%DESCRIPTION: 288* Forms the md5 sum of peer MAC address, our MAC address and seed, useful 289* in a PPPoE Cookie tag. 290***********************************************************************/ 291void 292genCookie(unsigned char const *peerEthAddr, 293 unsigned char const *myEthAddr, 294 unsigned char const *seed, 295 unsigned char *cookie) 296{ 297 struct MD5Context ctx; 298 299 MD5Init(&ctx); 300 MD5Update(&ctx, peerEthAddr, ETH_ALEN); 301 MD5Update(&ctx, myEthAddr, ETH_ALEN); 302 MD5Update(&ctx, seed, SEED_LEN); 303 MD5Final(cookie, &ctx); 304} 305 306/********************************************************************** 307*%FUNCTION: processPADI 308*%ARGUMENTS: 309* sock -- Ethernet socket 310* myAddr -- my Ethernet address 311* packet -- PPPoE PADI packet 312* len -- length of received packet 313*%RETURNS: 314* Nothing 315*%DESCRIPTION: 316* Sends a PADO packet back to client 317***********************************************************************/ 318void 319processPADI(int sock, unsigned char *myAddr, 320 struct PPPoEPacket *packet, int len) 321{ 322 struct PPPoEPacket pado; 323 struct PPPoETag acname; 324 struct PPPoETag servname; 325 struct PPPoETag cookie; 326 size_t acname_len; 327 328 unsigned char *cursor = pado.payload; 329 UINT16_t plen; 330 331 acname.type = htons(TAG_AC_NAME); 332 acname_len = strlen(ACName); 333 acname.length = htons(acname_len); 334 memcpy(acname.payload, ACName, acname_len); 335 336 servname.type = htons(TAG_SERVICE_NAME); 337 servname.length = 0; 338 339 relayId.type = 0; 340 hostUniq.type = 0; 341 parsePacket(packet, parsePADITags, NULL); 342 343 /* Generate a cookie */ 344 cookie.type = htons(TAG_AC_COOKIE); 345 cookie.length = htons(16); /* MD5 output is 16 bytes */ 346 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload); 347 348 /* Construct a PADO packet */ 349 memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN); 350 memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN); 351 pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); 352 pado.ver = 1; 353 pado.type = 1; 354 pado.code = CODE_PADO; 355 pado.session = 0; 356 plen = TAG_HDR_SIZE + acname_len; 357 358 CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE); 359 memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE); 360 cursor += acname_len + TAG_HDR_SIZE; 361 362 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE); 363 memcpy(cursor, &servname, TAG_HDR_SIZE); 364 cursor += TAG_HDR_SIZE; 365 plen += TAG_HDR_SIZE; 366 367 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + 16); 368 memcpy(cursor, &cookie, TAG_HDR_SIZE + 16); 369 cursor += TAG_HDR_SIZE + 16; 370 plen += TAG_HDR_SIZE + 16; 371 372 if (relayId.type) { 373 CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE); 374 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE); 375 cursor += ntohs(relayId.length) + TAG_HDR_SIZE; 376 plen += ntohs(relayId.length) + TAG_HDR_SIZE; 377 } 378 if (hostUniq.type) { 379 CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE); 380 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE); 381 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE; 382 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE; 383 } 384 pado.length = htons(plen); 385 sendPacket(sock, &pado, (int) (plen + HDR_SIZE)); 386} 387 388/********************************************************************** 389*%FUNCTION: processPADR 390*%ARGUMENTS: 391* sock -- Ethernet socket 392* myAddr -- my Ethernet address 393* packet -- PPPoE PADR packet 394* len -- length of received packet 395*%RETURNS: 396* Nothing 397*%DESCRIPTION: 398* Sends a PADS packet back to client and starts a PPP session if PADR 399* packet is OK. 400***********************************************************************/ 401void 402processPADR(int sock, unsigned char *myAddr, 403 struct PPPoEPacket *packet, int len) 404{ 405 unsigned char cookieBuffer[16]; 406 struct ClientSession *cliSession; 407 pid_t child; 408 struct PPPoEPacket pads; 409 unsigned char *cursor = pads.payload; 410 UINT16_t plen; 411 struct PPPoETag servname; 412 413 /* Initialize some globals */ 414 relayId.type = 0; 415 hostUniq.type = 0; 416 receivedCookie.type = 0; 417 requestedService.type = 0; 418 419 parsePacket(packet, parsePADRTags, NULL); 420 421 /* Check that everything's cool */ 422 if (!receivedCookie.type) { 423 syslog(LOG_ERR, "Received PADR packet without cookie tag"); 424 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 425 TAG_GENERIC_ERROR, "No cookie. Me hungry!"); 426 return; 427 } 428 429 /* Is cookie kosher? */ 430 if (receivedCookie.length != htons(16)) { 431 syslog(LOG_ERR, "Received PADR packet with invalid cookie tag length"); 432 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 433 TAG_GENERIC_ERROR, "Cookie wrong size."); 434 return; 435 } 436 437 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer); 438 if (memcmp(receivedCookie.payload, cookieBuffer, 16)) { 439 syslog(LOG_ERR, "Received PADR packet with invalid cookie tag"); 440 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 441 TAG_GENERIC_ERROR, "Bad cookie. Me have tummy-ache."); 442 return; 443 } 444 445 /* Check service name -- we only offer service "" */ 446 if (!requestedService.type) { 447 syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag"); 448 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 449 TAG_SERVICE_NAME_ERROR, "No service name tag"); 450 return; 451 } 452 453 if (requestedService.length) { 454 syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload); 455 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 456 TAG_SERVICE_NAME_ERROR, "Invalid service name tag"); 457 return; 458 } 459 460 /* Looks cool... find a slot for the session */ 461 cliSession = findSession(0); 462 if (!cliSession) { 463 syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)", 464 (unsigned int) packet->ethHdr.h_source[0], 465 (unsigned int) packet->ethHdr.h_source[1], 466 (unsigned int) packet->ethHdr.h_source[2], 467 (unsigned int) packet->ethHdr.h_source[3], 468 (unsigned int) packet->ethHdr.h_source[4], 469 (unsigned int) packet->ethHdr.h_source[5]); 470 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 471 TAG_AC_SYSTEM_ERROR, "No client slots available"); 472 return; 473 } 474 475 /* Set up client session peer Ethernet address */ 476 memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN); 477 478 /* Create child process, send PADS packet back */ 479 child = fork(); 480 if (child < 0) { 481 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source, 482 TAG_AC_SYSTEM_ERROR, "Unable to start session process"); 483 return; 484 } 485 if (child != 0) { 486 /* In the parent process. Mark pid in session slot */ 487 cliSession->pid = child; 488 return; 489 } 490 491 /* In the child process. */ 492 493 /* pppd has a nasty habit of killing all processes in its process group. 494 Start a new session to stop pppd from killing us! */ 495 setsid(); 496 497 /* Send PADS and Start pppd */ 498 memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN); 499 memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN); 500 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); 501 pads.ver = 1; 502 pads.type = 1; 503 pads.code = CODE_PADS; 504 505 pads.session = htons(cliSession->sess); 506 plen = 0; 507 508 servname.type = htons(TAG_SERVICE_NAME); 509 servname.length = 0; 510 511 memcpy(cursor, &servname, TAG_HDR_SIZE); 512 cursor += TAG_HDR_SIZE; 513 plen += TAG_HDR_SIZE; 514 515 if (relayId.type) { 516 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE); 517 cursor += ntohs(relayId.length) + TAG_HDR_SIZE; 518 plen += ntohs(relayId.length) + TAG_HDR_SIZE; 519 } 520 if (hostUniq.type) { 521 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE); 522 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE; 523 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE; 524 } 525 pads.length = htons(plen); 526 sendPacket(sock, &pads, (int) (plen + HDR_SIZE)); 527 startPPPD(cliSession); 528} 529 530/********************************************************************** 531*%FUNCTION: childHandler 532*%ARGUMENTS: 533* sig -- signal number 534*%RETURNS: 535* Nothing 536*%DESCRIPTION: 537* Called by SIGCHLD. Writes one byte to Pipe to wake up the select 538* loop and cause reaping of dead sessions 539***********************************************************************/ 540void 541childHandler(int sig) 542{ 543 if (!ReapPending) { 544 ReapPending = 1; 545 write(Pipe[1], &ReapPending, 1); 546 } 547} 548 549/********************************************************************** 550*%FUNCTION: usage 551*%ARGUMENTS: 552* argv0 -- argv[0] from main 553*%RETURNS: 554* Nothing 555*%DESCRIPTION: 556* Prints usage instructions 557***********************************************************************/ 558void 559usage(char const *argv0) 560{ 561 fprintf(stderr, "Usage: %s [options]\n", argv0); 562 fprintf(stderr, "Options:\n"); 563#ifdef USE_BPF 564 fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n"); 565#else 566 fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n", 567 DEFAULT_IF); 568#endif 569 fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n"); 570 fprintf(stderr, " -C name -- Set access concentrator name.\n"); 571 fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n"); 572 fprintf(stderr, " -L ip -- Set local IP address.\n"); 573 fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n"); 574 fprintf(stderr, " -N num -- Allow 'num' concurrent sessions.\n"); 575 fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n"); 576 fprintf(stderr, " -s -- Use synchronous PPP mode.\n"); 577 fprintf(stderr, " -h -- Print usage information.\n\n"); 578 fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n", VERSION); 579 fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n"); 580 fprintf(stderr, "This is free software, and you are welcome to redistribute it\n"); 581 fprintf(stderr, "under the terms of the GNU General Public License, version 2\n"); 582 fprintf(stderr, "or (at your option) any later version.\n"); 583 fprintf(stderr, "http://www.roaringpenguin.com\n"); 584} 585 586/********************************************************************** 587*%FUNCTION: main 588*%ARGUMENTS: 589* argc, argv -- usual suspects 590*%RETURNS: 591* Exit status 592*%DESCRIPTION: 593* Main program of PPPoE server 594***********************************************************************/ 595int 596main(int argc, char **argv) 597{ 598 599 FILE *fp; 600 int i; 601 int opt; 602 unsigned char myAddr[ETH_ALEN]; 603 struct PPPoEPacket packet; 604 int len; 605 int sock; 606 int d[IPV4ALEN]; 607 int beDaemon = 1; 608 struct sigaction act; 609 int maxFD; 610 unsigned int discoveryType, sessionType; 611 612 /* Initialize syslog */ 613 openlog("pppoe-server", LOG_PID, LOG_DAEMON); 614 615 /* Default number of session slots */ 616 NumSessionSlots = DEFAULT_MAX_SESSIONS; 617 618 /* Parse command-line options */ 619 while((opt = getopt(argc, argv, "hI:C:L:R:T:m:FN:f:s")) != -1) { 620 switch(opt) { 621 case 's': 622 Synchronous = 1; 623 /* Pass the Synchronous option on to pppoe */ 624 snprintf(PppoeOptions + strlen(PppoeOptions), 625 SMALLBUF-strlen(PppoeOptions), 626 " -s"); 627 break; 628 case 'f': 629 if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) { 630 fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n"); 631 exit(1); 632 } 633 Eth_PPPOE_Discovery = (UINT16_t) discoveryType; 634 Eth_PPPOE_Session = (UINT16_t) sessionType; 635 /* This option gets passed to pppoe */ 636 snprintf(PppoeOptions + strlen(PppoeOptions), 637 SMALLBUF-strlen(PppoeOptions), 638 " -%c %s", opt, optarg); 639 break; 640 case 'F': 641 beDaemon = 0; 642 break; 643 case 'N': 644 if (sscanf(optarg, "%d", &opt) != 1) { 645 usage(argv[0]); 646 exit(1); 647 } 648 if (opt <= 0) { 649 fprintf(stderr, "-N: Value must be positive\n"); 650 exit(1); 651 } 652 NumSessionSlots = opt; 653 break; 654 655 case 'I': 656 SET_STRING(IfName, optarg); 657 break; 658 case 'C': 659 SET_STRING(ACName, optarg); 660 break; 661 case 'L': 662 case 'R': 663 /* Get local/remote IP address */ 664 if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) { 665 usage(argv[0]); 666 exit(1); 667 } 668 for (i=0; i<IPV4ALEN; i++) { 669 if (d[i] < 0 || d[i] > 255) { 670 usage(argv[0]); 671 exit(1); 672 } 673 if (opt == 'L') { 674 LocalIP[i] = (unsigned char) d[i]; 675 } else { 676 RemoteIP[i] = (unsigned char) d[i]; 677 } 678 } 679 break; 680 case 'T': 681 case 'm': 682 /* These just get passed to pppoe */ 683 snprintf(PppoeOptions + strlen(PppoeOptions), 684 SMALLBUF-strlen(PppoeOptions), 685 " -%c %s", opt, optarg); 686 break; 687 case 'h': 688 usage(argv[0]); 689 exit(0); 690 } 691 } 692 693 if (!IfName) { 694 IfName = DEFAULT_IF; 695 } 696 697 if (!ACName) { 698 ACName = malloc(HOSTNAMELEN); 699 if (gethostname(ACName, HOSTNAMELEN) < 0) { 700 fatalSys("gethostname"); 701 } 702 } 703 704 /* Allocate memory for sessions */ 705 Sessions = calloc(NumSessionSlots, sizeof(struct ClientSession)); 706 if (!Sessions) { 707 fatal("Cannot allocate memory for session slots"); 708 } 709 710 /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */ 711 if (beDaemon) { 712 i = fork(); 713 if (i < 0) { 714 fatalSys("fork"); 715 } else if (i != 0) { 716 /* parent */ 717 exit(0); 718 } 719 setsid(); 720 signal(SIGHUP, SIG_IGN); 721 i = fork(); 722 if (i < 0) { 723 fatalSys("fork"); 724 } else if (i != 0) { 725 exit(0); 726 } 727 728 chdir("/"); 729 closelog(); 730 for (i=0; i<CLOSEFD; i++) close(i); 731 /* We nuked our syslog descriptor... */ 732 openlog("pppoe-server", LOG_PID, LOG_DAEMON); 733 } 734 735 for(i=0; i<NumSessionSlots; i++) { 736 Sessions[i].pid = 0; 737 memcpy(Sessions[i].ip, RemoteIP, sizeof(RemoteIP)); 738 Sessions[i].sess = i+1; 739 740 /* Increment IP */ 741 RemoteIP[3]++; 742 if (!RemoteIP[3] || RemoteIP[3] == 255) { 743 RemoteIP[3] = 1; 744 RemoteIP[2]++; 745 if (!RemoteIP[2]) { 746 RemoteIP[1]++; 747 if (!RemoteIP[1]) { 748 RemoteIP[0]++; 749 } 750 } 751 } 752 } 753 754 /* Initialize our random cookie. Try /dev/urandom; if that fails, 755 use PID and rand() */ 756 fp = fopen("/dev/urandom", "r"); 757 if (fp) { 758 fread(&CookieSeed, 1, SEED_LEN, fp); 759 fclose(fp); 760 } else { 761 CookieSeed[0] = getpid() & 0xFF; 762 CookieSeed[1] = (getpid() >> 8) & 0xFF; 763 for (i=2; i<SEED_LEN; i++) { 764 CookieSeed[i] = (rand() >> (i % 9)) & 0xFF; 765 } 766 } 767 768 sock = openInterface(IfName, Eth_PPPOE_Discovery, myAddr); 769 770 /* Set signal handler for SIGCHLD */ 771 act.sa_handler = childHandler; 772 sigemptyset(&act.sa_mask); 773 act.sa_flags = SA_NOCLDSTOP | SA_RESTART; 774 if (sigaction(SIGCHLD, &act, NULL) < 0) { 775 fatalSys("sigaction"); 776 } 777 778 /* Set up pipe for signal handler */ 779 if (pipe(Pipe) < 0) { 780 fatalSys("pipe"); 781 } 782 783 /* Main server loop */ 784 maxFD = sock; 785 if (Pipe[0] > maxFD) maxFD = Pipe[0]; 786 maxFD++; 787 788 for(;;) { 789 fd_set readable; 790 FD_ZERO(&readable); 791 FD_SET(sock, &readable); 792 FD_SET(Pipe[0], &readable); 793 794 while(1) { 795 i = select(maxFD, &readable, NULL, NULL, NULL); 796 if (i >= 0 || errno != EINTR) break; 797 } 798 if (i < 0) { 799 fatalSys("select"); 800 } 801 802 if (ReapPending) { 803 ReapPending = 0; 804 reapSessions(); 805 } 806 if (!FD_ISSET(sock, &readable)) { 807 continue; 808 } 809 810 receivePacket(sock, &packet, &len); 811 812 /* Check length */ 813 if (ntohs(packet.length) + HDR_SIZE > len) { 814 syslog(LOG_ERR, "Bogus PPPoE length field"); 815 continue; 816 } 817 818 /* Sanity check on packet */ 819 if (packet.ver != 1 || packet.type != 1) { 820 /* Syslog an error */ 821 continue; 822 } 823 switch(packet.code) { 824 case CODE_PADI: 825 processPADI(sock, myAddr, &packet, len); 826 break; 827 case CODE_PADR: 828 processPADR(sock, myAddr, &packet, len); 829 break; 830 case CODE_PADT: 831 case CODE_SESS: 832 /* Ignore PADT and SESS -- children will handle them */ 833 break; 834 case CODE_PADO: 835 case CODE_PADS: 836 /* Ignore PADO and PADS totally */ 837 break; 838 default: 839 /* Syslog an error */ 840 break; 841 } 842 } 843 return 0; 844} 845 846/********************************************************************** 847*%FUNCTION: sendErrorPADS 848*%ARGUMENTS: 849* sock -- socket to write to 850* source -- source Ethernet address 851* dest -- destination Ethernet address 852* errorTag -- error tag 853* errorMsg -- error message 854*%RETURNS: 855* Nothing 856*%DESCRIPTION: 857* Sends a PADS packet with an error message 858***********************************************************************/ 859void 860sendErrorPADS(int sock, 861 unsigned char *source, 862 unsigned char *dest, 863 int errorTag, 864 char *errorMsg) 865{ 866 struct PPPoEPacket pads; 867 unsigned char *cursor = pads.payload; 868 UINT16_t plen; 869 struct PPPoETag err; 870 int elen = strlen(errorMsg); 871 872 memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN); 873 memcpy(pads.ethHdr.h_source, source, ETH_ALEN); 874 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery); 875 pads.ver = 1; 876 pads.type = 1; 877 pads.code = CODE_PADS; 878 879 pads.session = htons(0); 880 plen = 0; 881 882 err.type = htons(errorTag); 883 err.length = htons(elen); 884 885 memcpy(err.payload, errorMsg, elen); 886 memcpy(cursor, &err, TAG_HDR_SIZE+elen); 887 cursor += TAG_HDR_SIZE + elen; 888 plen += TAG_HDR_SIZE + elen; 889 890 if (relayId.type) { 891 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE); 892 cursor += ntohs(relayId.length) + TAG_HDR_SIZE; 893 plen += ntohs(relayId.length) + TAG_HDR_SIZE; 894 } 895 if (hostUniq.type) { 896 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE); 897 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE; 898 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE; 899 } 900 pads.length = htons(plen); 901 sendPacket(sock, &pads, (int) (plen + HDR_SIZE)); 902} 903 904 905/********************************************************************** 906*%FUNCTION: startPPPD 907*%ARGUMENTS: 908* session -- client session record 909*%RETURNS: 910* Nothing 911*%DESCRIPTION: 912* Starts PPPD 913***********************************************************************/ 914void 915startPPPD(struct ClientSession *session) 916{ 917 /* Leave some room */ 918 char *argv[20]; 919 920 char buffer[SMALLBUF]; 921 922 argv[0] = "pppd"; 923 argv[1] = "pty"; 924 925 snprintf(buffer, SMALLBUF, "%s -I %s -e %d:%02x:%02x:%02x:%02x:%02x:%02x%s", 926 PPPOE_PATH, IfName, 927 session->sess, 928 session->eth[0], session->eth[1], session->eth[2], 929 session->eth[3], session->eth[4], session->eth[5], 930 PppoeOptions); 931 argv[2] = strdup(buffer); 932 if (!argv[2]) { 933 /* TODO: Send a PADT */ 934 exit(1); 935 } 936 937 argv[3] = "file"; 938 argv[4] = PPPOE_SERVER_OPTIONS; 939 940 snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d", 941 (int) LocalIP[0], (int) LocalIP[1], 942 (int) LocalIP[2], (int) LocalIP[3], 943 (int) session->ip[0], (int) session->ip[1], 944 (int) session->ip[2], (int) session->ip[3]); 945 syslog(LOG_INFO, 946 "Session %d created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d)", 947 session->sess, 948 session->eth[0], session->eth[1], session->eth[2], 949 session->eth[3], session->eth[4], session->eth[5], 950 (int) session->ip[0], (int) session->ip[1], 951 (int) session->ip[2], (int) session->ip[3]); 952 argv[5] = buffer; /* No need for strdup -- about to execv! */ 953 argv[6] = "nodetach"; 954 argv[7] = "noaccomp"; 955 argv[8] = "nobsdcomp"; 956 argv[9] = "nodeflate"; 957 argv[10] = "nopcomp"; 958 argv[11] = "novj"; 959 argv[12] = "novjccomp"; 960 argv[13] = "default-asyncmap"; 961 if (Synchronous) { 962 argv[14] = "sync"; 963 argv[15] = NULL; 964 } else { 965 argv[14] = NULL; 966 } 967 968 execv(PPPD_PATH, argv); 969 exit(1); 970} 971