summaryrefslogtreecommitdiff
path: root/src/pppoe-server.c (plain)
blob: b59cd3c4767295a84a9d2420604614d0ec84e509
1/***********************************************************************
2*
3* pppoe-server.c
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$
13*
14* LIC: GPL
15*
16***********************************************************************/
17
18static char const RCSID[] =
19"$Id$";
20
21#include "config.h"
22
23#if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
24#define _POSIX_SOURCE 1 /* For sigaction defines */
25#endif
26
27#define _BSD_SOURCE 1 /* for gethostname */
28
29#include "pppoe-server.h"
30#include "md5.h"
31
32#ifdef HAVE_SYSLOG_H
33#include <syslog.h>
34#endif
35
36#include <errno.h>
37#include <string.h>
38#include <stdlib.h>
39#include <fcntl.h>
40
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44
45#ifdef HAVE_GETOPT_H
46#include <getopt.h>
47#endif
48
49#ifdef HAVE_SYS_WAIT_H
50#include <sys/wait.h>
51#endif
52
53#ifdef HAVE_SYS_TIME_H
54#include <sys/time.h>
55#endif
56
57#include <time.h>
58
59#include <signal.h>
60
61#ifdef HAVE_LICENSE
62#include "license.h"
63#include "licensed-only/servfuncs.h"
64static struct License const *ServerLicense;
65static struct License const *ClusterLicense;
66#else
67#define control_session_started(x) (void) 0
68#define control_session_terminated(x) (void) 0
69#define control_exit() (void) 0
70#define realpeerip peerip
71#endif
72
73#ifdef HAVE_L2TP
74extern PppoeSessionFunctionTable L2TPSessionFunctionTable;
75extern void pppoe_to_l2tp_add_interface(EventSelector *es,
76 Interface *interface);
77#endif
78
79static void InterfaceHandler(EventSelector *es,
80 int fd, unsigned int flags, void *data);
81static void startPPPD(ClientSession *sess);
82static void sendErrorPADS(int sock, unsigned char *source, unsigned char *dest,
83 int errorTag, char *errorMsg);
84
85#define CHECK_ROOM(cursor, start, len) \
86do {\
87 if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
88 syslog(LOG_ERR, "Would create too-long packet"); \
89 return; \
90 } \
91} while(0)
92
93static void PppoeStopSession(ClientSession *ses, char const *reason);
94static int PppoeSessionIsActive(ClientSession *ses);
95
96/* Service-Names we advertise */
97#define MAX_SERVICE_NAMES 64
98static int NumServiceNames = 0;
99static char const *ServiceNames[MAX_SERVICE_NAMES];
100
101PppoeSessionFunctionTable DefaultSessionFunctionTable = {
102 PppoeStopSession,
103 PppoeSessionIsActive,
104 NULL
105};
106
107/* An array of client sessions */
108ClientSession *Sessions = NULL;
109ClientSession *FreeSessions = NULL;
110ClientSession *LastFreeSession = NULL;
111ClientSession *BusySessions = NULL;
112
113/* Interfaces we're listening on */
114Interface interfaces[MAX_INTERFACES];
115int NumInterfaces = 0;
116
117/* The number of session slots */
118size_t NumSessionSlots;
119
120/* Maximum number of sessions per MAC address */
121int MaxSessionsPerMac;
122
123/* Number of active sessions */
124size_t NumActiveSessions = 0;
125
126/* Offset of first session */
127size_t SessOffset = 0;
128
129/* Event Selector */
130EventSelector *event_selector;
131
132/* Use Linux kernel-mode PPPoE? */
133static int UseLinuxKernelModePPPoE = 0;
134
135/* File with PPPD options */
136static char *pppoptfile = NULL;
137
138static int Debug = 0;
139static int CheckPoolSyntax = 0;
140
141/* Synchronous mode */
142static int Synchronous = 0;
143
144/* Random seed for cookie generation */
145#define SEED_LEN 16
146#define MD5_LEN 16
147#define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
148
149static unsigned char CookieSeed[SEED_LEN];
150
151#define MAXLINE 512
152
153/* Default interface if no -I option given */
154#define DEFAULT_IF "eth0"
155
156/* Access concentrator name */
157char *ACName = NULL;
158
159/* Options to pass to pppoe process */
160char PppoeOptions[SMALLBUF] = "";
161
162/* Our local IP address */
163unsigned char LocalIP[IPV4ALEN] = {10, 0, 0, 1}; /* Counter optionally STARTS here */
164unsigned char RemoteIP[IPV4ALEN] = {10, 67, 15, 1}; /* Counter STARTS here */
165
166/* Do we increment local IP for each connection? */
167int IncrLocalIP = 0;
168
169/* Do we randomize session numbers? */
170int RandomizeSessionNumbers = 0;
171
172/* Do we pass the "unit" option to pppd? (2.4 or greater) */
173int PassUnitOptionToPPPD = 0;
174
175static PPPoETag hostUniq;
176static PPPoETag relayId;
177static PPPoETag receivedCookie;
178static PPPoETag requestedService;
179
180#define HOSTNAMELEN 256
181
182static int
183count_sessions_from_mac(unsigned char *eth)
184{
185 int n=0;
186 ClientSession *s = BusySessions;
187 while(s) {
188 if (!memcmp(eth, s->eth, ETH_ALEN)) n++;
189 s = s->next;
190 }
191 return n;
192}
193
194/**********************************************************************
195*%FUNCTION: childHandler
196*%ARGUMENTS:
197* pid -- pid of child
198* status -- exit status
199* ses -- which session terminated
200*%RETURNS:
201* Nothing
202*%DESCRIPTION:
203* Called synchronously when a child dies. Remove from busy list.
204***********************************************************************/
205static void
206childHandler(pid_t pid, int status, void *s)
207{
208 ClientSession *session = s;
209
210 /* Temporary structure for sending PADT's. */
211 PPPoEConnection conn;
212
213#ifdef HAVE_L2TP
214 /* We're acting as LAC, so when child exits, become a PPPoE <-> L2TP
215 relay */
216 if (session->flags & FLAG_ACT_AS_LAC) {
217 syslog(LOG_INFO, "Session %u for client "
218 "%02x:%02x:%02x:%02x:%02x:%02x handed off to LNS %s",
219 (unsigned int) ntohs(session->sess),
220 session->eth[0], session->eth[1], session->eth[2],
221 session->eth[3], session->eth[4], session->eth[5],
222 inet_ntoa(session->tunnel_endpoint.sin_addr));
223 session->pid = 0;
224 session->funcs = &L2TPSessionFunctionTable;
225 return;
226 }
227#endif
228
229 memset(&conn, 0, sizeof(conn));
230 conn.useHostUniq = 0;
231
232 syslog(LOG_INFO,
233 "Session %u closed for client "
234 "%02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s",
235 (unsigned int) ntohs(session->sess),
236 session->eth[0], session->eth[1], session->eth[2],
237 session->eth[3], session->eth[4], session->eth[5],
238 (int) session->realpeerip[0], (int) session->realpeerip[1],
239 (int) session->realpeerip[2], (int) session->realpeerip[3],
240 session->ethif->name);
241 memcpy(conn.myEth, session->ethif->mac, ETH_ALEN);
242 conn.discoverySocket = session->ethif->sock;
243 conn.session = session->sess;
244 memcpy(conn.peerEth, session->eth, ETH_ALEN);
245 if (!(session->flags & FLAG_SENT_PADT)) {
246 if (session->flags & FLAG_RECVD_PADT) {
247 sendPADT(&conn, "RP-PPPoE: Received PADT from peer");
248 } else {
249 sendPADT(&conn, "RP-PPPoE: Child pppd process terminated");
250 }
251 session->flags |= FLAG_SENT_PADT;
252 }
253
254 session->serviceName = "";
255 control_session_terminated(session);
256 if (pppoe_free_session(session) < 0) {
257 return;
258 }
259
260}
261
262/**********************************************************************
263*%FUNCTION: incrementIPAddress (static)
264*%ARGUMENTS:
265* addr -- a 4-byte array representing IP address
266*%RETURNS:
267* Nothing
268*%DESCRIPTION:
269* Increments addr in-place
270***********************************************************************/
271static void
272incrementIPAddress(unsigned char ip[IPV4ALEN])
273{
274 ip[3]++;
275 if (!ip[3]) {
276 ip[2]++;
277 if (!ip[2]) {
278 ip[1]++;
279 if (!ip[1]) {
280 ip[0]++;
281 }
282 }
283 }
284}
285
286/**********************************************************************
287*%FUNCTION: killAllSessions
288*%ARGUMENTS:
289* None
290*%RETURNS:
291* Nothing
292*%DESCRIPTION:
293* Kills all pppd processes (and hence all PPPoE sessions)
294***********************************************************************/
295void
296killAllSessions(void)
297{
298 ClientSession *sess = BusySessions;
299 while(sess) {
300 sess->funcs->stop(sess, "Shutting Down");
301 sess = sess->next;
302 }
303#ifdef HAVE_L2TP
304 pppoe_close_l2tp_tunnels();
305#endif
306}
307
308/**********************************************************************
309*%FUNCTION: parseAddressPool
310*%ARGUMENTS:
311* fname -- name of file containing IP address pool.
312* install -- if true, install IP addresses in sessions.
313*%RETURNS:
314* Number of valid IP addresses found.
315*%DESCRIPTION:
316* Reads a list of IP addresses from a file.
317***********************************************************************/
318static int
319parseAddressPool(char const *fname, int install)
320{
321 FILE *fp = fopen(fname, "r");
322 int numAddrs = 0;
323 unsigned int a, b, c, d;
324 unsigned int e, f, g, h;
325 char line[MAXLINE];
326
327 if (!fp) {
328 sysErr("Cannot open address pool file");
329 exit(1);
330 }
331
332 while (!feof(fp)) {
333 if (!fgets(line, MAXLINE, fp)) {
334 break;
335 }
336 if ((sscanf(line, "%u.%u.%u.%u:%u.%u.%u.%u",
337 &a, &b, &c, &d, &e, &f, &g, &h) == 8) &&
338 a < 256 && b < 256 && c < 256 && d < 256 &&
339 e < 256 && f < 256 && g < 256 && h < 256) {
340
341 /* Both specified (local:remote) */
342 if (install) {
343 Sessions[numAddrs].myip[0] = (unsigned char) a;
344 Sessions[numAddrs].myip[1] = (unsigned char) b;
345 Sessions[numAddrs].myip[2] = (unsigned char) c;
346 Sessions[numAddrs].myip[3] = (unsigned char) d;
347 Sessions[numAddrs].peerip[0] = (unsigned char) e;
348 Sessions[numAddrs].peerip[1] = (unsigned char) f;
349 Sessions[numAddrs].peerip[2] = (unsigned char) g;
350 Sessions[numAddrs].peerip[3] = (unsigned char) h;
351#ifdef HAVE_LICENSE
352 memcpy(Sessions[numAddrs].realpeerip,
353 Sessions[numAddrs].peerip, IPV4ALEN);
354#endif
355 }
356 numAddrs++;
357 } else if ((sscanf(line, "%u.%u.%u.%u-%u", &a, &b, &c, &d, &e) == 5) &&
358 a < 256 && b < 256 && c < 256 && d < 256 && e < 256) {
359 /* Remote specied as a.b.c.d-e. Example: 1.2.3.4-8 yields:
360 1.2.3.4, 1.2.3.5, 1.2.3.6, 1.2.3.7, 1.2.3.8 */
361 /* Swap d and e so that e >= d */
362 if (e < d) {
363 f = d;
364 d = e;
365 e = f;
366 }
367 if (install) {
368 while (d <= e) {
369 Sessions[numAddrs].peerip[0] = (unsigned char) a;
370 Sessions[numAddrs].peerip[1] = (unsigned char) b;
371 Sessions[numAddrs].peerip[2] = (unsigned char) c;
372 Sessions[numAddrs].peerip[3] = (unsigned char) d;
373#ifdef HAVE_LICENSE
374 memcpy(Sessions[numAddrs].realpeerip,
375 Sessions[numAddrs].peerip, IPV4ALEN);
376#endif
377 d++;
378 numAddrs++;
379 }
380 } else {
381 numAddrs += (e-d) + 1;
382 }
383 } else if ((sscanf(line, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) &&
384 a < 256 && b < 256 && c < 256 && d < 256) {
385 /* Only remote specified */
386 if (install) {
387 Sessions[numAddrs].peerip[0] = (unsigned char) a;
388 Sessions[numAddrs].peerip[1] = (unsigned char) b;
389 Sessions[numAddrs].peerip[2] = (unsigned char) c;
390 Sessions[numAddrs].peerip[3] = (unsigned char) d;
391#ifdef HAVE_LICENSE
392 memcpy(Sessions[numAddrs].realpeerip,
393 Sessions[numAddrs].peerip, IPV4ALEN);
394#endif
395 }
396 numAddrs++;
397 }
398 }
399 fclose(fp);
400 if (!numAddrs) {
401 rp_fatal("No valid ip addresses found in pool file");
402 }
403 return numAddrs;
404}
405
406/**********************************************************************
407*%FUNCTION: parsePADITags
408*%ARGUMENTS:
409* type -- tag type
410* len -- tag length
411* data -- tag data
412* extra -- extra user data.
413*%RETURNS:
414* Nothing
415*%DESCRIPTION:
416* Picks interesting tags out of a PADI packet
417***********************************************************************/
418void
419parsePADITags(UINT16_t type, UINT16_t len, unsigned char *data,
420 void *extra)
421{
422 switch(type) {
423 case TAG_SERVICE_NAME:
424 /* Copy requested service name */
425 requestedService.type = htons(type);
426 requestedService.length = htons(len);
427 memcpy(requestedService.payload, data, len);
428 break;
429 case TAG_RELAY_SESSION_ID:
430 relayId.type = htons(type);
431 relayId.length = htons(len);
432 memcpy(relayId.payload, data, len);
433 break;
434 case TAG_HOST_UNIQ:
435 hostUniq.type = htons(type);
436 hostUniq.length = htons(len);
437 memcpy(hostUniq.payload, data, len);
438 break;
439 }
440}
441
442/**********************************************************************
443*%FUNCTION: parsePADRTags
444*%ARGUMENTS:
445* type -- tag type
446* len -- tag length
447* data -- tag data
448* extra -- extra user data.
449*%RETURNS:
450* Nothing
451*%DESCRIPTION:
452* Picks interesting tags out of a PADR packet
453***********************************************************************/
454void
455parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
456 void *extra)
457{
458 switch(type) {
459 case TAG_RELAY_SESSION_ID:
460 relayId.type = htons(type);
461 relayId.length = htons(len);
462 memcpy(relayId.payload, data, len);
463 break;
464 case TAG_HOST_UNIQ:
465 hostUniq.type = htons(type);
466 hostUniq.length = htons(len);
467 memcpy(hostUniq.payload, data, len);
468 break;
469 case TAG_AC_COOKIE:
470 receivedCookie.type = htons(type);
471 receivedCookie.length = htons(len);
472 memcpy(receivedCookie.payload, data, len);
473 break;
474 case TAG_SERVICE_NAME:
475 requestedService.type = htons(type);
476 requestedService.length = htons(len);
477 memcpy(requestedService.payload, data, len);
478 break;
479 }
480}
481
482/**********************************************************************
483*%FUNCTION: fatalSys
484*%ARGUMENTS:
485* str -- error message
486*%RETURNS:
487* Nothing
488*%DESCRIPTION:
489* Prints a message plus the errno value to stderr and syslog and exits.
490***********************************************************************/
491void
492fatalSys(char const *str)
493{
494 char buf[SMALLBUF];
495 snprintf(buf, SMALLBUF, "%s: %s", str, strerror(errno));
496 printErr(buf);
497 control_exit();
498 exit(EXIT_FAILURE);
499}
500
501/**********************************************************************
502*%FUNCTION: sysErr
503*%ARGUMENTS:
504* str -- error message
505*%RETURNS:
506* Nothing
507*%DESCRIPTION:
508* Prints a message plus the errno value to syslog.
509***********************************************************************/
510void
511sysErr(char const *str)
512{
513 char buf[1024];
514 sprintf(buf, "%.256s: %.256s", str, strerror(errno));
515 printErr(buf);
516}
517
518/**********************************************************************
519*%FUNCTION: rp_fatal
520*%ARGUMENTS:
521* str -- error message
522*%RETURNS:
523* Nothing
524*%DESCRIPTION:
525* Prints a message to stderr and syslog and exits.
526***********************************************************************/
527void
528rp_fatal(char const *str)
529{
530 printErr(str);
531 control_exit();
532 exit(EXIT_FAILURE);
533}
534
535/**********************************************************************
536*%FUNCTION: genCookie
537*%ARGUMENTS:
538* peerEthAddr -- peer Ethernet address (6 bytes)
539* myEthAddr -- my Ethernet address (6 bytes)
540* seed -- random cookie seed to make things tasty (16 bytes)
541* cookie -- buffer which is filled with server PID and
542* md5 sum of previous items
543*%RETURNS:
544* Nothing
545*%DESCRIPTION:
546* Forms the md5 sum of peer MAC address, our MAC address and seed, useful
547* in a PPPoE Cookie tag.
548***********************************************************************/
549void
550genCookie(unsigned char const *peerEthAddr,
551 unsigned char const *myEthAddr,
552 unsigned char const *seed,
553 unsigned char *cookie)
554{
555 struct MD5Context ctx;
556 pid_t pid = getpid();
557
558 MD5Init(&ctx);
559 MD5Update(&ctx, peerEthAddr, ETH_ALEN);
560 MD5Update(&ctx, myEthAddr, ETH_ALEN);
561 MD5Update(&ctx, seed, SEED_LEN);
562 MD5Final(cookie, &ctx);
563 memcpy(cookie+MD5_LEN, &pid, sizeof(pid));
564}
565
566/**********************************************************************
567*%FUNCTION: processPADI
568*%ARGUMENTS:
569* ethif -- Interface
570* packet -- PPPoE PADI packet
571* len -- length of received packet
572*%RETURNS:
573* Nothing
574*%DESCRIPTION:
575* Sends a PADO packet back to client
576***********************************************************************/
577void
578processPADI(Interface *ethif, PPPoEPacket *packet, int len)
579{
580 PPPoEPacket pado;
581 PPPoETag acname;
582 PPPoETag servname;
583 PPPoETag cookie;
584 size_t acname_len;
585 unsigned char *cursor = pado.payload;
586 UINT16_t plen;
587
588 int sock = ethif->sock;
589 int i;
590 int ok = 0;
591 unsigned char *myAddr = ethif->mac;
592
593 /* Ignore PADI's which don't come from a unicast address */
594 if (NOT_UNICAST(packet->ethHdr.h_source)) {
595 syslog(LOG_ERR, "PADI packet from non-unicast source address");
596 return;
597 }
598
599 /* If number of sessions per MAC is limited, check here and don't
600 send PADO if already max number of sessions. */
601 if (MaxSessionsPerMac) {
602 if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
603 syslog(LOG_INFO, "PADI: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
604 packet->ethHdr.h_source[0],
605 packet->ethHdr.h_source[1],
606 packet->ethHdr.h_source[2],
607 packet->ethHdr.h_source[3],
608 packet->ethHdr.h_source[4],
609 packet->ethHdr.h_source[5],
610 MaxSessionsPerMac);
611 return;
612 }
613 }
614
615 acname.type = htons(TAG_AC_NAME);
616 acname_len = strlen(ACName);
617 acname.length = htons(acname_len);
618 memcpy(acname.payload, ACName, acname_len);
619
620 relayId.type = 0;
621 hostUniq.type = 0;
622 requestedService.type = 0;
623 parsePacket(packet, parsePADITags, NULL);
624
625 /* If PADI specified non-default service name, and we do not offer
626 that service, DO NOT send PADO */
627 if (requestedService.type) {
628 int slen = ntohs(requestedService.length);
629 if (slen) {
630 for (i=0; i<NumServiceNames; i++) {
631 if (slen == strlen(ServiceNames[i]) &&
632 !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
633 ok = 1;
634 break;
635 }
636 }
637 } else {
638 ok = 1; /* Default service requested */
639 }
640 } else {
641 ok = 1; /* No Service-Name tag in PADI */
642 }
643
644 if (!ok) {
645 /* PADI asked for unsupported service */
646 return;
647 }
648
649 /* Generate a cookie */
650 cookie.type = htons(TAG_AC_COOKIE);
651 cookie.length = htons(COOKIE_LEN);
652 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookie.payload);
653
654 /* Construct a PADO packet */
655 memcpy(pado.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
656 memcpy(pado.ethHdr.h_source, myAddr, ETH_ALEN);
657 pado.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
658 pado.ver = 1;
659 pado.type = 1;
660 pado.code = CODE_PADO;
661 pado.session = 0;
662 plen = TAG_HDR_SIZE + acname_len;
663
664 CHECK_ROOM(cursor, pado.payload, acname_len+TAG_HDR_SIZE);
665 memcpy(cursor, &acname, acname_len + TAG_HDR_SIZE);
666 cursor += acname_len + TAG_HDR_SIZE;
667
668 /* If no service-names specified on command-line, just send default
669 zero-length name. Otherwise, add all service-name tags */
670 servname.type = htons(TAG_SERVICE_NAME);
671 if (!NumServiceNames) {
672 servname.length = 0;
673 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE);
674 memcpy(cursor, &servname, TAG_HDR_SIZE);
675 cursor += TAG_HDR_SIZE;
676 plen += TAG_HDR_SIZE;
677 } else {
678 for (i=0; i<NumServiceNames; i++) {
679 int slen = strlen(ServiceNames[i]);
680 servname.length = htons(slen);
681 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE+slen);
682 memcpy(cursor, &servname, TAG_HDR_SIZE);
683 memcpy(cursor+TAG_HDR_SIZE, ServiceNames[i], slen);
684 cursor += TAG_HDR_SIZE+slen;
685 plen += TAG_HDR_SIZE+slen;
686 }
687 }
688
689 CHECK_ROOM(cursor, pado.payload, TAG_HDR_SIZE + COOKIE_LEN);
690 memcpy(cursor, &cookie, TAG_HDR_SIZE + COOKIE_LEN);
691 cursor += TAG_HDR_SIZE + COOKIE_LEN;
692 plen += TAG_HDR_SIZE + COOKIE_LEN;
693
694 if (relayId.type) {
695 CHECK_ROOM(cursor, pado.payload, ntohs(relayId.length) + TAG_HDR_SIZE);
696 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
697 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
698 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
699 }
700 if (hostUniq.type) {
701 CHECK_ROOM(cursor, pado.payload, ntohs(hostUniq.length)+TAG_HDR_SIZE);
702 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
703 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
704 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
705 }
706 pado.length = htons(plen);
707 sendPacket(NULL, sock, &pado, (int) (plen + HDR_SIZE));
708}
709
710/**********************************************************************
711*%FUNCTION: processPADT
712*%ARGUMENTS:
713* ethif -- interface
714* packet -- PPPoE PADT packet
715* len -- length of received packet
716*%RETURNS:
717* Nothing
718*%DESCRIPTION:
719* Kills session whose session-ID is in PADT packet.
720***********************************************************************/
721void
722processPADT(Interface *ethif, PPPoEPacket *packet, int len)
723{
724 size_t i;
725
726 unsigned char *myAddr = ethif->mac;
727
728 /* Ignore PADT's not directed at us */
729 if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
730
731 /* Get session's index */
732 i = ntohs(packet->session) - 1 - SessOffset;
733 if (i >= NumSessionSlots) return;
734 if (Sessions[i].sess != packet->session) {
735 syslog(LOG_ERR, "Session index %u doesn't match session number %u",
736 (unsigned int) i, (unsigned int) ntohs(packet->session));
737 return;
738 }
739
740
741 /* If source MAC does not match, do not kill session */
742 if (memcmp(packet->ethHdr.h_source, Sessions[i].eth, ETH_ALEN)) {
743 syslog(LOG_WARNING, "PADT for session %u received from "
744 "%02X:%02X:%02X:%02X:%02X:%02X; should be from "
745 "%02X:%02X:%02X:%02X:%02X:%02X",
746 (unsigned int) ntohs(packet->session),
747 packet->ethHdr.h_source[0],
748 packet->ethHdr.h_source[1],
749 packet->ethHdr.h_source[2],
750 packet->ethHdr.h_source[3],
751 packet->ethHdr.h_source[4],
752 packet->ethHdr.h_source[5],
753 Sessions[i].eth[0],
754 Sessions[i].eth[1],
755 Sessions[i].eth[2],
756 Sessions[i].eth[3],
757 Sessions[i].eth[4],
758 Sessions[i].eth[5]);
759 return;
760 }
761 Sessions[i].flags |= FLAG_RECVD_PADT;
762 parsePacket(packet, parseLogErrs, NULL);
763 Sessions[i].funcs->stop(&Sessions[i], "Received PADT");
764}
765
766/**********************************************************************
767*%FUNCTION: processPADR
768*%ARGUMENTS:
769* ethif -- Ethernet interface
770* packet -- PPPoE PADR packet
771* len -- length of received packet
772*%RETURNS:
773* Nothing
774*%DESCRIPTION:
775* Sends a PADS packet back to client and starts a PPP session if PADR
776* packet is OK.
777***********************************************************************/
778void
779processPADR(Interface *ethif, PPPoEPacket *packet, int len)
780{
781 unsigned char cookieBuffer[COOKIE_LEN];
782 ClientSession *cliSession;
783 pid_t child;
784 PPPoEPacket pads;
785 unsigned char *cursor = pads.payload;
786 UINT16_t plen;
787 int i;
788 int sock = ethif->sock;
789 unsigned char *myAddr = ethif->mac;
790 int slen = 0;
791 char const *serviceName = NULL;
792
793#ifdef HAVE_LICENSE
794 int freemem;
795#endif
796
797 /* Initialize some globals */
798 relayId.type = 0;
799 hostUniq.type = 0;
800 receivedCookie.type = 0;
801 requestedService.type = 0;
802
803 /* Ignore PADR's not directed at us */
804 if (memcmp(packet->ethHdr.h_dest, myAddr, ETH_ALEN)) return;
805
806 /* Ignore PADR's from non-unicast addresses */
807 if (NOT_UNICAST(packet->ethHdr.h_source)) {
808 syslog(LOG_ERR, "PADR packet from non-unicast source address");
809 return;
810 }
811
812 /* If number of sessions per MAC is limited, check here and don't
813 send PADS if already max number of sessions. */
814 if (MaxSessionsPerMac) {
815 if (count_sessions_from_mac(packet->ethHdr.h_source) >= MaxSessionsPerMac) {
816 syslog(LOG_INFO, "PADR: Client %02x:%02x:%02x:%02x:%02x:%02x attempted to create more than %d session(s)",
817 packet->ethHdr.h_source[0],
818 packet->ethHdr.h_source[1],
819 packet->ethHdr.h_source[2],
820 packet->ethHdr.h_source[3],
821 packet->ethHdr.h_source[4],
822 packet->ethHdr.h_source[5],
823 MaxSessionsPerMac);
824 return;
825 }
826 }
827 parsePacket(packet, parsePADRTags, NULL);
828
829 /* Check that everything's cool */
830 if (!receivedCookie.type) {
831 /* Drop it -- do not send error PADS */
832 return;
833 }
834
835 /* Is cookie kosher? */
836 if (receivedCookie.length != htons(COOKIE_LEN)) {
837 /* Drop it -- do not send error PADS */
838 return;
839 }
840
841 genCookie(packet->ethHdr.h_source, myAddr, CookieSeed, cookieBuffer);
842 if (memcmp(receivedCookie.payload, cookieBuffer, COOKIE_LEN)) {
843 /* Drop it -- do not send error PADS */
844 return;
845 }
846
847 /* Check service name */
848 if (!requestedService.type) {
849 syslog(LOG_ERR, "Received PADR packet with no SERVICE_NAME tag");
850 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
851 TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: No service name tag");
852 return;
853 }
854
855 slen = ntohs(requestedService.length);
856 if (slen) {
857 /* Check supported services */
858 for(i=0; i<NumServiceNames; i++) {
859 if (slen == strlen(ServiceNames[i]) &&
860 !memcmp(ServiceNames[i], &requestedService.payload, slen)) {
861 serviceName = ServiceNames[i];
862 break;
863 }
864 }
865
866 if (!serviceName) {
867 syslog(LOG_ERR, "Received PADR packet asking for unsupported service %.*s", (int) ntohs(requestedService.length), requestedService.payload);
868 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
869 TAG_SERVICE_NAME_ERROR, "RP-PPPoE: Server: Invalid service name tag");
870 return;
871 }
872 } else {
873 serviceName = "";
874 }
875
876
877#ifdef HAVE_LICENSE
878 /* Are we licensed for this many sessions? */
879 if (License_NumLicenses("PPPOE-SESSIONS") <= NumActiveSessions) {
880 syslog(LOG_ERR, "Insufficient session licenses (%02x:%02x:%02x:%02x:%02x:%02x)",
881 (unsigned int) packet->ethHdr.h_source[0],
882 (unsigned int) packet->ethHdr.h_source[1],
883 (unsigned int) packet->ethHdr.h_source[2],
884 (unsigned int) packet->ethHdr.h_source[3],
885 (unsigned int) packet->ethHdr.h_source[4],
886 (unsigned int) packet->ethHdr.h_source[5]);
887 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
888 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No session licenses available");
889 return;
890 }
891#endif
892 /* Enough free memory? */
893#ifdef HAVE_LICENSE
894 freemem = getFreeMem();
895 if (freemem < MIN_FREE_MEMORY) {
896 syslog(LOG_WARNING,
897 "Insufficient free memory to create session: Want %d, have %d",
898 MIN_FREE_MEMORY, freemem);
899 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
900 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Insufficient free RAM");
901 return;
902 }
903#endif
904 /* Looks cool... find a slot for the session */
905 cliSession = pppoe_alloc_session();
906 if (!cliSession) {
907 syslog(LOG_ERR, "No client slots available (%02x:%02x:%02x:%02x:%02x:%02x)",
908 (unsigned int) packet->ethHdr.h_source[0],
909 (unsigned int) packet->ethHdr.h_source[1],
910 (unsigned int) packet->ethHdr.h_source[2],
911 (unsigned int) packet->ethHdr.h_source[3],
912 (unsigned int) packet->ethHdr.h_source[4],
913 (unsigned int) packet->ethHdr.h_source[5]);
914 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
915 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: No client slots available");
916 return;
917 }
918
919 /* Set up client session peer Ethernet address */
920 memcpy(cliSession->eth, packet->ethHdr.h_source, ETH_ALEN);
921 cliSession->ethif = ethif;
922 cliSession->flags = 0;
923 cliSession->funcs = &DefaultSessionFunctionTable;
924 cliSession->startTime = time(NULL);
925 cliSession->serviceName = serviceName;
926
927 /* Create child process, send PADS packet back */
928 child = fork();
929 if (child < 0) {
930 sendErrorPADS(sock, myAddr, packet->ethHdr.h_source,
931 TAG_AC_SYSTEM_ERROR, "RP-PPPoE: Server: Unable to start session process");
932 pppoe_free_session(cliSession);
933 return;
934 }
935 if (child != 0) {
936 /* In the parent process. Mark pid in session slot */
937 cliSession->pid = child;
938 Event_HandleChildExit(event_selector, child,
939 childHandler, cliSession);
940 control_session_started(cliSession);
941 return;
942 }
943
944 /* In the child process. */
945
946 /* Close all file descriptors except for socket */
947 closelog();
948 for (i=0; i<CLOSEFD; i++) {
949 if (i != sock) {
950 close(i);
951 }
952 }
953
954 openlog("pppoe-server", LOG_PID, LOG_DAEMON);
955 /* pppd has a nasty habit of killing all processes in its process group.
956 Start a new session to stop pppd from killing us! */
957 setsid();
958
959 /* Send PADS and Start pppd */
960 memcpy(pads.ethHdr.h_dest, packet->ethHdr.h_source, ETH_ALEN);
961 memcpy(pads.ethHdr.h_source, myAddr, ETH_ALEN);
962 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
963 pads.ver = 1;
964 pads.type = 1;
965 pads.code = CODE_PADS;
966
967 pads.session = cliSession->sess;
968 plen = 0;
969
970 /* Copy requested service name tag back in. If requested-service name
971 length is zero, and we have non-zero services, use first service-name
972 as default */
973 if (!slen && NumServiceNames) {
974 slen = strlen(ServiceNames[0]);
975 memcpy(&requestedService.payload, ServiceNames[0], slen);
976 requestedService.length = htons(slen);
977 }
978 memcpy(cursor, &requestedService, TAG_HDR_SIZE+slen);
979 cursor += TAG_HDR_SIZE+slen;
980 plen += TAG_HDR_SIZE+slen;
981
982 if (relayId.type) {
983 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
984 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
985 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
986 }
987 if (hostUniq.type) {
988 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
989 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
990 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
991 }
992 pads.length = htons(plen);
993 sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
994
995 /* Close sock; don't need it any more */
996 close(sock);
997
998 startPPPD(cliSession);
999}
1000
1001/**********************************************************************
1002*%FUNCTION: termHandler
1003*%ARGUMENTS:
1004* sig -- signal number
1005*%RETURNS:
1006* Nothing
1007*%DESCRIPTION:
1008* Called by SIGTERM or SIGINT. Causes all sessions to be killed!
1009***********************************************************************/
1010static void
1011termHandler(int sig)
1012{
1013 syslog(LOG_INFO,
1014 "Terminating on signal %d -- killing all PPPoE sessions",
1015 sig);
1016 killAllSessions();
1017 control_exit();
1018 exit(0);
1019}
1020
1021/**********************************************************************
1022*%FUNCTION: usage
1023*%ARGUMENTS:
1024* argv0 -- argv[0] from main
1025*%RETURNS:
1026* Nothing
1027*%DESCRIPTION:
1028* Prints usage instructions
1029***********************************************************************/
1030void
1031usage(char const *argv0)
1032{
1033 fprintf(stderr, "Usage: %s [options]\n", argv0);
1034 fprintf(stderr, "Options:\n");
1035#ifdef USE_BPF
1036 fprintf(stderr, " -I if_name -- Specify interface (REQUIRED)\n");
1037#else
1038 fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
1039 DEFAULT_IF);
1040#endif
1041 fprintf(stderr, " -T timeout -- Specify inactivity timeout in seconds.\n");
1042 fprintf(stderr, " -C name -- Set access concentrator name.\n");
1043 fprintf(stderr, " -m MSS -- Clamp incoming and outgoing MSS options.\n");
1044 fprintf(stderr, " -L ip -- Set local IP address.\n");
1045 fprintf(stderr, " -l -- Increment local IP address for each session.\n");
1046 fprintf(stderr, " -R ip -- Set start address of remote IP pool.\n");
1047 fprintf(stderr, " -S name -- Advertise specified service-name.\n");
1048 fprintf(stderr, " -O fname -- Use PPPD options from specified file\n");
1049 fprintf(stderr, " (default %s).\n", PPPOE_SERVER_OPTIONS);
1050 fprintf(stderr, " -p fname -- Optain IP address pool from specified file.\n");
1051 fprintf(stderr, " -N num -- Allow 'num' concurrent sessions.\n");
1052 fprintf(stderr, " -o offset -- Assign session numbers starting at offset+1.\n");
1053 fprintf(stderr, " -f disc:sess -- Set Ethernet frame types (hex).\n");
1054 fprintf(stderr, " -s -- Use synchronous PPP mode.\n");
1055#ifdef HAVE_LINUX_KERNEL_PPPOE
1056 fprintf(stderr, " -k -- Use kernel-mode PPPoE.\n");
1057#endif
1058 fprintf(stderr, " -u -- Pass 'unit' option to pppd.\n");
1059 fprintf(stderr, " -r -- Randomize session numbers.\n");
1060 fprintf(stderr, " -d -- Debug session creation.\n");
1061 fprintf(stderr, " -x n -- Limit to 'n' sessions/MAC address.\n");
1062 fprintf(stderr, " -P -- Check pool file for correctness and exit.\n");
1063#ifdef HAVE_LICENSE
1064 fprintf(stderr, " -c secret:if:port -- Enable clustering on interface 'if'.\n");
1065 fprintf(stderr, " -1 -- Allow only one session per user.\n");
1066#endif
1067
1068 fprintf(stderr, " -h -- Print usage information.\n\n");
1069 fprintf(stderr, "PPPoE-Server Version %s, Copyright (C) 2001-2006 Roaring Penguin Software Inc.\n", VERSION);
1070
1071#ifndef HAVE_LICENSE
1072 fprintf(stderr, "PPPoE-Server comes with ABSOLUTELY NO WARRANTY.\n");
1073 fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
1074 fprintf(stderr, "under the terms of the GNU General Public License, version 2\n");
1075 fprintf(stderr, "or (at your option) any later version.\n");
1076#endif
1077 fprintf(stderr, "http://www.roaringpenguin.com\n");
1078}
1079
1080/**********************************************************************
1081*%FUNCTION: main
1082*%ARGUMENTS:
1083* argc, argv -- usual suspects
1084*%RETURNS:
1085* Exit status
1086*%DESCRIPTION:
1087* Main program of PPPoE server
1088***********************************************************************/
1089int
1090main(int argc, char **argv)
1091{
1092
1093 FILE *fp;
1094 int i, j;
1095 int opt;
1096 int d[IPV4ALEN];
1097 int beDaemon = 1;
1098 int found;
1099 unsigned int discoveryType, sessionType;
1100 char *addressPoolFname = NULL;
1101#ifdef HAVE_LICENSE
1102 int use_clustering = 0;
1103#endif
1104
1105#ifndef HAVE_LINUX_KERNEL_PPPOE
1106 char *options = "x:hI:C:L:R:T:m:FN:f:O:o:sp:lrudPc:S:1";
1107#else
1108 char *options = "x:hI:C:L:R:T:m:FN:f:O:o:skp:lrudPc:S:1";
1109#endif
1110
1111 if (getuid() != geteuid() ||
1112 getgid() != getegid()) {
1113 fprintf(stderr, "SECURITY WARNING: pppoe-server will NOT run suid or sgid. Fix your installation.\n");
1114 exit(1);
1115 }
1116
1117 memset(interfaces, 0, sizeof(interfaces));
1118
1119 /* Initialize syslog */
1120 openlog("pppoe-server", LOG_PID, LOG_DAEMON);
1121
1122 /* Default number of session slots */
1123 NumSessionSlots = DEFAULT_MAX_SESSIONS;
1124 MaxSessionsPerMac = 0; /* No limit */
1125 NumActiveSessions = 0;
1126
1127 /* Parse command-line options */
1128 while((opt = getopt(argc, argv, options)) != -1) {
1129 switch(opt) {
1130 case 'x':
1131 if (sscanf(optarg, "%d", &MaxSessionsPerMac) != 1) {
1132 usage(argv[0]);
1133 exit(EXIT_FAILURE);
1134 }
1135 if (MaxSessionsPerMac < 0) {
1136 MaxSessionsPerMac = 0;
1137 }
1138 break;
1139
1140#ifdef HAVE_LINUX_KERNEL_PPPOE
1141 case 'k':
1142 UseLinuxKernelModePPPoE = 1;
1143 break;
1144#endif
1145 case 'S':
1146 if (NumServiceNames == MAX_SERVICE_NAMES) {
1147 fprintf(stderr, "Too many '-S' options (%d max)",
1148 MAX_SERVICE_NAMES);
1149 exit(1);
1150 }
1151 ServiceNames[NumServiceNames] = strdup(optarg);
1152 if (!ServiceNames[NumServiceNames]) {
1153 fprintf(stderr, "Out of memory");
1154 exit(1);
1155 }
1156 NumServiceNames++;
1157 break;
1158 case 'c':
1159#ifndef HAVE_LICENSE
1160 fprintf(stderr, "Clustering capability not available.\n");
1161 exit(1);
1162#else
1163 cluster_handle_option(optarg);
1164 use_clustering = 1;
1165 break;
1166#endif
1167
1168 case 'd':
1169 Debug = 1;
1170 break;
1171 case 'P':
1172 CheckPoolSyntax = 1;
1173 break;
1174 case 'u':
1175 PassUnitOptionToPPPD = 1;
1176 break;
1177
1178 case 'r':
1179 RandomizeSessionNumbers = 1;
1180 break;
1181
1182 case 'l':
1183 IncrLocalIP = 1;
1184 break;
1185
1186 case 'p':
1187 SET_STRING(addressPoolFname, optarg);
1188 break;
1189
1190 case 's':
1191 Synchronous = 1;
1192 /* Pass the Synchronous option on to pppoe */
1193 snprintf(PppoeOptions + strlen(PppoeOptions),
1194 SMALLBUF-strlen(PppoeOptions),
1195 " -s");
1196 break;
1197
1198 case 'f':
1199 if (sscanf(optarg, "%x:%x", &discoveryType, &sessionType) != 2) {
1200 fprintf(stderr, "Illegal argument to -f: Should be disc:sess in hex\n");
1201 exit(EXIT_FAILURE);
1202 }
1203 Eth_PPPOE_Discovery = (UINT16_t) discoveryType;
1204 Eth_PPPOE_Session = (UINT16_t) sessionType;
1205 /* This option gets passed to pppoe */
1206 snprintf(PppoeOptions + strlen(PppoeOptions),
1207 SMALLBUF-strlen(PppoeOptions),
1208 " -%c %s", opt, optarg);
1209 break;
1210
1211 case 'F':
1212 beDaemon = 0;
1213 break;
1214
1215 case 'N':
1216 if (sscanf(optarg, "%d", &opt) != 1) {
1217 usage(argv[0]);
1218 exit(EXIT_FAILURE);
1219 }
1220 if (opt <= 0) {
1221 fprintf(stderr, "-N: Value must be positive\n");
1222 exit(EXIT_FAILURE);
1223 }
1224 NumSessionSlots = opt;
1225 break;
1226
1227 case 'O':
1228 SET_STRING(pppoptfile, optarg);
1229 break;
1230
1231 case 'o':
1232 if (sscanf(optarg, "%d", &opt) != 1) {
1233 usage(argv[0]);
1234 exit(EXIT_FAILURE);
1235 }
1236 if (opt < 0) {
1237 fprintf(stderr, "-o: Value must be non-negative\n");
1238 exit(EXIT_FAILURE);
1239 }
1240 SessOffset = (size_t) opt;
1241 break;
1242
1243 case 'I':
1244 if (NumInterfaces >= MAX_INTERFACES) {
1245 fprintf(stderr, "Too many -I options (max %d)\n",
1246 MAX_INTERFACES);
1247 exit(EXIT_FAILURE);
1248 }
1249 found = 0;
1250 for (i=0; i<NumInterfaces; i++) {
1251 if (!strncmp(interfaces[i].name, optarg, IFNAMSIZ)) {
1252 found = 1;
1253 break;
1254 }
1255 }
1256 if (!found) {
1257 strncpy(interfaces[NumInterfaces].name, optarg, IFNAMSIZ);
1258 NumInterfaces++;
1259 }
1260 break;
1261
1262 case 'C':
1263 SET_STRING(ACName, optarg);
1264 break;
1265
1266 case 'L':
1267 case 'R':
1268 /* Get local/remote IP address */
1269 if (sscanf(optarg, "%d.%d.%d.%d", &d[0], &d[1], &d[2], &d[3]) != 4) {
1270 usage(argv[0]);
1271 exit(EXIT_FAILURE);
1272 }
1273 for (i=0; i<IPV4ALEN; i++) {
1274 if (d[i] < 0 || d[i] > 255) {
1275 usage(argv[0]);
1276 exit(EXIT_FAILURE);
1277 }
1278 if (opt == 'L') {
1279 LocalIP[i] = (unsigned char) d[i];
1280 } else {
1281 RemoteIP[i] = (unsigned char) d[i];
1282 }
1283 }
1284 break;
1285
1286 case 'T':
1287 case 'm':
1288 /* These just get passed to pppoe */
1289 snprintf(PppoeOptions + strlen(PppoeOptions),
1290 SMALLBUF-strlen(PppoeOptions),
1291 " -%c %s", opt, optarg);
1292 break;
1293
1294 case 'h':
1295 usage(argv[0]);
1296 exit(EXIT_SUCCESS);
1297 case '1':
1298#ifdef HAVE_LICENSE
1299 MaxSessionsPerUser = 1;
1300#else
1301 fprintf(stderr, "-1 option not valid.\n");
1302 exit(1);
1303#endif
1304 break;
1305 }
1306 }
1307
1308 if (!pppoptfile) {
1309 pppoptfile = PPPOE_SERVER_OPTIONS;
1310 }
1311
1312#ifdef HAVE_LICENSE
1313 License_SetVersion(SERVPOET_VERSION);
1314 License_ReadBundleFile("/etc/rp/bundle.txt");
1315 License_ReadFile("/etc/rp/license.txt");
1316 ServerLicense = License_GetFeature("PPPOE-SERVER");
1317 if (!ServerLicense) {
1318 fprintf(stderr, "License: GetFeature failed: %s\n",
1319 License_ErrorMessage());
1320 exit(1);
1321 }
1322#endif
1323
1324#ifdef USE_LINUX_PACKET
1325#ifndef HAVE_STRUCT_SOCKADDR_LL
1326 fprintf(stderr, "The PPPoE server does not work on Linux 2.0 kernels.\n");
1327 exit(EXIT_FAILURE);
1328#endif
1329#endif
1330
1331 if (!NumInterfaces) {
1332 strcpy(interfaces[0].name, DEFAULT_IF);
1333 NumInterfaces = 1;
1334 }
1335
1336 if (!ACName) {
1337 ACName = malloc(HOSTNAMELEN);
1338 if (gethostname(ACName, HOSTNAMELEN) < 0) {
1339 fatalSys("gethostname");
1340 }
1341 }
1342
1343 /* If address pool filename given, count number of addresses */
1344 if (addressPoolFname) {
1345 NumSessionSlots = parseAddressPool(addressPoolFname, 0);
1346 if (CheckPoolSyntax) {
1347 printf("%lu\n", (unsigned long) NumSessionSlots);
1348 exit(0);
1349 }
1350 }
1351
1352 /* Max 65534 - SessOffset sessions */
1353 if (NumSessionSlots + SessOffset > 65534) {
1354 fprintf(stderr, "-N and -o options must add up to at most 65534\n");
1355 exit(EXIT_FAILURE);
1356 }
1357
1358 /* Allocate memory for sessions */
1359 Sessions = calloc(NumSessionSlots, sizeof(ClientSession));
1360 if (!Sessions) {
1361 rp_fatal("Cannot allocate memory for session slots");
1362 }
1363
1364 /* Fill in local addresses first (let pool file override later */
1365 for (i=0; i<NumSessionSlots; i++) {
1366 memcpy(Sessions[i].myip, LocalIP, sizeof(LocalIP));
1367 if (IncrLocalIP) {
1368 incrementIPAddress(LocalIP);
1369 }
1370 }
1371
1372 /* Fill in remote IP addresses from pool (may also overwrite local ips) */
1373 if (addressPoolFname) {
1374 (void) parseAddressPool(addressPoolFname, 1);
1375 }
1376
1377 /* For testing -- generate sequential remote IP addresses */
1378 for (i=0; i<NumSessionSlots; i++) {
1379 Sessions[i].pid = 0;
1380 Sessions[i].funcs = &DefaultSessionFunctionTable;
1381 Sessions[i].sess = htons(i+1+SessOffset);
1382
1383 if (!addressPoolFname) {
1384 memcpy(Sessions[i].peerip, RemoteIP, sizeof(RemoteIP));
1385#ifdef HAVE_LICENSE
1386 memcpy(Sessions[i].realpeerip, RemoteIP, sizeof(RemoteIP));
1387#endif
1388 incrementIPAddress(RemoteIP);
1389 }
1390 }
1391
1392 /* Initialize our random cookie. Try /dev/urandom; if that fails,
1393 use PID and rand() */
1394 fp = fopen("/dev/urandom", "r");
1395 if (fp) {
1396 unsigned int x;
1397 fread(&x, 1, sizeof(x), fp);
1398 srand(x);
1399 fread(&CookieSeed, 1, SEED_LEN, fp);
1400 fclose(fp);
1401 } else {
1402 srand((unsigned int) getpid() * (unsigned int) time(NULL));
1403 CookieSeed[0] = getpid() & 0xFF;
1404 CookieSeed[1] = (getpid() >> 8) & 0xFF;
1405 for (i=2; i<SEED_LEN; i++) {
1406 CookieSeed[i] = (rand() >> (i % 9)) & 0xFF;
1407 }
1408 }
1409
1410 if (RandomizeSessionNumbers) {
1411 int *permutation;
1412 int tmp;
1413 permutation = malloc(sizeof(int) * NumSessionSlots);
1414 if (!permutation) {
1415 fprintf(stderr, "Could not allocate memory to randomize session numbers\n");
1416 exit(EXIT_FAILURE);
1417 }
1418 for (i=0; i<NumSessionSlots; i++) {
1419 permutation[i] = i;
1420 }
1421 for (i=0; i<NumSessionSlots-1; i++) {
1422 j = i + rand() % (NumSessionSlots - i);
1423 if (j != i) {
1424 tmp = permutation[j];
1425 permutation[j] = permutation[i];
1426 permutation[i] = tmp;
1427 }
1428 }
1429 /* Link sessions together */
1430 FreeSessions = &Sessions[permutation[0]];
1431 LastFreeSession = &Sessions[permutation[NumSessionSlots-1]];
1432 for (i=0; i<NumSessionSlots-1; i++) {
1433 Sessions[permutation[i]].next = &Sessions[permutation[i+1]];
1434 }
1435 Sessions[permutation[NumSessionSlots-1]].next = NULL;
1436 free(permutation);
1437 } else {
1438 /* Link sessions together */
1439 FreeSessions = &Sessions[0];
1440 LastFreeSession = &Sessions[NumSessionSlots - 1];
1441 for (i=0; i<NumSessionSlots-1; i++) {
1442 Sessions[i].next = &Sessions[i+1];
1443 }
1444 Sessions[NumSessionSlots-1].next = NULL;
1445 }
1446
1447 if (Debug) {
1448 /* Dump session array and exit */
1449 ClientSession *ses = FreeSessions;
1450 while(ses) {
1451 printf("Session %u local %d.%d.%d.%d remote %d.%d.%d.%d\n",
1452 (unsigned int) (ntohs(ses->sess)),
1453 ses->myip[0], ses->myip[1],
1454 ses->myip[2], ses->myip[3],
1455 ses->peerip[0], ses->peerip[1],
1456 ses->peerip[2], ses->peerip[3]);
1457 ses = ses->next;
1458 }
1459 exit(0);
1460 }
1461
1462 /* Open all the interfaces */
1463 for (i=0; i<NumInterfaces; i++) {
1464 interfaces[i].sock = openInterface(interfaces[i].name, Eth_PPPOE_Discovery, interfaces[i].mac);
1465 }
1466
1467 /* Ignore SIGPIPE */
1468 signal(SIGPIPE, SIG_IGN);
1469
1470 /* Create event selector */
1471 event_selector = Event_CreateSelector();
1472 if (!event_selector) {
1473 rp_fatal("Could not create EventSelector -- probably out of memory");
1474 }
1475
1476 /* Set signal handlers for SIGTERM and SIGINT */
1477 if (Event_HandleSignal(event_selector, SIGTERM, termHandler) < 0 ||
1478 Event_HandleSignal(event_selector, SIGINT, termHandler) < 0) {
1479 fatalSys("Event_HandleSignal");
1480 }
1481
1482 /* Control channel */
1483#ifdef HAVE_LICENSE
1484 if (control_init(argc, argv, event_selector)) {
1485 rp_fatal("control_init failed");
1486 }
1487#endif
1488
1489 /* Create event handler for each interface */
1490 for (i = 0; i<NumInterfaces; i++) {
1491 interfaces[i].eh = Event_AddHandler(event_selector,
1492 interfaces[i].sock,
1493 EVENT_FLAG_READABLE,
1494 InterfaceHandler,
1495 &interfaces[i]);
1496#ifdef HAVE_L2TP
1497 interfaces[i].session_sock = -1;
1498#endif
1499 if (!interfaces[i].eh) {
1500 rp_fatal("Event_AddHandler failed");
1501 }
1502 }
1503
1504#ifdef HAVE_LICENSE
1505 if (use_clustering) {
1506 ClusterLicense = License_GetFeature("PPPOE-CLUSTER");
1507 if (!ClusterLicense) {
1508 fprintf(stderr, "License: GetFeature failed: %s\n",
1509 License_ErrorMessage());
1510 exit(1);
1511 }
1512 if (!License_Expired(ClusterLicense)) {
1513 if (cluster_init(event_selector) < 0) {
1514 rp_fatal("cluster_init failed");
1515 }
1516 }
1517 }
1518#endif
1519
1520#ifdef HAVE_L2TP
1521 for (i=0; i<NumInterfaces; i++) {
1522 pppoe_to_l2tp_add_interface(event_selector,
1523 &interfaces[i]);
1524 }
1525#endif
1526
1527 /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
1528 if (beDaemon) {
1529 i = fork();
1530 if (i < 0) {
1531 fatalSys("fork");
1532 } else if (i != 0) {
1533 /* parent */
1534 exit(EXIT_SUCCESS);
1535 }
1536 setsid();
1537 signal(SIGHUP, SIG_IGN);
1538 i = fork();
1539 if (i < 0) {
1540 fatalSys("fork");
1541 } else if (i != 0) {
1542 exit(EXIT_SUCCESS);
1543 }
1544
1545 chdir("/");
1546
1547 /* Point stdin/stdout/stderr to /dev/null */
1548 for (i=0; i<3; i++) {
1549 close(i);
1550 }
1551 i = open("/dev/null", O_RDWR);
1552 if (i >= 0) {
1553 dup2(i, 0);
1554 dup2(i, 1);
1555 dup2(i, 2);
1556 if (i > 2) close(i);
1557 }
1558 }
1559
1560 for(;;) {
1561 i = Event_HandleEvent(event_selector);
1562 if (i < 0) {
1563 fatalSys("Event_HandleEvent");
1564 }
1565
1566#ifdef HAVE_LICENSE
1567 if (License_Expired(ServerLicense)) {
1568 syslog(LOG_INFO, "Server license has expired -- killing all PPPoE sessions");
1569 killAllSessions();
1570 control_exit();
1571 exit(0);
1572 }
1573#endif
1574 }
1575 return 0;
1576}
1577
1578void
1579serverProcessPacket(Interface *i)
1580{
1581 int len;
1582 PPPoEPacket packet;
1583 int sock = i->sock;
1584
1585 if (receivePacket(sock, &packet, &len) < 0) {
1586 return;
1587 }
1588
1589 /* Check length */
1590 if (ntohs(packet.length) + HDR_SIZE > len) {
1591 syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
1592 (unsigned int) ntohs(packet.length));
1593 return;
1594 }
1595
1596 /* Sanity check on packet */
1597 if (packet.ver != 1 || packet.type != 1) {
1598 /* Syslog an error */
1599 return;
1600 }
1601 switch(packet.code) {
1602 case CODE_PADI:
1603 processPADI(i, &packet, len);
1604 break;
1605 case CODE_PADR:
1606 processPADR(i, &packet, len);
1607 break;
1608 case CODE_PADT:
1609 /* Kill the child */
1610 processPADT(i, &packet, len);
1611 break;
1612 case CODE_SESS:
1613 /* Ignore SESS -- children will handle them */
1614 break;
1615 case CODE_PADO:
1616 case CODE_PADS:
1617 /* Ignore PADO and PADS totally */
1618 break;
1619 default:
1620 /* Syslog an error */
1621 break;
1622 }
1623}
1624
1625/**********************************************************************
1626*%FUNCTION: sendErrorPADS
1627*%ARGUMENTS:
1628* sock -- socket to write to
1629* source -- source Ethernet address
1630* dest -- destination Ethernet address
1631* errorTag -- error tag
1632* errorMsg -- error message
1633*%RETURNS:
1634* Nothing
1635*%DESCRIPTION:
1636* Sends a PADS packet with an error message
1637***********************************************************************/
1638void
1639sendErrorPADS(int sock,
1640 unsigned char *source,
1641 unsigned char *dest,
1642 int errorTag,
1643 char *errorMsg)
1644{
1645 PPPoEPacket pads;
1646 unsigned char *cursor = pads.payload;
1647 UINT16_t plen;
1648 PPPoETag err;
1649 int elen = strlen(errorMsg);
1650
1651 memcpy(pads.ethHdr.h_dest, dest, ETH_ALEN);
1652 memcpy(pads.ethHdr.h_source, source, ETH_ALEN);
1653 pads.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
1654 pads.ver = 1;
1655 pads.type = 1;
1656 pads.code = CODE_PADS;
1657
1658 pads.session = htons(0);
1659 plen = 0;
1660
1661 err.type = htons(errorTag);
1662 err.length = htons(elen);
1663
1664 memcpy(err.payload, errorMsg, elen);
1665 memcpy(cursor, &err, TAG_HDR_SIZE+elen);
1666 cursor += TAG_HDR_SIZE + elen;
1667 plen += TAG_HDR_SIZE + elen;
1668
1669 if (relayId.type) {
1670 memcpy(cursor, &relayId, ntohs(relayId.length) + TAG_HDR_SIZE);
1671 cursor += ntohs(relayId.length) + TAG_HDR_SIZE;
1672 plen += ntohs(relayId.length) + TAG_HDR_SIZE;
1673 }
1674 if (hostUniq.type) {
1675 memcpy(cursor, &hostUniq, ntohs(hostUniq.length) + TAG_HDR_SIZE);
1676 cursor += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1677 plen += ntohs(hostUniq.length) + TAG_HDR_SIZE;
1678 }
1679 pads.length = htons(plen);
1680 sendPacket(NULL, sock, &pads, (int) (plen + HDR_SIZE));
1681}
1682
1683
1684/**********************************************************************
1685*%FUNCTION: startPPPDUserMode
1686*%ARGUMENTS:
1687* session -- client session record
1688*%RETURNS:
1689* Nothing
1690*%DESCRIPTION:
1691* Starts PPPD for user-mode PPPoE
1692***********************************************************************/
1693void
1694startPPPDUserMode(ClientSession *session)
1695{
1696 /* Leave some room */
1697 char *argv[32];
1698
1699 char buffer[SMALLBUF];
1700
1701 int c = 0;
1702
1703 argv[c++] = "pppd";
1704 argv[c++] = "pty";
1705
1706 /* Let's hope service-name does not have ' in it... */
1707 snprintf(buffer, SMALLBUF, "%s -n -I %s -e %u:%02x:%02x:%02x:%02x:%02x:%02x%s -S '%s'",
1708 PPPOE_PATH, session->ethif->name,
1709 (unsigned int) ntohs(session->sess),
1710 session->eth[0], session->eth[1], session->eth[2],
1711 session->eth[3], session->eth[4], session->eth[5],
1712 PppoeOptions, session->serviceName);
1713 argv[c++] = strdup(buffer);
1714 if (!argv[c-1]) {
1715 /* TODO: Send a PADT */
1716 exit(EXIT_FAILURE);
1717 }
1718
1719 argv[c++] = "file";
1720 argv[c++] = pppoptfile;
1721
1722 snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
1723 (int) session->myip[0], (int) session->myip[1],
1724 (int) session->myip[2], (int) session->myip[3],
1725 (int) session->peerip[0], (int) session->peerip[1],
1726 (int) session->peerip[2], (int) session->peerip[3]);
1727 syslog(LOG_INFO,
1728 "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
1729 (unsigned int) ntohs(session->sess),
1730 session->eth[0], session->eth[1], session->eth[2],
1731 session->eth[3], session->eth[4], session->eth[5],
1732 (int) session->peerip[0], (int) session->peerip[1],
1733 (int) session->peerip[2], (int) session->peerip[3],
1734 session->ethif->name,
1735 session->serviceName);
1736 argv[c++] = strdup(buffer);
1737 if (!argv[c-1]) {
1738 /* TODO: Send a PADT */
1739 exit(EXIT_FAILURE);
1740 }
1741 argv[c++] = "nodetach";
1742 argv[c++] = "noaccomp";
1743 argv[c++] = "nobsdcomp";
1744 argv[c++] = "nodeflate";
1745 argv[c++] = "nopcomp";
1746 argv[c++] = "novj";
1747 argv[c++] = "novjccomp";
1748 argv[c++] = "default-asyncmap";
1749 if (Synchronous) {
1750 argv[c++] = "sync";
1751 }
1752 if (PassUnitOptionToPPPD) {
1753 argv[c++] = "unit";
1754 sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
1755 argv[c++] = buffer;
1756 }
1757 argv[c++] = NULL;
1758
1759 execv(PPPD_PATH, argv);
1760 exit(EXIT_FAILURE);
1761}
1762
1763/**********************************************************************
1764*%FUNCTION: startPPPDLinuxKernelMode
1765*%ARGUMENTS:
1766* session -- client session record
1767*%RETURNS:
1768* Nothing
1769*%DESCRIPTION:
1770* Starts PPPD for kernel-mode PPPoE on Linux
1771***********************************************************************/
1772void
1773startPPPDLinuxKernelMode(ClientSession *session)
1774{
1775 /* Leave some room */
1776 char *argv[32];
1777
1778 int c = 0;
1779
1780 char buffer[SMALLBUF];
1781
1782 argv[c++] = "pppd";
1783 argv[c++] = "plugin";
1784 argv[c++] = PLUGIN_PATH;
1785
1786 /* Add "nic-" to interface name */
1787 snprintf(buffer, SMALLBUF, "nic-%s", session->ethif->name);
1788 argv[c++] = strdup(buffer);
1789 if (!argv[c-1]) {
1790 exit(EXIT_FAILURE);
1791 }
1792
1793 snprintf(buffer, SMALLBUF, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
1794 (unsigned int) ntohs(session->sess),
1795 session->eth[0], session->eth[1], session->eth[2],
1796 session->eth[3], session->eth[4], session->eth[5]);
1797 argv[c++] = "rp_pppoe_sess";
1798 argv[c++] = strdup(buffer);
1799 if (!argv[c-1]) {
1800 /* TODO: Send a PADT */
1801 exit(EXIT_FAILURE);
1802 }
1803 argv[c++] = "rp_pppoe_service";
1804 argv[c++] = (char *) session->serviceName;
1805 argv[c++] = "file";
1806 argv[c++] = pppoptfile;
1807
1808 snprintf(buffer, SMALLBUF, "%d.%d.%d.%d:%d.%d.%d.%d",
1809 (int) session->myip[0], (int) session->myip[1],
1810 (int) session->myip[2], (int) session->myip[3],
1811 (int) session->peerip[0], (int) session->peerip[1],
1812 (int) session->peerip[2], (int) session->peerip[3]);
1813 syslog(LOG_INFO,
1814 "Session %u created for client %02x:%02x:%02x:%02x:%02x:%02x (%d.%d.%d.%d) on %s using Service-Name '%s'",
1815 (unsigned int) ntohs(session->sess),
1816 session->eth[0], session->eth[1], session->eth[2],
1817 session->eth[3], session->eth[4], session->eth[5],
1818 (int) session->peerip[0], (int) session->peerip[1],
1819 (int) session->peerip[2], (int) session->peerip[3],
1820 session->ethif->name,
1821 session->serviceName);
1822 argv[c++] = strdup(buffer);
1823 if (!argv[c-1]) {
1824 /* TODO: Send a PADT */
1825 exit(EXIT_FAILURE);
1826 }
1827 argv[c++] = "nodetach";
1828 argv[c++] = "noaccomp";
1829 argv[c++] = "nobsdcomp";
1830 argv[c++] = "nodeflate";
1831 argv[c++] = "nopcomp";
1832 argv[c++] = "novj";
1833 argv[c++] = "novjccomp";
1834 argv[c++] = "default-asyncmap";
1835 if (PassUnitOptionToPPPD) {
1836 argv[c++] = "unit";
1837 sprintf(buffer, "%u", (unsigned int) (ntohs(session->sess) - 1 - SessOffset));
1838 argv[c++] = buffer;
1839 }
1840 argv[c++] = NULL;
1841 execv(PPPD_PATH, argv);
1842 exit(EXIT_FAILURE);
1843}
1844
1845/**********************************************************************
1846*%FUNCTION: startPPPD
1847*%ARGUMENTS:
1848* session -- client session record
1849*%RETURNS:
1850* Nothing
1851*%DESCRIPTION:
1852* Starts PPPD
1853***********************************************************************/
1854void
1855startPPPD(ClientSession *session)
1856{
1857 if (UseLinuxKernelModePPPoE) startPPPDLinuxKernelMode(session);
1858 else startPPPDUserMode(session);
1859}
1860
1861/**********************************************************************
1862* %FUNCTION: InterfaceHandler
1863* %ARGUMENTS:
1864* es -- event selector (ignored)
1865* fd -- file descriptor which is readable
1866* flags -- ignored
1867* data -- Pointer to the Interface structure
1868* %RETURNS:
1869* Nothing
1870* %DESCRIPTION:
1871* Handles a packet ready at an interface
1872***********************************************************************/
1873void
1874InterfaceHandler(EventSelector *es,
1875 int fd,
1876 unsigned int flags,
1877 void *data)
1878{
1879 serverProcessPacket((Interface *) data);
1880}
1881
1882/**********************************************************************
1883* %FUNCTION: PppoeStopSession
1884* %ARGUMENTS:
1885* ses -- the session
1886* reason -- reason session is being stopped.
1887* %RETURNS:
1888* Nothing
1889* %DESCRIPTION:
1890* Kills pppd.
1891***********************************************************************/
1892static void
1893PppoeStopSession(ClientSession *ses,
1894 char const *reason)
1895{
1896 /* Temporary structure for sending PADT's. */
1897 PPPoEConnection conn;
1898
1899 memset(&conn, 0, sizeof(conn));
1900 conn.useHostUniq = 0;
1901
1902 memcpy(conn.myEth, ses->ethif->mac, ETH_ALEN);
1903 conn.discoverySocket = ses->ethif->sock;
1904 conn.session = ses->sess;
1905 memcpy(conn.peerEth, ses->eth, ETH_ALEN);
1906 sendPADT(&conn, reason);
1907 ses->flags |= FLAG_SENT_PADT;
1908
1909 if (ses->pid) {
1910 kill(ses->pid, SIGTERM);
1911 }
1912 ses->funcs = &DefaultSessionFunctionTable;
1913}
1914
1915/**********************************************************************
1916* %FUNCTION: PppoeSessionIsActive
1917* %ARGUMENTS:
1918* ses -- the session
1919* %RETURNS:
1920* True if session is active, false if not.
1921***********************************************************************/
1922static int
1923PppoeSessionIsActive(ClientSession *ses)
1924{
1925 return (ses->pid != 0);
1926}
1927
1928#ifdef HAVE_LICENSE
1929/**********************************************************************
1930* %FUNCTION: getFreeMem
1931* %ARGUMENTS:
1932* None
1933* %RETURNS:
1934* The amount of free RAM in kilobytes, or -1 if it could not be
1935* determined
1936* %DESCRIPTION:
1937* Reads Linux-specific /proc/meminfo file and extracts free RAM
1938***********************************************************************/
1939int
1940getFreeMem(void)
1941{
1942 char buf[512];
1943 int memfree=0, buffers=0, cached=0;
1944 FILE *fp = fopen("/proc/meminfo", "r");
1945 if (!fp) return -1;
1946
1947 while (fgets(buf, sizeof(buf), fp)) {
1948 if (!strncmp(buf, "MemFree:", 8)) {
1949 if (sscanf(buf, "MemFree: %d", &memfree) != 1) {
1950 fclose(fp);
1951 return -1;
1952 }
1953 } else if (!strncmp(buf, "Buffers:", 8)) {
1954 if (sscanf(buf, "Buffers: %d", &buffers) != 1) {
1955 fclose(fp);
1956 return -1;
1957 }
1958 } else if (!strncmp(buf, "Cached:", 7)) {
1959 if (sscanf(buf, "Cached: %d", &cached) != 1) {
1960 fclose(fp);
1961 return -1;
1962 }
1963 }
1964 }
1965 fclose(fp);
1966 /* return memfree + buffers + cached; */
1967 return memfree;
1968}
1969#endif
1970
1971/**********************************************************************
1972* %FUNCTION: pppoe_alloc_session
1973* %ARGUMENTS:
1974* None
1975* %RETURNS:
1976* NULL if no session is available, otherwise a ClientSession structure.
1977* %DESCRIPTION:
1978* Allocates a ClientSession structure and removes from free list, puts
1979* on busy list
1980***********************************************************************/
1981ClientSession *
1982pppoe_alloc_session(void)
1983{
1984 ClientSession *ses = FreeSessions;
1985 if (!ses) return NULL;
1986
1987 /* Remove from free sessions list */
1988 if (ses == LastFreeSession) {
1989 LastFreeSession = NULL;
1990 }
1991 FreeSessions = ses->next;
1992
1993 /* Put on busy sessions list */
1994 ses->next = BusySessions;
1995 BusySessions = ses;
1996
1997 /* Initialize fields to sane values */
1998 ses->funcs = &DefaultSessionFunctionTable;
1999 ses->pid = 0;
2000 ses->ethif = NULL;
2001 memset(ses->eth, 0, ETH_ALEN);
2002 ses->flags = 0;
2003 ses->startTime = time(NULL);
2004 ses->serviceName = "";
2005#ifdef HAVE_LICENSE
2006 memset(ses->user, 0, MAX_USERNAME_LEN+1);
2007 memset(ses->realm, 0, MAX_USERNAME_LEN+1);
2008 memset(ses->realpeerip, 0, IPV4ALEN);
2009#endif
2010#ifdef HAVE_L2TP
2011 ses->l2tp_ses = NULL;
2012#endif
2013 NumActiveSessions++;
2014 return ses;
2015}
2016
2017/**********************************************************************
2018* %FUNCTION: pppoe_free_session
2019* %ARGUMENTS:
2020* ses -- session to free
2021* %RETURNS:
2022* 0 if OK, -1 if error
2023* %DESCRIPTION:
2024* Places a ClientSession on the free list.
2025***********************************************************************/
2026int
2027pppoe_free_session(ClientSession *ses)
2028{
2029 ClientSession *cur, *prev;
2030
2031 cur = BusySessions;
2032 prev = NULL;
2033 while (cur) {
2034 if (ses == cur) break;
2035 prev = cur;
2036 cur = cur->next;
2037 }
2038
2039 if (!cur) {
2040 syslog(LOG_ERR, "pppoe_free_session: Could not find session %p on busy list", (void *) ses);
2041 return -1;
2042 }
2043
2044 /* Remove from busy sessions list */
2045 if (prev) {
2046 prev->next = ses->next;
2047 } else {
2048 BusySessions = ses->next;
2049 }
2050
2051 /* Add to end of free sessions */
2052 ses->next = NULL;
2053 if (LastFreeSession) {
2054 LastFreeSession->next = ses;
2055 LastFreeSession = ses;
2056 } else {
2057 FreeSessions = ses;
2058 LastFreeSession = ses;
2059 }
2060
2061 /* Initialize fields to sane values */
2062 ses->funcs = &DefaultSessionFunctionTable;
2063 ses->pid = 0;
2064 ses->flags = 0;
2065#ifdef HAVE_L2TP
2066 ses->l2tp_ses = NULL;
2067#endif
2068 NumActiveSessions--;
2069 return 0;
2070}
2071
2072/**********************************************************************
2073* %FUNCTION: sendHURLorMOTM
2074* %ARGUMENTS:
2075* conn -- PPPoE connection
2076* url -- a URL, which *MUST* begin with "http://" or it won't be sent, or
2077* a message.
2078* tag -- one of TAG_HURL or TAG_MOTM
2079* %RETURNS:
2080* Nothing
2081* %DESCRIPTION:
2082* Sends a PADM packet contaning a HURL or MOTM tag to the victim...er, peer.
2083***********************************************************************/
2084void
2085sendHURLorMOTM(PPPoEConnection *conn, char const *url, UINT16_t tag)
2086{
2087 PPPoEPacket packet;
2088 PPPoETag hurl;
2089 size_t elen;
2090 unsigned char *cursor = packet.payload;
2091 UINT16_t plen = 0;
2092
2093 if (!conn->session) return;
2094 if (conn->discoverySocket < 0) return;
2095
2096 if (tag == TAG_HURL) {
2097 if (strncmp(url, "http://", 7)) {
2098 syslog(LOG_WARNING, "sendHURL(%s): URL must begin with http://", url);
2099 return;
2100 }
2101 } else {
2102 tag = TAG_MOTM;
2103 }
2104
2105 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
2106 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
2107
2108 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
2109 packet.ver = 1;
2110 packet.type = 1;
2111 packet.code = CODE_PADM;
2112 packet.session = conn->session;
2113
2114 elen = strlen(url);
2115 if (elen > 256) {
2116 syslog(LOG_WARNING, "MOTM or HURL too long: %d", (int) elen);
2117 return;
2118 }
2119
2120 hurl.type = htons(tag);
2121 hurl.length = htons(elen);
2122 strcpy((char *) hurl.payload, url);
2123 memcpy(cursor, &hurl, elen + TAG_HDR_SIZE);
2124 cursor += elen + TAG_HDR_SIZE;
2125 plen += elen + TAG_HDR_SIZE;
2126
2127 packet.length = htons(plen);
2128
2129 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
2130#ifdef DEBUGGING_ENABLED
2131 if (conn->debugFile) {
2132 dumpPacket(conn->debugFile, &packet, "SENT");
2133 fprintf(conn->debugFile, "\n");
2134 fflush(conn->debugFile);
2135 }
2136#endif
2137}
2138