Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / rp-pppoe / src / pppoe-server.c
blob9b1f56d9c3b6cd1ce193b75dc8b80d4ba5568285
1 /***********************************************************************
3 * pppoe-server.c
5 * Implementation of a user-space PPPoE server
7 * Copyright (C) 2000-2012 Roaring Penguin Software Inc.
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.
12 * $Id$
14 * LIC: GPL
16 ***********************************************************************/
18 static char const RCSID[] =
19 "$Id$";
21 #include "config.h"
23 #if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
24 #define _POSIX_SOURCE 1 /* For sigaction defines */
25 #endif
27 #define _BSD_SOURCE 1 /* for gethostname */
29 #include "pppoe-server.h"
30 #include "md5.h"
32 #ifdef HAVE_SYSLOG_H
33 #include <syslog.h>
34 #endif
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <fcntl.h>
40 #include <sys/file.h>
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
46 #ifdef HAVE_GETOPT_H
47 #include <getopt.h>
48 #endif
50 #ifdef HAVE_SYS_WAIT_H
51 #include <sys/wait.h>
52 #endif
54 #ifdef HAVE_SYS_TIME_H
55 #include <sys/time.h>
56 #endif
58 #include <time.h>
60 #include <signal.h>
62 #ifdef HAVE_LICENSE
63 #include "license.h"
64 #include "licensed-only/servfuncs.h"
65 static struct License const *ServerLicense;
66 static struct License const *ClusterLicense;
67 #else
68 #define control_session_started(x) (void) 0
69 #define control_session_terminated(x) (void) 0
70 #define control_exit() (void) 0
71 #define realpeerip peerip
72 #endif
74 #ifdef HAVE_L2TP
75 extern PppoeSessionFunctionTable L2TPSessionFunctionTable;
76 extern void pppoe_to_l2tp_add_interface(EventSelector *es,
77 Interface *interface);
78 #endif
80 static void InterfaceHandler(EventSelector *es,
81 int fd, unsigned int flags, void *data);
82 static void startPPPD(ClientSession *sess);
83 static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest,
84 int errorTag, char *errorMsg);
86 #define CHECK_ROOM(cursor, start, len) \
87 do {\
88 if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
89 syslog(LOG_ERR, "Would create too-long packet"); \
90 return; \
91 } \
92 } while(0)
94 static void PppoeStopSession(ClientSession *ses, char const *reason);
95 static int PppoeSessionIsActive(ClientSession *ses);
97 /* Service-Names we advertise */
98 #define MAX_SERVICE_NAMES 64
99 static int NumServiceNames = 0;
100 static char const *ServiceNames[MAX_SERVICE_NAMES];
102 PppoeSessionFunctionTable DefaultSessionFunctionTable = {
103 PppoeStopSession,
104 PppoeSessionIsActive,
105 NULL
108 /* An array of client sessions */
109 ClientSession *Sessions = NULL;
110 ClientSession *FreeSessions = NULL;
111 ClientSession *LastFreeSession = NULL;
112 ClientSession *BusySessions = NULL;
114 /* Interfaces we're listening on */
115 Interface interfaces[MAX_INTERFACES];
116 int NumInterfaces = 0;
118 /* The number of session slots */
119 size_t NumSessionSlots;
121 /* Maximum number of sessions per MAC address */
122 int MaxSessionsPerMac;
124 /* Number of active sessions */
125 size_t NumActiveSessions = 0;
127 /* Offset of first session */
128 size_t SessOffset = 0;
130 /* Event Selector */
131 EventSelector *event_selector;
133 /* Use Linux kernel-mode PPPoE? */
134 static int UseLinuxKernelModePPPoE = 0;
136 /* Requested max_ppp_payload */
137 static UINT16_t max_ppp_payload = 0;
139 /* File with PPPD options */
140 static char *pppoptfile = NULL;
142 static char *pppd_path = PPPD_PATH;
143 static char *pppoe_path = PPPOE_PATH;
145 static int Debug = 0;
146 static int CheckPoolSyntax = 0;
148 /* Synchronous mode */
149 static int Synchronous = 0;
151 /* Ignore PADI if no free sessions */
152 static int IgnorePADIIfNoFreeSessions = 0;
154 static int KidPipe[2] = {-1, -1};
155 static int LockFD = -1;
157 /* Random seed for cookie generation */
158 #define SEED_LEN 16
159 #define MD5_LEN 16
160 #define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
162 static unsigned char CookieSeed[SEED_LEN];
164 #define MAXLINE 512
166 /* Default interface if no -I option given */
167 #define DEFAULT_IF "eth0"
169 /* Access concentrator name */
170 char *ACName = NULL;
172 /* Options to pass to pppoe process */
173 char PppoeOptions[SMALLBUF] = "";
175 /* Our local IP address */
176 unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1}; /* Counter optionally STARTS here */
177 unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
179 /* Do we increment local IP for each connection? */
180 int IncrLocalIP = 0;
182 /* Do we randomize session numbers? */
183 int RandomizeSessionNumbers = 0;
185 /* Do we pass the "unit" option to pppd? (2.4 or greater) */
186 int PassUnitOptionToPPPD = 0;
188 static PPPoETag hostUniq;
189 static PPPoETag relayId;
190 static PPPoETag receivedCookie;
191 static PPPoETag requestedService;
193 #define HOSTNAMELEN 256
195 static int
196 count_sessions_from_mac(unsigned char *eth)
198 int n=0;
199 ClientSession *s = BusySessions;
200 while(s) {
201 if (!memcmp(eth, s->eth, ETH_ALEN)) n++;
202 s = s->next;
204 return n;
207 /**********************************************************************
208 *%FUNCTION: childHandler
209 *%ARGUMENTS:
210 * pid -- pid of child
211 * status -- exit status
212 * ses -- which session terminated
213 *%RETURNS:
214 * Nothing
215 *%DESCRIPTION:
216 * Called synchronously when a child dies. Remove from busy list.
217 ***********************************************************************/
218 static void
219 childHandler(pid_t pid, int status, void *s)
221 ClientSession *session = s;
223 /* Temporary structure for sending PADT's. */
224 PPPoEConnection conn;
226 #ifdef HAVE_L2TP
227 /* We're acting as LAC, so when child exits, become a PPPoE <-> L2TP
228 relay */
229 if (session->flags & FLAG_ACT_AS_LAC) {
230 syslog(LOG_INFO, "Session %u for client "
231 "%02x:%02x:%02x:%02x:%02x:%02x handed off to LNS %s",
232 (unsigned int) ntohs(session->sess),
233 session->eth[0], session->eth[1], session->eth[2],
234 session->eth[3], session->eth[4], session->eth[5],
235 inet_ntoa(session->tunnel_endpoint.sin_addr));
236 session->pid = 0;
237 session->funcs = &L2TPSessionFunctionTable;
238 return;
240 #endif
242 memset(&conn, 0, sizeof(conn));
243 conn.useHostUniq = 0;
245 syslog(LOG_INFO,
246 "Session %u closed for client "
247 "%02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s",
248 (unsigned int) ntohs(session->sess),
249 session->eth[0], session->eth[1], session->eth[2],
250 session->eth[3], session->eth[4], session->eth[5],
251 (int) session->realpeerip[0], (int) session->realpeerip[1],
252 (int) session->realpeerip[2], (int) session->realpeerip[3],
253 session->ethif->name);
254 memcpy(conn.myEth, session->ethif->mac, ETH_ALEN);
255 conn.discoverySocket = session->ethif->sock;
256 conn.session = session->sess;
257 memcpy(conn.peerEth, session->eth, ETH_ALEN);
258 if (!(session->flags & FLAG_SENT_PADT)) {
259 if (session->flags & FLAG_RECVD_PADT) {
260 sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
261 } else {
262 sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
264 session->flags |= FLAG_SENT_PADT;
267 session->serviceName = "";
268 control_session_terminated(session);
269 if (pppoe_free_session(session) < 0) {
270 return;
275 /**********************************************************************
276 *%FUNCTION: incrementIPAddress (static)
277 *%ARGUMENTS:
278 * addr -- a 4-byte array representing IP address
279 *%RETURNS:
280 * Nothing
281 *%DESCRIPTION:
282 * Increments addr in-place
283 ***********************************************************************/
284 static void
285 incrementIPAddress(unsigned char ip[IPV4ALEN])
287 ip[3]++;
288 if (!ip[3]) {
289 ip[2]++;
290 if (!ip[2]) {
291 ip[1]++;
292 if (!ip[1]) {
293 ip[0]++;
299 /**********************************************************************
300 *%FUNCTION: killAllSessions
301 *%ARGUMENTS:
302 * None
303 *%RETURNS:
304 * Nothing
305 *%DESCRIPTION:
306 * Kills all pppd processes (and hence all PPPoE sessions)
307 ***********************************************************************/
308 void
309 killAllSessions(void)
311 ClientSession *sess = BusySessions;
312 while(sess) {
313 sess->funcs->stop(sess, "Shutting Down");
314 sess = sess->next;
316 #ifdef HAVE_L2TP
317 pppoe_close_l2tp_tunnels();
318 #endif
321 /**********************************************************************
322 *%FUNCTION: parseAddressPool
323 *%ARGUMENTS:
324 * fname -- name of file containing IP address pool.
325 * install -- if true, install IP addresses in sessions.
326 *%RETURNS:
327 * Number of valid IP addresses found.
328 *%DESCRIPTION:
329 * Reads a list of IP addresses from a file.
330 ***********************************************************************/
331 static int
332 parseAddressPool(char const *fname, int install)
334 FILE *fp = fopen(fname, "r");
335 int numAddrs = 0;
336 unsigned int a, b, c, d;
337 unsigned int e, f, g, h;
338 char line[MAXLINE];
340 if (!fp) {
341 sysErr("Cannot open address pool file");
342 exit(1);
345 while (!feof(fp)) {
346 if (!fgets(line, MAXLINE, fp)) {
347 break;
349 if ((sscanf(line, "%u.%u.%u.%u:%u.%u.%u.%u",
350 &a, &b, &c, &d, &e, &f, &g, &h) == 8) &&
351 a < 256 && b < 256 && c < 256 && d < 256 &&
352 e < 256 && f < 256 && g < 256 && h < 256) {
354 /* Both specified (local:remote) */
355 if (install) {
356 Sessions[numAddrs].myip[0] = (unsigned char) a;
357 Sessions[numAddrs].myip[1] = (unsigned char) b;
358 Sessions[numAddrs].myip[2] = (unsigned char) c;
359 Sessions[numAddrs].myip[3] = (unsigned char) d;
360 Sessions[numAddrs].peerip[0] = (unsigned char) e;
361 Sessions[numAddrs].peerip[1] = (unsigned char) f;
362 Sessions[numAddrs].peerip[2] = (unsigned char) g;
363 Sessions[numAddrs].peerip[3] = (unsigned char) h;
364 #ifdef HAVE_LICENSE
365 memcpy(Sessions[numAddrs].realpeerip,
366 Sessions[numAddrs].peerip, IPV4ALEN);
367 #endif
369 numAddrs++;
370 } else if ((sscanf(line, "%u.%u.%u.%u-%u", &a, &b, &c, &d, &e) == 5) &&
371 a < 256 && b < 256 && c < 256 && d < 256 && e < 256) {
372 /* Remote specied as a.b.c.d-e. Example: 1.2.3.4-8 yields:
373 1.2.3.4, 1.2.3.5, 1.2.3.6, 1.2.3.7, 1.2.3.8 */
374 /* Swap d and e so that e >= d */
375 if (e < d) {
376 f = d;
377 d = e;
378 e = f;
380 if (install) {
381 while (d <= e) {
382 Sessions[numAddrs].peerip[0] = (unsigned char) a;
383 Sessions[numAddrs].peerip[1] = (unsigned char) b;
384 Sessions[numAddrs].peerip[2] = (unsigned char) c;
385 Sessions[numAddrs].peerip[3] = (unsigned char) d;
386 #ifdef HAVE_LICENSE
387 memcpy(Sessions[numAddrs].realpeerip,
388 Sessions[numAddrs].peerip, IPV4ALEN);
389 #endif
390 d++;
391 numAddrs++;
393 } else {
394 numAddrs += (e-d) + 1;
396 } else if ((sscanf(line, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
397 a < 256 && b < 256 && c < 256 && d < 256) {
398 /* Only remote specified */
399 if (install) {
400 Sessions[numAddrs].peerip[0] = (unsigned char) a;
401 Sessions[numAddrs].peerip[1] = (unsigned char) b;
402 Sessions[numAddrs].peerip[2] = (unsigned char) c;
403 Sessions[numAddrs].peerip[3] = (unsigned char) d;
404 #ifdef HAVE_LICENSE
405 memcpy(Sessions[numAddrs].realpeerip,
406 Sessions[numAddrs].peerip, IPV4ALEN);
407 #endif
409 numAddrs++;
412 fclose(fp);
413 if (!numAddrs) {
414 rp_fatal("No valid ip addresses found in pool file");
416 return numAddrs;
419 /**********************************************************************
420 *%FUNCTION: parsePADITags
421 *%ARGUMENTS:
422 * type -- tag type
423 * len -- tag length
424 * data -- tag data
425 * extra -- extra user data.
426 *%RETURNS:
427 * Nothing
428 *%DESCRIPTION:
429 * Picks interesting tags out of a PADI packet
430 ***********************************************************************/
431 void
432 parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data,
433 void *extra)
435 switch(type) {
436 case TAG_PPP_MAX_PAYLOAD:
437 if (len == sizeof(max_ppp_payload)) {
438 memcpy(&max_ppp_payload, data, sizeof(max_ppp_payload));
439 max_ppp_payload = ntohs(max_ppp_payload);
440 if (max_ppp_payload <= ETH_PPPOE_MTU) {
441 max_ppp_payload = 0;
444 break;
445 case TAG_SERVICE_NAME:
446 /* Copy requested service name */
447 requestedService.type = htons(type);
448 requestedService.length = htons(len);
449 memcpy(requestedService.payload, data, len);
450 break;
451 case TAG_RELAY_SESSION_ID:
452 relayId.type = htons(type);
453 relayId.length = htons(len);
454 memcpy(relayId.payload, data, len);
455 break;
456 case TAG_HOST_UNIQ:
457 hostUniq.type = htons(type);
458 hostUniq.length = htons(len);
459 memcpy(hostUniq.payload, data, len);
460 break;
464 /**********************************************************************
465 *%FUNCTION: parsePADRTags
466 *%ARGUMENTS:
467 * type -- tag type
468 * len -- tag length
469 * data -- tag data
470 * extra -- extra user data.
471 *%RETURNS:
472 * Nothing
473 *%DESCRIPTION:
474 * Picks interesting tags out of a PADR packet
475 ***********************************************************************/
476 void
477 parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
478 void *extra)
480 switch(type) {
481 case TAG_PPP_MAX_PAYLOAD:
482 if (len == sizeof(max_ppp_payload)) {
483 memcpy(&max_ppp_payload, data, sizeof(max_ppp_payload));
484 max_ppp_payload = ntohs(max_ppp_payload);
485 if (max_ppp_payload <= ETH_PPPOE_MTU) {
486 max_ppp_payload = 0;
489 break;
490 case TAG_RELAY_SESSION_ID:
491 relayId.type = htons(type);
492 relayId.length = htons(len);
493 memcpy(relayId.payload, data, len);
494 break;
495 case TAG_HOST_UNIQ:
496 hostUniq.type = htons(type);
497 hostUniq.length = htons(len);
498 memcpy(hostUniq.payload, data, len);
499 break;
500 case TAG_AC_COOKIE:
501 receivedCookie.type = htons(type);
502 receivedCookie.length = htons(len);
503 memcpy(receivedCookie.payload, data, len);
504 break;
505 case TAG_SERVICE_NAME:
506 requestedService.type = htons(type);
507 requestedService.length = htons(len);
508 memcpy(requestedService.payload, data, len);
509 break;
513 /**********************************************************************
514 *%FUNCTION: fatalSys
515 *%ARGUMENTS:
516 * str -- error message
517 *%RETURNS:
518 * Nothing
519 *%DESCRIPTION:
520 * Prints a message plus the errno value to stderr and syslog and exits.
521 ***********************************************************************/
522 void
523 fatalSys(char const *str)
525 char buf[SMALLBUF];
526 snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno));
527 printErr(buf);
528 control_exit();
529 exit(EXIT_FAILURE);
532 /**********************************************************************
533 *%FUNCTION: sysErr
534 *%ARGUMENTS:
535 * str -- error message
536 *%RETURNS:
537 * Nothing
538 *%DESCRIPTION:
539 * Prints a message plus the errno value to syslog.
540 ***********************************************************************/
541 void
542 sysErr(char const *str)
544 char buf[1024];
545 sprintf(buf, "%.256s: %.256s", str, strerror(errno));
546 printErr(buf);
549 /**********************************************************************
550 *%FUNCTION: rp_fatal
551 *%ARGUMENTS:
552 * str -- error message
553 *%RETURNS:
554 * Nothing
555 *%DESCRIPTION:
556 * Prints a message to stderr and syslog and exits.
557 ***********************************************************************/
558 void
559 rp_fatal(char const *str)
561 printErr(str);
562 control_exit();
563 exit(EXIT_FAILURE);
566 /**********************************************************************
567 *%FUNCTION: genCookie
568 *%ARGUMENTS:
569 * peerEthAddr -- peer Ethernet address (6 bytes)
570 * myEthAddr -- my Ethernet address (6 bytes)
571 * seed -- random cookie seed to make things tasty (16 bytes)
572 * cookie -- buffer which is filled with server PID and
573 * md5 sum of previous items
574 *%RETURNS:
575 * Nothing
576 *%DESCRIPTION:
577 * Forms the md5 sum of peer MAC address, our MAC address and seed, useful
578 * in a PPPoE Cookie tag.
579 ***********************************************************************/
580 void
581 genCookie(unsigned char const *peerEthAddr,
582 unsigned char const *myEthAddr,
583 unsigned char const *seed,
584 unsigned char *cookie)
586 struct MD5Context ctx;
587 pid_t pid = getpid();
589 MD5Init(&ctx);
590 MD5Update(&ctx, peerEthAddr, ETH_ALEN);
591 MD5Update(&ctx, myEthAddr, ETH_ALEN);
592 MD5Update(&ctx, seed, SEED_LEN);
593 MD5Final(cookie, &ctx);
594 memcpy(cookie+MD5_LEN, &pid, sizeof(pid));
597 /**********************************************************************
598 *%FUNCTION: processPADI
599 *%ARGUMENTS:
600 * ethif -- Interface
601 * packet -- PPPoE PADI packet
602 * len -- length of received packet
603 *%RETURNS:
604 * Nothing
605 *%DESCRIPTION:
606 * Sends a PADO packet back to client
607 ***********************************************************************/
608 void
609 processPADI(Interface *ethif, PPPoEPacket *packet, int len)
611 PPPoEPacket pado;
612 PPPoETag acname;
613 PPPoETag servname;
614 PPPoETag cookie;
615 size_t acname_len;
616 unsigned char *cursor = pado.payload;
617 UINT16_t plen;
619 int sock = ethif->sock;
620 int i;
621 int ok = 0;
622 unsigned char *myAddr = ethif->mac;
624 /* Ignore PADI's which don't come from a unicast address */
625 if (NOT_UNICAST(packet->ethHdr.h_source)) {
626 syslog(LOG_ERR, "PADI packet from non-unicast source address");
627 return;
630 /* If no free sessions and "-i" flag given, ignore */
631 if (IgnorePADIIfNoFreeSessions && !FreeSessions) {
632 syslog(LOG_INFO, "PADI ignored - No free session slots available");
633 return;
636 /* If number of sessions per MAC is limited, check here and don't
637 send PADO if already max number of sessions. */
638 if (MaxSessionsPerMac) {
639 if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
640 syslog(LOG_INFO, "PADI: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
641 packet->ethHdr.h_source[0],
642 packet->ethHdr.h_source[1],
643 packet->ethHdr.h_source[2],
644 packet->ethHdr.h_source[3],
645 packet->ethHdr.h_source[4],
646 packet->ethHdr.h_source[5],
647 MaxSessionsPerMac);
648 return;
652 acname.type = htons(TAG_AC_NAME);
653 acname_len = strlen(ACName);
654 acname.length = htons(acname_len);
655 memcpy(acname.payload, ACName, acname_len);
657 relayId.type = 0;
658 hostUniq.type = 0;
659 requestedService.type = 0;
660 max_ppp_payload = 0;
662 parsePacket(packet, parsePADITags, NULL);
664 /* If PADI specified non-default service name, and we do not offer
665 that service, DO NOT send PADO */
666 if (requestedService.type) {
667 int slen = ntohs(requestedService.length);
668 if (slen) {
669 for (i=0; i<NumServiceNames; i++) {
670 if (slen == strlen(ServiceNames[i]) &&
671 !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
672 ok = 1;
673 break;
676 } else {
677 ok = 1; /* Default service requested */
679 } else {
680 ok = 1; /* No Service-Name tag in PADI */
683 if (!ok) {
684 /* PADI asked for unsupported service */
685 return;
688 /* Generate a cookie */
689 cookie.type = htons(TAG_AC_COOKIE);
690 cookie.length = htons(COOKIE_LEN);
691 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
693 /* Construct a PADO packet */
694 memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
695 memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);
696 pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
697 pado.ver = 1;
698 pado.type = 1;
699 pado.code = CODE_PADO;
700 pado.session = 0;
701 plen = TAG_HDR_SIZE + acname_len;
703 CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);
704 memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE);
705 cursor += acname_len + TAG_HDR_SIZE;
707 /* If we asked for an MTU, handle it */
708 if (max_ppp_payload > ETH_PPPOE_MTU && ethif->mtu > 0) {
709 /* Shrink payload to fit */
710 if (max_ppp_payload > ethif->mtu - TOTAL_OVERHEAD) {
711 max_ppp_payload = ethif->mtu - TOTAL_OVERHEAD;
713 if (max_ppp_payload > ETH_JUMBO_LEN - TOTAL_OVERHEAD) {
714 max_ppp_payload = ETH_JUMBO_LEN - TOTAL_OVERHEAD;
716 if (max_ppp_payload > ETH_PPPOE_MTU) {
717 PPPoETag maxPayload;
718 UINT16_t mru = htons(max_ppp_payload);
719 maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
720 maxPayload.length = htons(sizeof(mru));
721 memcpy(maxPayload.payload, &mru, sizeof(mru));
722 CHECK_ROOM(cursor, pado.payload, sizeof(mru) + TAG_HDR_SIZE);
723 memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
724 cursor += sizeof(mru) + TAG_HDR_SIZE;
725 plen += sizeof(mru) + TAG_HDR_SIZE;
728 /* If no service-names specified on command-line, just send default
729 zero-length name. Otherwise, add all service-name tags */
730 servname.type = htons(TAG_SERVICE_NAME);
731 if (!NumServiceNames) {
732 servname.length = 0;
733 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
734 memcpy(cursor, &servname, TAG_HDR_SIZE);
735 cursor += TAG_HDR_SIZE;
736 plen += TAG_HDR_SIZE;
737 } else {
738 for (i=0; i<NumServiceNames; i++) {
739 int slen = strlen(ServiceNames[i]);
740 servname.length = htons(slen);
741 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE+slen);
742 memcpy(cursor, &servname, TAG_HDR_SIZE);
743 memcpy(cursor+TAG_HDR_SIZE, ServiceNames[i], slen);
744 cursor += TAG_HDR_SIZE+slen;
745 plen += TAG_HDR_SIZE+slen;
749 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
750 memcpy(cursor, &cookie, TAG_HDR_SIZE + COOKIE_LEN);
751 cursor += TAG_HDR_SIZE + COOKIE_LEN;
752 plen += TAG_HDR_SIZE + COOKIE_LEN;
754 if (relayId.type) {
755 CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);
756 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
757 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
758 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
760 if (hostUniq.type) {
761 CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);
762 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
763 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
764 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
766 pado.length = htons(plen);
767 sendPacket(NULL, sock, &pado, (int) (plen + HDR_SIZE));
770 /**********************************************************************
771 *%FUNCTION: processPADT
772 *%ARGUMENTS:
773 * ethif -- interface
774 * packet -- PPPoE PADT packet
775 * len -- length of received packet
776 *%RETURNS:
777 * Nothing
778 *%DESCRIPTION:
779 * Kills session whose session-ID is in PADT packet.
780 ***********************************************************************/
781 void
782 processPADT(Interface *ethif, PPPoEPacket *packet, int len)
784 size_t i;
786 unsigned char *myAddr = ethif->mac;
788 /* Ignore PADT's not directed at us */
789 if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
791 /* Get session's index */
792 i = ntohs(packet->session) - 1 - SessOffset;
793 if (i >= NumSessionSlots) return;
794 if (Sessions[i].sess != packet->session) {
795 syslog(LOG_ERR, "Session index %u doesn't match session number %u",
796 (unsigned int) i, (unsigned int) ntohs(packet->session));
797 return;
801 /* If source MAC does not match, do not kill session */
802 if (memcmp(packet->ethHdr.h_source, Sessions[i].eth, ETH_ALEN)) {
803 syslog(LOG_WARNING, "PADT for session %u received from "
804 "%02X:%02X:%02X:%02X:%02X:%02X; should be from "
805 "%02X:%02X:%02X:%02X:%02X:%02X",
806 (unsigned int) ntohs(packet->session),
807 packet->ethHdr.h_source[0],
808 packet->ethHdr.h_source[1],
809 packet->ethHdr.h_source[2],
810 packet->ethHdr.h_source[3],
811 packet->ethHdr.h_source[4],
812 packet->ethHdr.h_source[5],
813 Sessions[i].eth[0],
814 Sessions[i].eth[1],
815 Sessions[i].eth[2],
816 Sessions[i].eth[3],
817 Sessions[i].eth[4],
818 Sessions[i].eth[5]);
819 return;
821 Sessions[i].flags |= FLAG_RECVD_PADT;
822 parsePacket(packet, parseLogErrs, NULL);
823 Sessions[i].funcs->stop(&Sessions[i], "Received PADT");
826 /**********************************************************************
827 *%FUNCTION: processPADR
828 *%ARGUMENTS:
829 * ethif -- Ethernet interface
830 * packet -- PPPoE PADR packet
831 * len -- length of received packet
832 *%RETURNS:
833 * Nothing
834 *%DESCRIPTION:
835 * Sends a PADS packet back to client and starts a PPP session if PADR
836 * packet is OK.
837 ***********************************************************************/
838 void
839 processPADR(Interface *ethif, PPPoEPacket *packet, int len)
841 unsigned char cookieBuffer[COOKIE_LEN];
842 ClientSession *cliSession;
843 pid_t child;
844 PPPoEPacket pads;
845 unsigned char *cursor = pads.payload;
846 UINT16_t plen;
847 int i;
848 int sock = ethif->sock;
849 unsigned char *myAddr = ethif->mac;
850 int slen = 0;
851 char const *serviceName = NULL;
853 #ifdef HAVE_LICENSE
854 int freemem;
855 #endif
857 /* Initialize some globals */
858 relayId.type = 0;
859 hostUniq.type = 0;
860 receivedCookie.type = 0;
861 requestedService.type = 0;
863 /* Ignore PADR's not directed at us */
864 if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
866 /* Ignore PADR's from non-unicast addresses */
867 if (NOT_UNICAST(packet->ethHdr.h_source)) {
868 syslog(LOG_ERR, "PADR packet from non-unicast source address");
869 return;
872 /* If number of sessions per MAC is limited, check here and don't
873 send PADS if already max number of sessions. */
874 if (MaxSessionsPerMac) {
875 if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
876 syslog(LOG_INFO, "PADR: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
877 packet->ethHdr.h_source[0],
878 packet->ethHdr.h_source[1],
879 packet->ethHdr.h_source[2],
880 packet->ethHdr.h_source[3],
881 packet->ethHdr.h_source[4],
882 packet->ethHdr.h_source[5],
883 MaxSessionsPerMac);
884 return;
888 max_ppp_payload = 0;
889 parsePacket(packet, parsePADRTags, NULL);
891 /* Check that everything's cool */
892 if (!receivedCookie.type) {
893 /* Drop it -- do not send error PADS */
894 return;
897 /* Is cookie kosher? */
898 if (receivedCookie.length != htons(COOKIE_LEN)) {
899 /* Drop it -- do not send error PADS */
900 return;
903 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);
904 if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {
905 /* Drop it -- do not send error PADS */
906 return;
909 /* Check service name */
910 if (!requestedService.type) {
911 syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");
912 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
913 TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");
914 return;
917 slen = ntohs(requestedService.length);
918 if (slen) {
919 /* Check supported services */
920 for(i=0; i<NumServiceNames; i++) {
921 if (slen == strlen(ServiceNames[i]) &&
922 !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
923 serviceName = ServiceNames[i];
924 break;
928 if (!serviceName) {
929 syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);
930 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
931 TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");
932 return;
934 } else {
935 serviceName = "";
939 #ifdef HAVE_LICENSE
940 /* Are we licensed for this many sessions? */
941 if (License_NumLicenses("PPPOE-SESSIONS") <= NumActiveSessions) {
942 syslog(LOG_ERR, "Insufficient session licenses (%02x:%02x:%02x:%02x:%02x:%02x)",
943 (unsigned int) packet->ethHdr.h_source[0],
944 (unsigned int) packet->ethHdr.h_source[1],
945 (unsigned int) packet->ethHdr.h_source[2],
946 (unsigned int) packet->ethHdr.h_source[3],
947 (unsigned int) packet->ethHdr.h_source[4],
948 (unsigned int) packet->ethHdr.h_source[5]);
949 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
950 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No session licenses available");
951 return;
953 #endif
954 /* Enough free memory? */
955 #ifdef HAVE_LICENSE
956 freemem = getFreeMem();
957 if (freemem < MIN_FREE_MEMORY) {
958 syslog(LOG_WARNING,
959 "Insufficient free memory to create session: Want %d, have %d",
960 MIN_FREE_MEMORY, freemem);
961 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
962 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Insufficient free RAM");
963 return;
965 #endif
966 /* Looks cool... find a slot for the session */
967 cliSession = pppoe_alloc_session();
968 if (!cliSession) {
969 syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",
970 (unsigned int) packet->ethHdr.h_source[0],
971 (unsigned int) packet->ethHdr.h_source[1],
972 (unsigned int) packet->ethHdr.h_source[2],
973 (unsigned int) packet->ethHdr.h_source[3],
974 (unsigned int) packet->ethHdr.h_source[4],
975 (unsigned int) packet->ethHdr.h_source[5]);
976 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
977 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");
978 return;
981 /* Set up client session peer Ethernet address */
982 memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);
983 cliSession->ethif = ethif;
984 cliSession->flags = 0;
985 cliSession->funcs = &DefaultSessionFunctionTable;
986 cliSession->startTime = time(NULL);
987 cliSession->serviceName = serviceName;
989 /* Create child process, send PADS packet back */
990 child = fork();
991 if (child < 0) {
992 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
993 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");
994 pppoe_free_session(cliSession);
995 return;
997 if (child != 0) {
998 /* In the parent process. Mark pid in session slot */
999 cliSession->pid = child;
1000 Event_HandleChildExit(event_selector, child,
1001 childHandler, cliSession);
1002 control_session_started(cliSession);
1003 return;
1006 /* In the child process */
1008 /* Reset signal handlers to default */
1009 signal(SIGTERM, SIG_DFL);
1010 signal(SIGINT, SIG_DFL);
1012 /* Close all file descriptors except for socket */
1013 closelog();
1014 if (LockFD >= 0) close(LockFD);
1015 for (i=0; i<CLOSEFD; i++) {
1016 if (i != sock) {
1017 close(i);
1021 openlog("pppoe-server", LOG_PID, LOG_DAEMON);
1022 /* pppd has a nasty habit of killing all processes in its process group.
1023 Start a new session to stop pppd from killing us! */
1024 setsid();
1026 /* Send PADS and Start pppd */
1027 memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
1028 memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);
1029 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
1030 pads.ver = 1;
1031 pads.type = 1;
1032 pads.code = CODE_PADS;
1034 pads.session = cliSession->sess;
1035 plen = 0;
1037 /* Copy requested service name tag back in. If requested-service name
1038 length is zero, and we have non-zero services, use first service-name
1039 as default */
1040 if (!slen && NumServiceNames) {
1041 slen = strlen(ServiceNames[0]);
1042 memcpy(&requestedService.payload, ServiceNames[0], slen);
1043 requestedService.length = htons(slen);
1045 memcpy(cursor, &requestedService, TAG_HDR_SIZE+slen);
1046 cursor += TAG_HDR_SIZE+slen;
1047 plen += TAG_HDR_SIZE+slen;
1049 /* If we asked for an MTU, handle it */
1050 if (max_ppp_payload > ETH_PPPOE_MTU && ethif->mtu > 0) {
1051 /* Shrink payload to fit */
1052 if (max_ppp_payload > ethif->mtu - TOTAL_OVERHEAD) {
1053 max_ppp_payload = ethif->mtu - TOTAL_OVERHEAD;
1055 if (max_ppp_payload > ETH_JUMBO_LEN - TOTAL_OVERHEAD) {
1056 max_ppp_payload = ETH_JUMBO_LEN - TOTAL_OVERHEAD;
1058 if (max_ppp_payload > ETH_PPPOE_MTU) {
1059 PPPoETag maxPayload;
1060 UINT16_t mru = htons(max_ppp_payload);
1061 maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
1062 maxPayload.length = htons(sizeof(mru));
1063 memcpy(maxPayload.payload, &mru, sizeof(mru));
1064 CHECK_ROOM(cursor, pads.payload, sizeof(mru) + TAG_HDR_SIZE);
1065 memcpy(cursor, &maxPayload, sizeof(mru) + TAG_HDR_SIZE);
1066 cursor += sizeof(mru) + TAG_HDR_SIZE;
1067 plen += sizeof(mru) + TAG_HDR_SIZE;
1068 cliSession->requested_mtu = max_ppp_payload;
1072 if (relayId.type) {
1073 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
1074 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
1075 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
1077 if (hostUniq.type) {
1078 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
1079 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1080 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1082 pads.length = htons(plen);
1083 sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
1085 /* Close sock; don't need it any more */
1086 close(sock);
1088 startPPPD(cliSession);
1091 /**********************************************************************
1092 *%FUNCTION: termHandler
1093 *%ARGUMENTS:
1094 * sig -- signal number
1095 *%RETURNS:
1096 * Nothing
1097 *%DESCRIPTION:
1098 * Called by SIGTERM or SIGINT. Causes all sessions to be killed!
1099 ***********************************************************************/
1100 static void
1101 termHandler(int sig)
1103 syslog(LOG_INFO,
1104 "Terminating on signal %d -- killing all PPPoE sessions",
1105 sig);
1106 killAllSessions();
1107 control_exit();
1108 exit(0);
1111 /**********************************************************************
1112 *%FUNCTION: usage
1113 *%ARGUMENTS:
1114 * argv0 -- argv[0] from main
1115 *%RETURNS:
1116 * Nothing
1117 *%DESCRIPTION:
1118 * Prints usage instructions
1119 ***********************************************************************/
1120 void
1121 usage(char const *argv0)
1123 fprintf(stderr, "Usage: %s [options]\n", argv0);
1124 fprintf(stderr, "Options:\n");
1125 #ifdef USE_BPF
1126 fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
1127 #else
1128 fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
1129 DEFAULT_IF);
1130 #endif
1131 fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
1132 fprintf(stderr, " -C name -- Set access concentrator name.\n");
1133 fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
1134 fprintf(stderr, " -L ip -- Set local IP address.\n");
1135 fprintf(stderr, " -l -- Increment local IP address for each session.\n");
1136 fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n");
1137 fprintf(stderr, " -S name -- Advertise specified service-name.\n");
1138 fprintf(stderr, " -O fname -- Use PPPD options from specified file\n");
1139 fprintf(stderr, " (default %s).\n", PPPOE_SERVER_OPTIONS);
1140 fprintf(stderr, " -p fname -- Optain IP address pool from specified file.\n");
1141 fprintf(stderr, " -N num -- Allow 'num' concurrent sessions.\n");
1142 fprintf(stderr, " -o offset -- Assign session numbers starting at offset+1.\n");
1143 fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
1144 fprintf(stderr, " -s -- Use synchronous PPP mode.\n");
1145 fprintf(stderr, " -X pidfile -- Write PID and lock pidfile.\n");
1146 fprintf(stderr, " -q /path/pppd -- Specify full path to pppd.\n");
1147 fprintf(stderr, " -Q /path/pppoe -- Specify full path to pppoe.\n");
1148 #ifdef HAVE_LINUX_KERNEL_PPPOE
1149 fprintf(stderr, " -k -- Use kernel-mode PPPoE.\n");
1150 #endif
1151 fprintf(stderr, " -u -- Pass 'unit' option to pppd.\n");
1152 fprintf(stderr, " -r -- Randomize session numbers.\n");
1153 fprintf(stderr, " -d -- Debug session creation.\n");
1154 fprintf(stderr, " -x n -- Limit to 'n' sessions/MAC address.\n");
1155 fprintf(stderr, " -P -- Check pool file for correctness and exit.\n");
1156 #ifdef HAVE_LICENSE
1157 fprintf(stderr, " -c secret:if:port -- Enable clustering on interface 'if'.\n");
1158 fprintf(stderr, " -1 -- Allow only one session per user.\n");
1159 #endif
1161 fprintf(stderr, " -i -- Ignore PADI if no free sessions.\n");
1162 fprintf(stderr, " -h -- Print usage information.\n\n");
1163 fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001-2009 Roaring Penguin Software Inc.\n", VERSION);
1165 #ifndef HAVE_LICENSE
1166 fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");
1167 fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
1168 fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");
1169 fprintf(stderr, "or (at your option) any later version.\n");
1170 #endif
1171 fprintf(stderr, "http://www.roaringpenguin.com\n");
1174 /**********************************************************************
1175 *%FUNCTION: main
1176 *%ARGUMENTS:
1177 * argc, argv -- usual suspects
1178 *%RETURNS:
1179 * Exit status
1180 *%DESCRIPTION:
1181 * Main program of PPPoE server
1182 ***********************************************************************/
1184 main(int argc, char **argv)
1187 FILE *fp;
1188 int i, j;
1189 int opt;
1190 int d[IPV4ALEN];
1191 int beDaemon = 1;
1192 int found;
1193 unsigned int discoveryType, sessionType;
1194 char *addressPoolFname = NULL;
1195 char *pidfile = NULL;
1196 char c;
1198 #ifdef HAVE_LICENSE
1199 int use_clustering = 0;
1200 #endif
1202 #ifndef HAVE_LINUX_KERNEL_PPPOE
1203 char *options = "X:ix:hI:C:L:R:T:m:FN:f:O:o:sp:lrudPc:S:1q:Q:";
1204 #else
1205 char *options = "X:ix:hI:C:L:R:T:m:FN:f:O:o:skp:lrudPc:S:1q:Q:";
1206 #endif
1208 if (getuid() != geteuid() ||
1209 getgid() != getegid()) {
1210 fprintf(stderr, "SECURITY WARNING: pppoe-server will NOT run suid or sgid. Fix your installation.\n");
1211 exit(1);
1214 memset(interfaces, 0, sizeof(interfaces));
1216 /* Initialize syslog */
1217 openlog("pppoe-server", LOG_PID, LOG_DAEMON);
1219 /* Default number of session slots */
1220 NumSessionSlots = DEFAULT_MAX_SESSIONS;
1221 MaxSessionsPerMac = 0; /* No limit */
1222 NumActiveSessions = 0;
1224 /* Parse command-line options */
1225 while((opt = getopt(argc, argv, options)) != -1) {
1226 switch(opt) {
1227 case 'i':
1228 IgnorePADIIfNoFreeSessions = 1;
1229 break;
1230 case 'x':
1231 if (sscanf(optarg, "%d", &MaxSessionsPerMac) != 1) {
1232 usage(argv[0]);
1233 exit(EXIT_FAILURE);
1235 if (MaxSessionsPerMac < 0) {
1236 MaxSessionsPerMac = 0;
1238 break;
1240 #ifdef HAVE_LINUX_KERNEL_PPPOE
1241 case 'k':
1242 UseLinuxKernelModePPPoE = 1;
1243 break;
1244 #endif
1245 case 'S':
1246 if (NumServiceNames == MAX_SERVICE_NAMES) {
1247 fprintf(stderr, "Too many '-S' options (%d max)",
1248 MAX_SERVICE_NAMES);
1249 exit(1);
1251 ServiceNames[NumServiceNames] = strdup(optarg);
1252 if (!ServiceNames[NumServiceNames]) {
1253 fprintf(stderr, "Out of memory");
1254 exit(1);
1256 NumServiceNames++;
1257 break;
1258 case 'q':
1259 pppd_path = strdup(optarg);
1260 if (!pppd_path) {
1261 fprintf(stderr, "Out of memory");
1262 exit(1);
1264 break;
1265 case 'Q':
1266 pppoe_path = strdup(optarg);
1267 if (!pppoe_path) {
1268 fprintf(stderr, "Out of memory");
1269 exit(1);
1271 break;
1273 case 'c':
1274 #ifndef HAVE_LICENSE
1275 fprintf(stderr, "Clustering capability not available.\n");
1276 exit(1);
1277 #else
1278 cluster_handle_option(optarg);
1279 use_clustering = 1;
1280 break;
1281 #endif
1283 case 'd':
1284 Debug = 1;
1285 break;
1286 case 'P':
1287 CheckPoolSyntax = 1;
1288 break;
1289 case 'u':
1290 PassUnitOptionToPPPD = 1;
1291 break;
1293 case 'r':
1294 RandomizeSessionNumbers = 1;
1295 break;
1297 case 'l':
1298 IncrLocalIP = 1;
1299 break;
1301 case 'p':
1302 SET_STRING(addressPoolFname, optarg);
1303 break;
1305 case 'X':
1306 SET_STRING(pidfile, optarg);
1307 break;
1308 case 's':
1309 Synchronous = 1;
1310 /* Pass the Synchronous option on to pppoe */
1311 snprintf(PppoeOptions + strlen(PppoeOptions),
1312 SMALLBUF-strlen(PppoeOptions),
1313 " -s");
1314 break;
1316 case 'f':
1317 if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
1318 fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
1319 exit(EXIT_FAILURE);
1321 Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
1322 Eth_PPPOE_Session = (UINT16_t) sessionType;
1323 /* This option gets passed to pppoe */
1324 snprintf(PppoeOptions + strlen(PppoeOptions),
1325 SMALLBUF-strlen(PppoeOptions),
1326 " -%c %s", opt, optarg);
1327 break;
1329 case 'F':
1330 beDaemon = 0;
1331 break;
1333 case 'N':
1334 if (sscanf(optarg, "%d", &opt) != 1) {
1335 usage(argv[0]);
1336 exit(EXIT_FAILURE);
1338 if (opt <= 0) {
1339 fprintf(stderr, "-N: Value must be positive\n");
1340 exit(EXIT_FAILURE);
1342 NumSessionSlots = opt;
1343 break;
1345 case 'O':
1346 SET_STRING(pppoptfile, optarg);
1347 break;
1349 case 'o':
1350 if (sscanf(optarg, "%d", &opt) != 1) {
1351 usage(argv[0]);
1352 exit(EXIT_FAILURE);
1354 if (opt < 0) {
1355 fprintf(stderr, "-o: Value must be non-negative\n");
1356 exit(EXIT_FAILURE);
1358 SessOffset = (size_t) opt;
1359 break;
1361 case 'I':
1362 if (NumInterfaces >= MAX_INTERFACES) {
1363 fprintf(stderr, "Too many -I options (max %d)\n",
1364 MAX_INTERFACES);
1365 exit(EXIT_FAILURE);
1367 found = 0;
1368 for (i=0; i<NumInterfaces; i++) {
1369 if (!strncmp(interfaces[i].name, optarg, IFNAMSIZ)) {
1370 found = 1;
1371 break;
1374 if (!found) {
1375 strncpy(interfaces[NumInterfaces].name, optarg, IFNAMSIZ);
1376 NumInterfaces++;
1378 break;
1380 case 'C':
1381 SET_STRING(ACName, optarg);
1382 break;
1384 case 'L':
1385 case 'R':
1386 /* Get local/remote IP address */
1387 if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) {
1388 usage(argv[0]);
1389 exit(EXIT_FAILURE);
1391 for (i=0; i<IPV4ALEN; i++) {
1392 if (d[i] < 0 || d[i] > 255) {
1393 usage(argv[0]);
1394 exit(EXIT_FAILURE);
1396 if (opt == 'L') {
1397 LocalIP[i] = (unsigned char) d[i];
1398 } else {
1399 RemoteIP[i] = (unsigned char) d[i];
1402 break;
1404 case 'T':
1405 case 'm':
1406 /* These just get passed to pppoe */
1407 snprintf(PppoeOptions + strlen(PppoeOptions),
1408 SMALLBUF-strlen(PppoeOptions),
1409 " -%c %s", opt, optarg);
1410 break;
1412 case 'h':
1413 usage(argv[0]);
1414 exit(EXIT_SUCCESS);
1415 case '1':
1416 #ifdef HAVE_LICENSE
1417 MaxSessionsPerUser = 1;
1418 #else
1419 fprintf(stderr, "-1 option not valid.\n");
1420 exit(1);
1421 #endif
1422 break;
1426 if (!pppoptfile) {
1427 pppoptfile = PPPOE_SERVER_OPTIONS;
1430 #ifdef HAVE_LICENSE
1431 License_SetVersion(SERVPOET_VERSION);
1432 License_ReadBundleFile("/etc/rp/bundle.txt");
1433 License_ReadFile("/etc/rp/license.txt");
1434 ServerLicense = License_GetFeature("PPPOE-SERVER");
1435 if (!ServerLicense) {
1436 fprintf(stderr, "License: GetFeature failed: %s\n",
1437 License_ErrorMessage());
1438 exit(1);
1440 #endif
1442 #ifdef USE_LINUX_PACKET
1443 #ifndef HAVE_STRUCT_SOCKADDR_LL
1444 fprintf(stderr, "The PPPoE server does not work on Linux 2.0 kernels.\n");
1445 exit(EXIT_FAILURE);
1446 #endif
1447 #endif
1449 if (!NumInterfaces) {
1450 strcpy(interfaces[0].name, DEFAULT_IF);
1451 NumInterfaces = 1;
1454 if (!ACName) {
1455 ACName = malloc(HOSTNAMELEN);
1456 if (gethostname(ACName, HOSTNAMELEN) < 0) {
1457 fatalSys("gethostname");
1461 /* If address pool filename given, count number of addresses */
1462 if (addressPoolFname) {
1463 NumSessionSlots = parseAddressPool(addressPoolFname, 0);
1464 if (CheckPoolSyntax) {
1465 printf("%lu\n", (unsigned long) NumSessionSlots);
1466 exit(0);
1470 /* Max 65534 - SessOffset sessions */
1471 if (NumSessionSlots + SessOffset > 65534) {
1472 fprintf(stderr, "-N and -o options must add up to at most 65534\n");
1473 exit(EXIT_FAILURE);
1476 /* Allocate memory for sessions */
1477 Sessions = calloc(NumSessionSlots, sizeof(ClientSession));
1478 if (!Sessions) {
1479 rp_fatal("Cannot allocate memory for session slots");
1482 /* Fill in local addresses first (let pool file override later */
1483 for (i=0; i<NumSessionSlots; i++) {
1484 memcpy(Sessions[i].myip, LocalIP, sizeof(LocalIP));
1485 if (IncrLocalIP) {
1486 incrementIPAddress(LocalIP);
1490 /* Fill in remote IP addresses from pool (may also overwrite local ips) */
1491 if (addressPoolFname) {
1492 (void) parseAddressPool(addressPoolFname, 1);
1495 /* For testing -- generate sequential remote IP addresses */
1496 for (i=0; i<NumSessionSlots; i++) {
1497 Sessions[i].pid = 0;
1498 Sessions[i].funcs = &DefaultSessionFunctionTable;
1499 Sessions[i].sess = htons(i+1+SessOffset);
1501 if (!addressPoolFname) {
1502 memcpy(Sessions[i].peerip, RemoteIP, sizeof(RemoteIP));
1503 #ifdef HAVE_LICENSE
1504 memcpy(Sessions[i].realpeerip, RemoteIP, sizeof(RemoteIP));
1505 #endif
1506 incrementIPAddress(RemoteIP);
1510 /* Initialize our random cookie. Try /dev/urandom; if that fails,
1511 use PID and rand() */
1512 fp = fopen("/dev/urandom", "r");
1513 if (fp) {
1514 unsigned int x;
1515 fread(&x, 1, sizeof(x), fp);
1516 srand(x);
1517 fread(&CookieSeed, 1, SEED_LEN, fp);
1518 fclose(fp);
1519 } else {
1520 srand((unsigned int) getpid() * (unsigned int) time(NULL));
1521 CookieSeed[0] = getpid() & 0xFF;
1522 CookieSeed[1] = (getpid() >> 8) & 0xFF;
1523 for (i=2; i<SEED_LEN; i++) {
1524 CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
1528 if (RandomizeSessionNumbers) {
1529 int *permutation;
1530 int tmp;
1531 permutation = malloc(sizeof(int) * NumSessionSlots);
1532 if (!permutation) {
1533 fprintf(stderr, "Could not allocate memory to randomize session numbers\n");
1534 exit(EXIT_FAILURE);
1536 for (i=0; i<NumSessionSlots; i++) {
1537 permutation[i] = i;
1539 for (i=0; i<NumSessionSlots-1; i++) {
1540 j = i + rand() % (NumSessionSlots - i);
1541 if (j != i) {
1542 tmp = permutation[j];
1543 permutation[j] = permutation[i];
1544 permutation[i] = tmp;
1547 /* Link sessions together */
1548 FreeSessions = &Sessions[permutation[0]];
1549 LastFreeSession = &Sessions[permutation[NumSessionSlots-1]];
1550 for (i=0; i<NumSessionSlots-1; i++) {
1551 Sessions[permutation[i]].next = &Sessions[permutation[i+1]];
1553 Sessions[permutation[NumSessionSlots-1]].next = NULL;
1554 free(permutation);
1555 } else {
1556 /* Link sessions together */
1557 FreeSessions = &Sessions[0];
1558 LastFreeSession = &Sessions[NumSessionSlots - 1];
1559 for (i=0; i<NumSessionSlots-1; i++) {
1560 Sessions[i].next = &Sessions[i+1];
1562 Sessions[NumSessionSlots-1].next = NULL;
1565 if (Debug) {
1566 /* Dump session array and exit */
1567 ClientSession *ses = FreeSessions;
1568 while(ses) {
1569 printf("Session %u local %d.%d.%d.%d remote %d.%d.%d.%d\n",
1570 (unsigned int) (ntohs(ses->sess)),
1571 ses->myip[0], ses->myip[1],
1572 ses->myip[2], ses->myip[3],
1573 ses->peerip[0], ses->peerip[1],
1574 ses->peerip[2], ses->peerip[3]);
1575 ses = ses->next;
1577 exit(0);
1580 /* Open all the interfaces */
1581 for (i=0; i<NumInterfaces; i++) {
1582 interfaces[i].mtu = 0;
1583 interfaces[i].sock = openInterface(interfaces[i].name, Eth_PPPOE_Discovery, interfaces[i].mac, &interfaces[i].mtu);
1586 /* Ignore SIGPIPE */
1587 signal(SIGPIPE, SIG_IGN);
1589 /* Create event selector */
1590 event_selector = Event_CreateSelector();
1591 if (!event_selector) {
1592 rp_fatal("Could not create EventSelector -- probably out of memory");
1595 /* Control channel */
1596 #ifdef HAVE_LICENSE
1597 if (control_init(argc, argv, event_selector)) {
1598 rp_fatal("control_init failed");
1600 #endif
1602 /* Create event handler for each interface */
1603 for (i = 0; i<NumInterfaces; i++) {
1604 interfaces[i].eh = Event_AddHandler(event_selector,
1605 interfaces[i].sock,
1606 EVENT_FLAG_READABLE,
1607 InterfaceHandler,
1608 &interfaces[i]);
1609 #ifdef HAVE_L2TP
1610 interfaces[i].session_sock = -1;
1611 #endif
1612 if (!interfaces[i].eh) {
1613 rp_fatal("Event_AddHandler failed");
1617 #ifdef HAVE_LICENSE
1618 if (use_clustering) {
1619 ClusterLicense = License_GetFeature("PPPOE-CLUSTER");
1620 if (!ClusterLicense) {
1621 fprintf(stderr, "License: GetFeature failed: %s\n",
1622 License_ErrorMessage());
1623 exit(1);
1625 if (!License_Expired(ClusterLicense)) {
1626 if (cluster_init(event_selector) < 0) {
1627 rp_fatal("cluster_init failed");
1631 #endif
1633 #ifdef HAVE_L2TP
1634 for (i=0; i<NumInterfaces; i++) {
1635 pppoe_to_l2tp_add_interface(event_selector,
1636 &interfaces[i]);
1638 #endif
1640 /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
1641 if (beDaemon) {
1642 if (pipe(KidPipe) < 0) {
1643 fatalSys("pipe");
1645 i = fork();
1646 if (i < 0) {
1647 fatalSys("fork");
1648 } else if (i != 0) {
1649 /* parent */
1650 close(KidPipe[1]);
1651 KidPipe[1] = -1;
1652 /* Wait for child to give the go-ahead */
1653 while(1) {
1654 int r = read(KidPipe[0], &c, 1);
1655 if (r == 0) {
1656 fprintf(stderr, "EOF from child - something went wrong; please check logs.\n");
1657 exit(EXIT_FAILURE);
1659 if (r < 0) {
1660 if (errno == EINTR) continue;
1661 fatalSys("read");
1663 break;
1666 if (c == 'X') {
1667 exit(EXIT_SUCCESS);
1670 /* Read error message from child */
1671 while (1) {
1672 int r = read(KidPipe[0], &c, 1);
1673 if (r == 0) exit(EXIT_FAILURE);
1674 if (r < 0) {
1675 if (errno == EINTR) continue;
1676 fatalSys("read");
1678 fprintf(stderr, "%c", c);
1680 exit(EXIT_FAILURE);
1682 setsid();
1683 signal(SIGHUP, SIG_IGN);
1684 i = fork();
1685 if (i < 0) {
1686 fatalSys("fork");
1687 } else if (i != 0) {
1688 exit(EXIT_SUCCESS);
1691 chdir("/");
1693 if (KidPipe[0] >= 0) {
1694 close(KidPipe[0]);
1695 KidPipe[0] = -1;
1698 /* Point stdin/stdout/stderr to /dev/null */
1699 for (i=0; i<3; i++) {
1700 close(i);
1702 i = open("/dev/null", O_RDWR);
1703 if (i >= 0) {
1704 dup2(i, 0);
1705 dup2(i, 1);
1706 dup2(i, 2);
1707 if (i > 2) close(i);
1711 if (pidfile) {
1712 FILE *foo = NULL;
1713 if (KidPipe[1] >= 0) foo = fdopen(KidPipe[1], "w");
1714 struct flock fl;
1715 char buf[64];
1716 fl.l_type = F_WRLCK;
1717 fl.l_whence = SEEK_SET;
1718 fl.l_start = 0;
1719 fl.l_len = 0;
1720 LockFD = open(pidfile, O_RDWR|O_CREAT, 0666);
1721 if (LockFD < 0) {
1722 syslog(LOG_INFO, "Could not open PID file %s: %s", pidfile, strerror(errno));
1723 if (foo) fprintf(foo, "ECould not open PID file %s: %s\n", pidfile, strerror(errno));
1724 exit(1);
1726 if (fcntl(LockFD, F_SETLK, &fl) < 0) {
1727 syslog(LOG_INFO, "Could not lock PID file %s: Is another process running?", pidfile);
1728 if (foo) fprintf(foo, "ECould not lock PID file %s: Is another process running?\n", pidfile);
1729 exit(1);
1731 ftruncate(LockFD, 0);
1732 snprintf(buf, sizeof(buf), "%lu\n", (unsigned long) getpid());
1733 write(LockFD, buf, strlen(buf));
1734 /* Do not close fd... use it to retain lock */
1737 /* Set signal handlers for SIGTERM and SIGINT */
1738 if (Event_HandleSignal(event_selector, SIGTERM, termHandler) < 0 ||
1739 Event_HandleSignal(event_selector, SIGINT, termHandler) < 0) {
1740 fatalSys("Event_HandleSignal");
1743 /* Tell parent all is cool */
1744 if (KidPipe[1] >= 0) {
1745 write(KidPipe[1], "X", 1);
1746 close(KidPipe[1]);
1747 KidPipe[1] = -1;
1750 for(;;) {
1751 i = Event_HandleEvent(event_selector);
1752 if (i < 0) {
1753 fatalSys("Event_HandleEvent");
1756 #ifdef HAVE_LICENSE
1757 if (License_Expired(ServerLicense)) {
1758 syslog(LOG_INFO, "Server license has expired -- killing all PPPoE sessions");
1759 killAllSessions();
1760 control_exit();
1761 exit(0);
1763 #endif
1765 return 0;
1768 void
1769 serverProcessPacket(Interface *i)
1771 int len;
1772 PPPoEPacket packet;
1773 int sock = i->sock;
1775 if (receivePacket(sock, &packet, &len) < 0) {
1776 return;
1779 if (len < HDR_SIZE) {
1780 /* Impossible - ignore */
1781 return;
1784 /* Sanity check on packet */
1785 if (packet.ver != 1 || packet.type != 1) {
1786 /* Syslog an error */
1787 return;
1790 /* Check length */
1791 if (ntohs(packet.length) + HDR_SIZE > len) {
1792 syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
1793 (unsigned int) ntohs(packet.length));
1794 return;
1797 switch(packet.code) {
1798 case CODE_PADI:
1799 processPADI(i, &packet, len);
1800 break;
1801 case CODE_PADR:
1802 processPADR(i, &packet, len);
1803 break;
1804 case CODE_PADT:
1805 /* Kill the child */
1806 processPADT(i, &packet, len);
1807 break;
1808 case CODE_SESS:
1809 /* Ignore SESS -- children will handle them */
1810 break;
1811 case CODE_PADO:
1812 case CODE_PADS:
1813 /* Ignore PADO and PADS totally */
1814 break;
1815 default:
1816 /* Syslog an error */
1817 break;
1821 /**********************************************************************
1822 *%FUNCTION: sendErrorPADS
1823 *%ARGUMENTS:
1824 * sock -- socket to write to
1825 * source -- source Ethernet address
1826 * dest -- destination Ethernet address
1827 * errorTag -- error tag
1828 * errorMsg -- error message
1829 *%RETURNS:
1830 * Nothing
1831 *%DESCRIPTION:
1832 * Sends a PADS packet with an error message
1833 ***********************************************************************/
1834 void
1835 sendErrorPADS(int sock,
1836 unsigned char *source,
1837 unsigned char *dest,
1838 int errorTag,
1839 char *errorMsg)
1841 PPPoEPacket pads;
1842 unsigned char *cursor = pads.payload;
1843 UINT16_t plen;
1844 PPPoETag err;
1845 int elen = strlen(errorMsg);
1847 memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
1848 memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
1849 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
1850 pads.ver = 1;
1851 pads.type = 1;
1852 pads.code = CODE_PADS;
1854 pads.session = htons(0);
1855 plen = 0;
1857 err.type = htons(errorTag);
1858 err.length = htons(elen);
1860 memcpy(err.payload, errorMsg, elen);
1861 memcpy(cursor, &err, TAG_HDR_SIZE+elen);
1862 cursor += TAG_HDR_SIZE + elen;
1863 plen += TAG_HDR_SIZE + elen;
1865 if (relayId.type) {
1866 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
1867 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
1868 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
1870 if (hostUniq.type) {
1871 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
1872 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1873 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1875 pads.length = htons(plen);
1876 sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
1880 /**********************************************************************
1881 *%FUNCTION: startPPPDUserMode
1882 *%ARGUMENTS:
1883 * session -- client session record
1884 *%RETURNS:
1885 * Nothing
1886 *%DESCRIPTION:
1887 * Starts PPPD for user-mode PPPoE
1888 ***********************************************************************/
1889 void
1890 startPPPDUserMode(ClientSession *session)
1892 /* Leave some room */
1893 char *argv[64];
1895 char buffer[SMALLBUF];
1897 int c = 0;
1899 argv[c++] = "pppd";
1900 argv[c++] = "pty";
1902 /* Let's hope service-name does not have ' in it... */
1903 snprintf(buffer, SMALLBUF, "%s -n -I %s -e %u:%02x:%02x:%02x:%02x:%02x:%02x%s -S '%s'",
1904 pppoe_path, session->ethif->name,
1905 (unsigned int) ntohs(session->sess),
1906 session->eth[0], session->eth[1], session->eth[2],
1907 session->eth[3], session->eth[4], session->eth[5],
1908 PppoeOptions, session->serviceName);
1909 argv[c++] = strdup(buffer);
1910 if (!argv[c-1]) {
1911 /* TODO: Send a PADT */
1912 exit(EXIT_FAILURE);
1915 argv[c++] = "file";
1916 argv[c++] = pppoptfile;
1918 snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
1919 (int) session->myip[0], (int) session->myip[1],
1920 (int) session->myip[2], (int) session->myip[3],
1921 (int) session->peerip[0], (int) session->peerip[1],
1922 (int) session->peerip[2], (int) session->peerip[3]);
1923 syslog(LOG_INFO,
1924 "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
1925 (unsigned int) ntohs(session->sess),
1926 session->eth[0], session->eth[1], session->eth[2],
1927 session->eth[3], session->eth[4], session->eth[5],
1928 (int) session->peerip[0], (int) session->peerip[1],
1929 (int) session->peerip[2], (int) session->peerip[3],
1930 session->ethif->name,
1931 session->serviceName);
1932 argv[c++] = strdup(buffer);
1933 if (!argv[c-1]) {
1934 /* TODO: Send a PADT */
1935 exit(EXIT_FAILURE);
1937 argv[c++] = "nodetach";
1938 argv[c++] = "noaccomp";
1939 argv[c++] = "nopcomp";
1940 argv[c++] = "default-asyncmap";
1941 if (Synchronous) {
1942 argv[c++] = "sync";
1944 if (PassUnitOptionToPPPD) {
1945 argv[c++] = "unit";
1946 sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
1947 argv[c++] = buffer;
1949 if (session->requested_mtu > 1492) {
1950 sprintf(buffer, "%u", (unsigned int) session->requested_mtu);
1951 argv[c++] = "mru";
1952 argv[c++] = buffer;
1953 argv[c++] = "mtu";
1954 argv[c++] = buffer;
1955 } else {
1956 argv[c++] = "mru";
1957 argv[c++] = "1492";
1958 argv[c++] = "mtu";
1959 argv[c++] = "1492";
1962 argv[c++] = NULL;
1964 execv(pppd_path, argv);
1965 exit(EXIT_FAILURE);
1968 /**********************************************************************
1969 *%FUNCTION: startPPPDLinuxKernelMode
1970 *%ARGUMENTS:
1971 * session -- client session record
1972 *%RETURNS:
1973 * Nothing
1974 *%DESCRIPTION:
1975 * Starts PPPD for kernel-mode PPPoE on Linux
1976 ***********************************************************************/
1977 void
1978 startPPPDLinuxKernelMode(ClientSession *session)
1980 /* Leave some room */
1981 char *argv[32];
1983 int c = 0;
1985 char buffer[SMALLBUF];
1987 argv[c++] = "pppd";
1988 argv[c++] = "plugin";
1989 argv[c++] = PLUGIN_PATH;
1991 /* Add "nic-" to interface name */
1992 snprintf(buffer, SMALLBUF, "nic-%s", session->ethif->name);
1993 argv[c++] = strdup(buffer);
1994 if (!argv[c-1]) {
1995 exit(EXIT_FAILURE);
1998 snprintf(buffer, SMALLBUF, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
1999 (unsigned int) ntohs(session->sess),
2000 session->eth[0], session->eth[1], session->eth[2],
2001 session->eth[3], session->eth[4], session->eth[5]);
2002 argv[c++] = "rp_pppoe_sess";
2003 argv[c++] = strdup(buffer);
2004 if (!argv[c-1]) {
2005 /* TODO: Send a PADT */
2006 exit(EXIT_FAILURE);
2008 argv[c++] = "rp_pppoe_service";
2009 argv[c++] = (char *) session->serviceName;
2010 argv[c++] = "file";
2011 argv[c++] = pppoptfile;
2013 snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
2014 (int) session->myip[0], (int) session->myip[1],
2015 (int) session->myip[2], (int) session->myip[3],
2016 (int) session->peerip[0], (int) session->peerip[1],
2017 (int) session->peerip[2], (int) session->peerip[3]);
2018 syslog(LOG_INFO,
2019 "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
2020 (unsigned int) ntohs(session->sess),
2021 session->eth[0], session->eth[1], session->eth[2],
2022 session->eth[3], session->eth[4], session->eth[5],
2023 (int) session->peerip[0], (int) session->peerip[1],
2024 (int) session->peerip[2], (int) session->peerip[3],
2025 session->ethif->name,
2026 session->serviceName);
2027 argv[c++] = strdup(buffer);
2028 if (!argv[c-1]) {
2029 /* TODO: Send a PADT */
2030 exit(EXIT_FAILURE);
2032 argv[c++] = "nodetach";
2033 argv[c++] = "noaccomp";
2034 argv[c++] = "nopcomp";
2035 argv[c++] = "default-asyncmap";
2036 if (PassUnitOptionToPPPD) {
2037 argv[c++] = "unit";
2038 sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
2039 argv[c++] = buffer;
2041 if (session->requested_mtu > 1492) {
2042 sprintf(buffer, "%u", (unsigned int) session->requested_mtu);
2043 argv[c++] = "mru";
2044 argv[c++] = buffer;
2045 argv[c++] = "mtu";
2046 argv[c++] = buffer;
2047 } else {
2048 argv[c++] = "mru";
2049 argv[c++] = "1492";
2050 argv[c++] = "mtu";
2051 argv[c++] = "1492";
2053 argv[c++] = NULL;
2054 execv(pppd_path, argv);
2055 exit(EXIT_FAILURE);
2058 /**********************************************************************
2059 *%FUNCTION: startPPPD
2060 *%ARGUMENTS:
2061 * session -- client session record
2062 *%RETURNS:
2063 * Nothing
2064 *%DESCRIPTION:
2065 * Starts PPPD
2066 ***********************************************************************/
2067 void
2068 startPPPD(ClientSession *session)
2070 if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
2071 else startPPPDUserMode(session);
2074 /**********************************************************************
2075 * %FUNCTION: InterfaceHandler
2076 * %ARGUMENTS:
2077 * es -- event selector (ignored)
2078 * fd -- file descriptor which is readable
2079 * flags -- ignored
2080 * data -- Pointer to the Interface structure
2081 * %RETURNS:
2082 * Nothing
2083 * %DESCRIPTION:
2084 * Handles a packet ready at an interface
2085 ***********************************************************************/
2086 void
2087 InterfaceHandler(EventSelector *es,
2088 int fd,
2089 unsigned int flags,
2090 void *data)
2092 serverProcessPacket((Interface *) data);
2095 /**********************************************************************
2096 * %FUNCTION: PppoeStopSession
2097 * %ARGUMENTS:
2098 * ses -- the session
2099 * reason -- reason session is being stopped.
2100 * %RETURNS:
2101 * Nothing
2102 * %DESCRIPTION:
2103 * Kills pppd.
2104 ***********************************************************************/
2105 static void
2106 PppoeStopSession(ClientSession *ses,
2107 char const *reason)
2109 /* Temporary structure for sending PADT's. */
2110 PPPoEConnection conn;
2112 memset(&conn, 0, sizeof(conn));
2113 conn.useHostUniq = 0;
2115 memcpy(conn.myEth, ses->ethif->mac, ETH_ALEN);
2116 conn.discoverySocket = ses->ethif->sock;
2117 conn.session = ses->sess;
2118 memcpy(conn.peerEth, ses->eth, ETH_ALEN);
2119 sendPADT(&conn, reason);
2120 ses->flags |= FLAG_SENT_PADT;
2122 if (ses->pid) {
2123 kill(ses->pid, SIGTERM);
2125 ses->funcs = &DefaultSessionFunctionTable;
2128 /**********************************************************************
2129 * %FUNCTION: PppoeSessionIsActive
2130 * %ARGUMENTS:
2131 * ses -- the session
2132 * %RETURNS:
2133 * True if session is active, false if not.
2134 ***********************************************************************/
2135 static int
2136 PppoeSessionIsActive(ClientSession *ses)
2138 return (ses->pid != 0);
2141 #ifdef HAVE_LICENSE
2142 /**********************************************************************
2143 * %FUNCTION: getFreeMem
2144 * %ARGUMENTS:
2145 * None
2146 * %RETURNS:
2147 * The amount of free RAM in kilobytes, or -1 if it could not be
2148 * determined
2149 * %DESCRIPTION:
2150 * Reads Linux-specific /proc/meminfo file and extracts free RAM
2151 ***********************************************************************/
2153 getFreeMem(void)
2155 char buf[512];
2156 int memfree=0, buffers=0, cached=0;
2157 FILE *fp = fopen("/proc/meminfo", "r");
2158 if (!fp) return -1;
2160 while (fgets(buf, sizeof(buf), fp)) {
2161 if (!strncmp(buf, "MemFree:", 8)) {
2162 if (sscanf(buf, "MemFree: %d", &memfree) != 1) {
2163 fclose(fp);
2164 return -1;
2166 } else if (!strncmp(buf, "Buffers:", 8)) {
2167 if (sscanf(buf, "Buffers: %d", &buffers) != 1) {
2168 fclose(fp);
2169 return -1;
2171 } else if (!strncmp(buf, "Cached:", 7)) {
2172 if (sscanf(buf, "Cached: %d", &cached) != 1) {
2173 fclose(fp);
2174 return -1;
2178 fclose(fp);
2179 /* return memfree + buffers + cached; */
2180 return memfree;
2182 #endif
2184 /**********************************************************************
2185 * %FUNCTION: pppoe_alloc_session
2186 * %ARGUMENTS:
2187 * None
2188 * %RETURNS:
2189 * NULL if no session is available, otherwise a ClientSession structure.
2190 * %DESCRIPTION:
2191 * Allocates a ClientSession structure and removes from free list, puts
2192 * on busy list
2193 ***********************************************************************/
2194 ClientSession *
2195 pppoe_alloc_session(void)
2197 ClientSession *ses = FreeSessions;
2198 if (!ses) return NULL;
2200 /* Remove from free sessions list */
2201 if (ses == LastFreeSession) {
2202 LastFreeSession = NULL;
2204 FreeSessions = ses->next;
2206 /* Put on busy sessions list */
2207 ses->next = BusySessions;
2208 BusySessions = ses;
2210 /* Initialize fields to sane values */
2211 ses->funcs = &DefaultSessionFunctionTable;
2212 ses->pid = 0;
2213 ses->ethif = NULL;
2214 memset(ses->eth, 0, ETH_ALEN);
2215 ses->flags = 0;
2216 ses->startTime = time(NULL);
2217 ses->serviceName = "";
2218 ses->requested_mtu = 0;
2219 #ifdef HAVE_LICENSE
2220 memset(ses->user, 0, MAX_USERNAME_LEN+1);
2221 memset(ses->realm, 0, MAX_USERNAME_LEN+1);
2222 memset(ses->realpeerip, 0, IPV4ALEN);
2223 #endif
2224 #ifdef HAVE_L2TP
2225 ses->l2tp_ses = NULL;
2226 #endif
2227 NumActiveSessions++;
2228 return ses;
2231 /**********************************************************************
2232 * %FUNCTION: pppoe_free_session
2233 * %ARGUMENTS:
2234 * ses -- session to free
2235 * %RETURNS:
2236 * 0 if OK, -1 if error
2237 * %DESCRIPTION:
2238 * Places a ClientSession on the free list.
2239 ***********************************************************************/
2241 pppoe_free_session(ClientSession *ses)
2243 ClientSession *cur, *prev;
2245 cur = BusySessions;
2246 prev = NULL;
2247 while (cur) {
2248 if (ses == cur) break;
2249 prev = cur;
2250 cur = cur->next;
2253 if (!cur) {
2254 syslog(LOG_ERR, "pppoe_free_session: Could not find session %p on busy list", (void *) ses);
2255 return -1;
2258 /* Remove from busy sessions list */
2259 if (prev) {
2260 prev->next = ses->next;
2261 } else {
2262 BusySessions = ses->next;
2265 /* Add to end of free sessions */
2266 ses->next = NULL;
2267 if (LastFreeSession) {
2268 LastFreeSession->next = ses;
2269 LastFreeSession = ses;
2270 } else {
2271 FreeSessions = ses;
2272 LastFreeSession = ses;
2275 /* Initialize fields to sane values */
2276 ses->funcs = &DefaultSessionFunctionTable;
2277 ses->pid = 0;
2278 memset(ses->eth, 0, ETH_ALEN);
2279 ses->flags = 0;
2280 #ifdef HAVE_L2TP
2281 ses->l2tp_ses = NULL;
2282 #endif
2283 NumActiveSessions--;
2284 return 0;
2287 /**********************************************************************
2288 * %FUNCTION: sendHURLorMOTM
2289 * %ARGUMENTS:
2290 * conn -- PPPoE connection
2291 * url -- a URL, which *MUST* begin with "http://" or it won't be sent, or
2292 * a message.
2293 * tag -- one of TAG_HURL or TAG_MOTM
2294 * %RETURNS:
2295 * Nothing
2296 * %DESCRIPTION:
2297 * Sends a PADM packet contaning a HURL or MOTM tag to the victim...er, peer.
2298 ***********************************************************************/
2299 void
2300 sendHURLorMOTM(PPPoEConnection *conn, char const *url, UINT16_t tag)
2302 PPPoEPacket packet;
2303 PPPoETag hurl;
2304 size_t elen;
2305 unsigned char *cursor = packet.payload;
2306 UINT16_t plen = 0;
2308 if (!conn->session) return;
2309 if (conn->discoverySocket < 0) return;
2311 if (tag == TAG_HURL) {
2312 if (strncmp(url, "http://", 7)) {
2313 syslog(LOG_WARNING, "sendHURL(%s): URL must begin with http://", url);
2314 return;
2316 } else {
2317 tag = TAG_MOTM;
2320 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
2321 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
2323 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
2324 packet.ver = 1;
2325 packet.type = 1;
2326 packet.code = CODE_PADM;
2327 packet.session = conn->session;
2329 elen = strlen(url);
2330 if (elen > 256) {
2331 syslog(LOG_WARNING, "MOTM or HURL too long: %d", (int) elen);
2332 return;
2335 hurl.type = htons(tag);
2336 hurl.length = htons(elen);
2337 strcpy((char *) hurl.payload, url);
2338 memcpy(cursor, &hurl, elen + TAG_HDR_SIZE);
2339 cursor += elen + TAG_HDR_SIZE;
2340 plen += elen + TAG_HDR_SIZE;
2342 packet.length = htons(plen);
2344 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
2345 #ifdef DEBUGGING_ENABLED
2346 if (conn->debugFile) {
2347 dumpPacket(conn->debugFile, &packet, "SENT");
2348 fprintf(conn->debugFile, "\n");
2349 fflush(conn->debugFile);
2351 #endif