1 /***********************************************************************
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.
16 ***********************************************************************/
18 static char const RCSID
[] =
23 #if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H)
24 #define _POSIX_SOURCE 1 /* For sigaction defines */
27 #define _BSD_SOURCE 1 /* for gethostname */
29 #include "pppoe-server.h"
50 #ifdef HAVE_SYS_WAIT_H
54 #ifdef HAVE_SYS_TIME_H
64 #include "licensed-only/servfuncs.h"
65 static struct License
const *ServerLicense
;
66 static struct License
const *ClusterLicense
;
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
75 extern PppoeSessionFunctionTable L2TPSessionFunctionTable
;
76 extern void pppoe_to_l2tp_add_interface(EventSelector
*es
,
77 Interface
*interface
);
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) \
88 if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
89 syslog(LOG_ERR, "Would create too-long packet"); \
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
= {
104 PppoeSessionIsActive
,
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;
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 */
160 #define COOKIE_LEN (MD5_LEN + sizeof(pid_t)) /* Cookie is 16-byte MD5 + PID of server */
162 static unsigned char CookieSeed
[SEED_LEN
];
166 /* Default interface if no -I option given */
167 #define DEFAULT_IF "eth0"
169 /* Access concentrator name */
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? */
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
196 count_sessions_from_mac(unsigned char *eth
)
199 ClientSession
*s
= BusySessions
;
201 if (!memcmp(eth
, s
->eth
, ETH_ALEN
)) n
++;
207 /**********************************************************************
208 *%FUNCTION: childHandler
210 * pid -- pid of child
211 * status -- exit status
212 * ses -- which session terminated
216 * Called synchronously when a child dies. Remove from busy list.
217 ***********************************************************************/
219 childHandler(pid_t pid
, int status
, void *s
)
221 ClientSession
*session
= s
;
223 /* Temporary structure for sending PADT's. */
224 PPPoEConnection conn
;
227 /* We're acting as LAC, so when child exits, become a PPPoE <-> L2TP
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
));
237 session
->funcs
= &L2TPSessionFunctionTable
;
242 memset(&conn
, 0, sizeof(conn
));
243 conn
.useHostUniq
= 0;
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");
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) {
275 /**********************************************************************
276 *%FUNCTION: incrementIPAddress (static)
278 * addr -- a 4-byte array representing IP address
282 * Increments addr in-place
283 ***********************************************************************/
285 incrementIPAddress(unsigned char ip
[IPV4ALEN
])
299 /**********************************************************************
300 *%FUNCTION: killAllSessions
306 * Kills all pppd processes (and hence all PPPoE sessions)
307 ***********************************************************************/
309 killAllSessions(void)
311 ClientSession
*sess
= BusySessions
;
313 sess
->funcs
->stop(sess
, "Shutting Down");
317 pppoe_close_l2tp_tunnels();
321 /**********************************************************************
322 *%FUNCTION: parseAddressPool
324 * fname -- name of file containing IP address pool.
325 * install -- if true, install IP addresses in sessions.
327 * Number of valid IP addresses found.
329 * Reads a list of IP addresses from a file.
330 ***********************************************************************/
332 parseAddressPool(char const *fname
, int install
)
334 FILE *fp
= fopen(fname
, "r");
336 unsigned int a
, b
, c
, d
;
337 unsigned int e
, f
, g
, h
;
341 sysErr("Cannot open address pool file");
346 if (!fgets(line
, MAXLINE
, fp
)) {
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) */
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
;
365 memcpy(Sessions
[numAddrs
].realpeerip
,
366 Sessions
[numAddrs
].peerip
, IPV4ALEN
);
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 */
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
;
387 memcpy(Sessions
[numAddrs
].realpeerip
,
388 Sessions
[numAddrs
].peerip
, IPV4ALEN
);
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 */
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
;
405 memcpy(Sessions
[numAddrs
].realpeerip
,
406 Sessions
[numAddrs
].peerip
, IPV4ALEN
);
414 rp_fatal("No valid ip addresses found in pool file");
419 /**********************************************************************
420 *%FUNCTION: parsePADITags
425 * extra -- extra user data.
429 * Picks interesting tags out of a PADI packet
430 ***********************************************************************/
432 parsePADITags(UINT16_t type
, UINT16_t len
, unsigned char *data
,
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
) {
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
);
451 case TAG_RELAY_SESSION_ID
:
452 relayId
.type
= htons(type
);
453 relayId
.length
= htons(len
);
454 memcpy(relayId
.payload
, data
, len
);
457 hostUniq
.type
= htons(type
);
458 hostUniq
.length
= htons(len
);
459 memcpy(hostUniq
.payload
, data
, len
);
464 /**********************************************************************
465 *%FUNCTION: parsePADRTags
470 * extra -- extra user data.
474 * Picks interesting tags out of a PADR packet
475 ***********************************************************************/
477 parsePADRTags(UINT16_t type
, UINT16_t len
, unsigned char *data
,
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
) {
490 case TAG_RELAY_SESSION_ID
:
491 relayId
.type
= htons(type
);
492 relayId
.length
= htons(len
);
493 memcpy(relayId
.payload
, data
, len
);
496 hostUniq
.type
= htons(type
);
497 hostUniq
.length
= htons(len
);
498 memcpy(hostUniq
.payload
, data
, len
);
501 receivedCookie
.type
= htons(type
);
502 receivedCookie
.length
= htons(len
);
503 memcpy(receivedCookie
.payload
, data
, len
);
505 case TAG_SERVICE_NAME
:
506 requestedService
.type
= htons(type
);
507 requestedService
.length
= htons(len
);
508 memcpy(requestedService
.payload
, data
, len
);
513 /**********************************************************************
516 * str -- error message
520 * Prints a message plus the errno value to stderr and syslog and exits.
521 ***********************************************************************/
523 fatalSys(char const *str
)
526 snprintf(buf
, SMALLBUF
, "%s: %s", str
, strerror(errno
));
532 /**********************************************************************
535 * str -- error message
539 * Prints a message plus the errno value to syslog.
540 ***********************************************************************/
542 sysErr(char const *str
)
545 sprintf(buf
, "%.256s: %.256s", str
, strerror(errno
));
549 /**********************************************************************
552 * str -- error message
556 * Prints a message to stderr and syslog and exits.
557 ***********************************************************************/
559 rp_fatal(char const *str
)
566 /**********************************************************************
567 *%FUNCTION: genCookie
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
577 * Forms the md5 sum of peer MAC address, our MAC address and seed, useful
578 * in a PPPoE Cookie tag.
579 ***********************************************************************/
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();
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
601 * packet -- PPPoE PADI packet
602 * len -- length of received packet
606 * Sends a PADO packet back to client
607 ***********************************************************************/
609 processPADI(Interface
*ethif
, PPPoEPacket
*packet
, int len
)
616 unsigned char *cursor
= pado
.payload
;
619 int sock
= ethif
->sock
;
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");
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");
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],
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
);
659 requestedService
.type
= 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
);
669 for (i
=0; i
<NumServiceNames
; i
++) {
670 if (slen
== strlen(ServiceNames
[i
]) &&
671 !memcmp(ServiceNames
[i
], &requestedService
.payload
, slen
)) {
677 ok
= 1; /* Default service requested */
680 ok
= 1; /* No Service-Name tag in PADI */
684 /* PADI asked for unsupported service */
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
);
699 pado
.code
= CODE_PADO
;
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
) {
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
) {
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
;
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
;
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
;
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
774 * packet -- PPPoE PADT packet
775 * len -- length of received packet
779 * Kills session whose session-ID is in PADT packet.
780 ***********************************************************************/
782 processPADT(Interface
*ethif
, PPPoEPacket
*packet
, int len
)
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
));
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],
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
829 * ethif -- Ethernet interface
830 * packet -- PPPoE PADR packet
831 * len -- length of received packet
835 * Sends a PADS packet back to client and starts a PPP session if PADR
837 ***********************************************************************/
839 processPADR(Interface
*ethif
, PPPoEPacket
*packet
, int len
)
841 unsigned char cookieBuffer
[COOKIE_LEN
];
842 ClientSession
*cliSession
;
845 unsigned char *cursor
= pads
.payload
;
848 int sock
= ethif
->sock
;
849 unsigned char *myAddr
= ethif
->mac
;
851 char const *serviceName
= NULL
;
857 /* Initialize some globals */
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");
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],
889 parsePacket(packet
, parsePADRTags
, NULL
);
891 /* Check that everything's cool */
892 if (!receivedCookie
.type
) {
893 /* Drop it -- do not send error PADS */
897 /* Is cookie kosher? */
898 if (receivedCookie
.length
!= htons(COOKIE_LEN
)) {
899 /* Drop it -- do not send error PADS */
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 */
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");
917 slen
= ntohs(requestedService
.length
);
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
];
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");
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");
954 /* Enough free memory? */
956 freemem
= getFreeMem();
957 if (freemem
< MIN_FREE_MEMORY
) {
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");
966 /* Looks cool... find a slot for the session */
967 cliSession
= pppoe_alloc_session();
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");
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 */
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
);
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
);
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 */
1014 if (LockFD
>= 0) close(LockFD
);
1015 for (i
=0; i
<CLOSEFD
; 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! */
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
);
1032 pads
.code
= CODE_PADS
;
1034 pads
.session
= cliSession
->sess
;
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
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
;
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 */
1088 startPPPD(cliSession
);
1091 /**********************************************************************
1092 *%FUNCTION: termHandler
1094 * sig -- signal number
1098 * Called by SIGTERM or SIGINT. Causes all sessions to be killed!
1099 ***********************************************************************/
1101 termHandler(int sig
)
1104 "Terminating on signal %d -- killing all PPPoE sessions",
1111 /**********************************************************************
1114 * argv0 -- argv[0] from main
1118 * Prints usage instructions
1119 ***********************************************************************/
1121 usage(char const *argv0
)
1123 fprintf(stderr
, "Usage: %s [options]\n", argv0
);
1124 fprintf(stderr
, "Options:\n");
1126 fprintf(stderr
, " -I if_name -- Specify interface (REQUIRED)\n");
1128 fprintf(stderr
, " -I if_name -- Specify interface (default %s.)\n",
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");
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");
1157 fprintf(stderr
, " -c secret:if:port -- Enable clustering on interface 'if'.\n");
1158 fprintf(stderr
, " -1 -- Allow only one session per user.\n");
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");
1171 fprintf(stderr
, "http://www.roaringpenguin.com\n");
1174 /**********************************************************************
1177 * argc, argv -- usual suspects
1181 * Main program of PPPoE server
1182 ***********************************************************************/
1184 main(int argc
, char **argv
)
1193 unsigned int discoveryType
, sessionType
;
1194 char *addressPoolFname
= NULL
;
1195 char *pidfile
= NULL
;
1199 int use_clustering
= 0;
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:";
1205 char *options
= "X:ix:hI:C:L:R:T:m:FN:f:O:o:skp:lrudPc:S:1q:Q:";
1208 if (getuid() != geteuid() ||
1209 getgid() != getegid()) {
1210 fprintf(stderr
, "SECURITY WARNING: pppoe-server will NOT run suid or sgid. Fix your installation.\n");
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) {
1228 IgnorePADIIfNoFreeSessions
= 1;
1231 if (sscanf(optarg
, "%d", &MaxSessionsPerMac
) != 1) {
1235 if (MaxSessionsPerMac
< 0) {
1236 MaxSessionsPerMac
= 0;
1240 #ifdef HAVE_LINUX_KERNEL_PPPOE
1242 UseLinuxKernelModePPPoE
= 1;
1246 if (NumServiceNames
== MAX_SERVICE_NAMES
) {
1247 fprintf(stderr
, "Too many '-S' options (%d max)",
1251 ServiceNames
[NumServiceNames
] = strdup(optarg
);
1252 if (!ServiceNames
[NumServiceNames
]) {
1253 fprintf(stderr
, "Out of memory");
1259 pppd_path
= strdup(optarg
);
1261 fprintf(stderr
, "Out of memory");
1266 pppoe_path
= strdup(optarg
);
1268 fprintf(stderr
, "Out of memory");
1274 #ifndef HAVE_LICENSE
1275 fprintf(stderr
, "Clustering capability not available.\n");
1278 cluster_handle_option(optarg
);
1287 CheckPoolSyntax
= 1;
1290 PassUnitOptionToPPPD
= 1;
1294 RandomizeSessionNumbers
= 1;
1302 SET_STRING(addressPoolFname
, optarg
);
1306 SET_STRING(pidfile
, optarg
);
1310 /* Pass the Synchronous option on to pppoe */
1311 snprintf(PppoeOptions
+ strlen(PppoeOptions
),
1312 SMALLBUF
-strlen(PppoeOptions
),
1317 if (sscanf(optarg
, "%x:%x", &discoveryType
, &sessionType
) != 2) {
1318 fprintf(stderr
, "Illegal argument to -f: Should be disc:sess in hex\n");
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
);
1334 if (sscanf(optarg
, "%d", &opt
) != 1) {
1339 fprintf(stderr
, "-N: Value must be positive\n");
1342 NumSessionSlots
= opt
;
1346 SET_STRING(pppoptfile
, optarg
);
1350 if (sscanf(optarg
, "%d", &opt
) != 1) {
1355 fprintf(stderr
, "-o: Value must be non-negative\n");
1358 SessOffset
= (size_t) opt
;
1362 if (NumInterfaces
>= MAX_INTERFACES
) {
1363 fprintf(stderr
, "Too many -I options (max %d)\n",
1368 for (i
=0; i
<NumInterfaces
; i
++) {
1369 if (!strncmp(interfaces
[i
].name
, optarg
, IFNAMSIZ
)) {
1375 strncpy(interfaces
[NumInterfaces
].name
, optarg
, IFNAMSIZ
);
1381 SET_STRING(ACName
, optarg
);
1386 /* Get local/remote IP address */
1387 if (sscanf(optarg
, "%d.%d.%d.%d", &d
[0], &d
[1], &d
[2], &d
[3]) != 4) {
1391 for (i
=0; i
<IPV4ALEN
; i
++) {
1392 if (d
[i
] < 0 || d
[i
] > 255) {
1397 LocalIP
[i
] = (unsigned char) d
[i
];
1399 RemoteIP
[i
] = (unsigned char) d
[i
];
1406 /* These just get passed to pppoe */
1407 snprintf(PppoeOptions
+ strlen(PppoeOptions
),
1408 SMALLBUF
-strlen(PppoeOptions
),
1409 " -%c %s", opt
, optarg
);
1417 MaxSessionsPerUser
= 1;
1419 fprintf(stderr
, "-1 option not valid.\n");
1427 pppoptfile
= PPPOE_SERVER_OPTIONS
;
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());
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");
1449 if (!NumInterfaces
) {
1450 strcpy(interfaces
[0].name
, DEFAULT_IF
);
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
);
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");
1476 /* Allocate memory for sessions */
1477 Sessions
= calloc(NumSessionSlots
, sizeof(ClientSession
));
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
));
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
));
1504 memcpy(Sessions
[i
].realpeerip
, RemoteIP
, sizeof(RemoteIP
));
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");
1515 fread(&x
, 1, sizeof(x
), fp
);
1517 fread(&CookieSeed
, 1, SEED_LEN
, fp
);
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
) {
1531 permutation
= malloc(sizeof(int) * NumSessionSlots
);
1533 fprintf(stderr
, "Could not allocate memory to randomize session numbers\n");
1536 for (i
=0; i
<NumSessionSlots
; i
++) {
1539 for (i
=0; i
<NumSessionSlots
-1; i
++) {
1540 j
= i
+ rand() % (NumSessionSlots
- 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
;
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
;
1566 /* Dump session array and exit */
1567 ClientSession
*ses
= FreeSessions
;
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]);
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 */
1597 if (control_init(argc
, argv
, event_selector
)) {
1598 rp_fatal("control_init failed");
1602 /* Create event handler for each interface */
1603 for (i
= 0; i
<NumInterfaces
; i
++) {
1604 interfaces
[i
].eh
= Event_AddHandler(event_selector
,
1606 EVENT_FLAG_READABLE
,
1610 interfaces
[i
].session_sock
= -1;
1612 if (!interfaces
[i
].eh
) {
1613 rp_fatal("Event_AddHandler failed");
1618 if (use_clustering
) {
1619 ClusterLicense
= License_GetFeature("PPPOE-CLUSTER");
1620 if (!ClusterLicense
) {
1621 fprintf(stderr
, "License: GetFeature failed: %s\n",
1622 License_ErrorMessage());
1625 if (!License_Expired(ClusterLicense
)) {
1626 if (cluster_init(event_selector
) < 0) {
1627 rp_fatal("cluster_init failed");
1634 for (i
=0; i
<NumInterfaces
; i
++) {
1635 pppoe_to_l2tp_add_interface(event_selector
,
1640 /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
1642 if (pipe(KidPipe
) < 0) {
1648 } else if (i
!= 0) {
1652 /* Wait for child to give the go-ahead */
1654 int r
= read(KidPipe
[0], &c
, 1);
1656 fprintf(stderr
, "EOF from child - something went wrong; please check logs.\n");
1660 if (errno
== EINTR
) continue;
1670 /* Read error message from child */
1672 int r
= read(KidPipe
[0], &c
, 1);
1673 if (r
== 0) exit(EXIT_FAILURE
);
1675 if (errno
== EINTR
) continue;
1678 fprintf(stderr
, "%c", c
);
1683 signal(SIGHUP
, SIG_IGN
);
1687 } else if (i
!= 0) {
1693 if (KidPipe
[0] >= 0) {
1698 /* Point stdin/stdout/stderr to /dev/null */
1699 for (i
=0; i
<3; i
++) {
1702 i
= open("/dev/null", O_RDWR
);
1707 if (i
> 2) close(i
);
1713 if (KidPipe
[1] >= 0) foo
= fdopen(KidPipe
[1], "w");
1716 fl
.l_type
= F_WRLCK
;
1717 fl
.l_whence
= SEEK_SET
;
1720 LockFD
= open(pidfile
, O_RDWR
|O_CREAT
, 0666);
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
));
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
);
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);
1751 i
= Event_HandleEvent(event_selector
);
1753 fatalSys("Event_HandleEvent");
1757 if (License_Expired(ServerLicense
)) {
1758 syslog(LOG_INFO
, "Server license has expired -- killing all PPPoE sessions");
1769 serverProcessPacket(Interface
*i
)
1775 if (receivePacket(sock
, &packet
, &len
) < 0) {
1779 if (len
< HDR_SIZE
) {
1780 /* Impossible - ignore */
1784 /* Sanity check on packet */
1785 if (packet
.ver
!= 1 || packet
.type
!= 1) {
1786 /* Syslog an error */
1791 if (ntohs(packet
.length
) + HDR_SIZE
> len
) {
1792 syslog(LOG_ERR
, "Bogus PPPoE length field (%u)",
1793 (unsigned int) ntohs(packet
.length
));
1797 switch(packet
.code
) {
1799 processPADI(i
, &packet
, len
);
1802 processPADR(i
, &packet
, len
);
1805 /* Kill the child */
1806 processPADT(i
, &packet
, len
);
1809 /* Ignore SESS -- children will handle them */
1813 /* Ignore PADO and PADS totally */
1816 /* Syslog an error */
1821 /**********************************************************************
1822 *%FUNCTION: sendErrorPADS
1824 * sock -- socket to write to
1825 * source -- source Ethernet address
1826 * dest -- destination Ethernet address
1827 * errorTag -- error tag
1828 * errorMsg -- error message
1832 * Sends a PADS packet with an error message
1833 ***********************************************************************/
1835 sendErrorPADS(int sock
,
1836 unsigned char *source
,
1837 unsigned char *dest
,
1842 unsigned char *cursor
= pads
.payload
;
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
);
1852 pads
.code
= CODE_PADS
;
1854 pads
.session
= htons(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
;
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
1883 * session -- client session record
1887 * Starts PPPD for user-mode PPPoE
1888 ***********************************************************************/
1890 startPPPDUserMode(ClientSession
*session
)
1892 /* Leave some room */
1895 char buffer
[SMALLBUF
];
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
);
1911 /* TODO: Send a PADT */
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]);
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
);
1934 /* TODO: Send a PADT */
1937 argv
[c
++] = "nodetach";
1938 argv
[c
++] = "noaccomp";
1939 argv
[c
++] = "nopcomp";
1940 argv
[c
++] = "default-asyncmap";
1944 if (PassUnitOptionToPPPD
) {
1946 sprintf(buffer
, "%u", (unsigned int) (ntohs(session
->sess
) - 1 - SessOffset
));
1949 if (session
->requested_mtu
> 1492) {
1950 sprintf(buffer
, "%u", (unsigned int) session
->requested_mtu
);
1964 execv(pppd_path
, argv
);
1968 /**********************************************************************
1969 *%FUNCTION: startPPPDLinuxKernelMode
1971 * session -- client session record
1975 * Starts PPPD for kernel-mode PPPoE on Linux
1976 ***********************************************************************/
1978 startPPPDLinuxKernelMode(ClientSession
*session
)
1980 /* Leave some room */
1985 char buffer
[SMALLBUF
];
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
);
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
);
2005 /* TODO: Send a PADT */
2008 argv
[c
++] = "rp_pppoe_service";
2009 argv
[c
++] = (char *) session
->serviceName
;
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]);
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
);
2029 /* TODO: Send a PADT */
2032 argv
[c
++] = "nodetach";
2033 argv
[c
++] = "noaccomp";
2034 argv
[c
++] = "nopcomp";
2035 argv
[c
++] = "default-asyncmap";
2036 if (PassUnitOptionToPPPD
) {
2038 sprintf(buffer
, "%u", (unsigned int) (ntohs(session
->sess
) - 1 - SessOffset
));
2041 if (session
->requested_mtu
> 1492) {
2042 sprintf(buffer
, "%u", (unsigned int) session
->requested_mtu
);
2054 execv(pppd_path
, argv
);
2058 /**********************************************************************
2059 *%FUNCTION: startPPPD
2061 * session -- client session record
2066 ***********************************************************************/
2068 startPPPD(ClientSession
*session
)
2070 if (UseLinuxKernelModePPPoE
) startPPPDLinuxKernelMode(session
);
2071 else startPPPDUserMode(session
);
2074 /**********************************************************************
2075 * %FUNCTION: InterfaceHandler
2077 * es -- event selector (ignored)
2078 * fd -- file descriptor which is readable
2080 * data -- Pointer to the Interface structure
2084 * Handles a packet ready at an interface
2085 ***********************************************************************/
2087 InterfaceHandler(EventSelector
*es
,
2092 serverProcessPacket((Interface
*) data
);
2095 /**********************************************************************
2096 * %FUNCTION: PppoeStopSession
2098 * ses -- the session
2099 * reason -- reason session is being stopped.
2104 ***********************************************************************/
2106 PppoeStopSession(ClientSession
*ses
,
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
;
2123 kill(ses
->pid
, SIGTERM
);
2125 ses
->funcs
= &DefaultSessionFunctionTable
;
2128 /**********************************************************************
2129 * %FUNCTION: PppoeSessionIsActive
2131 * ses -- the session
2133 * True if session is active, false if not.
2134 ***********************************************************************/
2136 PppoeSessionIsActive(ClientSession
*ses
)
2138 return (ses
->pid
!= 0);
2142 /**********************************************************************
2143 * %FUNCTION: getFreeMem
2147 * The amount of free RAM in kilobytes, or -1 if it could not be
2150 * Reads Linux-specific /proc/meminfo file and extracts free RAM
2151 ***********************************************************************/
2156 int memfree
=0, buffers
=0, cached
=0;
2157 FILE *fp
= fopen("/proc/meminfo", "r");
2160 while (fgets(buf
, sizeof(buf
), fp
)) {
2161 if (!strncmp(buf
, "MemFree:", 8)) {
2162 if (sscanf(buf
, "MemFree: %d", &memfree
) != 1) {
2166 } else if (!strncmp(buf
, "Buffers:", 8)) {
2167 if (sscanf(buf
, "Buffers: %d", &buffers
) != 1) {
2171 } else if (!strncmp(buf
, "Cached:", 7)) {
2172 if (sscanf(buf
, "Cached: %d", &cached
) != 1) {
2179 /* return memfree + buffers + cached; */
2184 /**********************************************************************
2185 * %FUNCTION: pppoe_alloc_session
2189 * NULL if no session is available, otherwise a ClientSession structure.
2191 * Allocates a ClientSession structure and removes from free list, puts
2193 ***********************************************************************/
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
;
2210 /* Initialize fields to sane values */
2211 ses
->funcs
= &DefaultSessionFunctionTable
;
2214 memset(ses
->eth
, 0, ETH_ALEN
);
2216 ses
->startTime
= time(NULL
);
2217 ses
->serviceName
= "";
2218 ses
->requested_mtu
= 0;
2220 memset(ses
->user
, 0, MAX_USERNAME_LEN
+1);
2221 memset(ses
->realm
, 0, MAX_USERNAME_LEN
+1);
2222 memset(ses
->realpeerip
, 0, IPV4ALEN
);
2225 ses
->l2tp_ses
= NULL
;
2227 NumActiveSessions
++;
2231 /**********************************************************************
2232 * %FUNCTION: pppoe_free_session
2234 * ses -- session to free
2236 * 0 if OK, -1 if error
2238 * Places a ClientSession on the free list.
2239 ***********************************************************************/
2241 pppoe_free_session(ClientSession
*ses
)
2243 ClientSession
*cur
, *prev
;
2248 if (ses
== cur
) break;
2254 syslog(LOG_ERR
, "pppoe_free_session: Could not find session %p on busy list", (void *) ses
);
2258 /* Remove from busy sessions list */
2260 prev
->next
= ses
->next
;
2262 BusySessions
= ses
->next
;
2265 /* Add to end of free sessions */
2267 if (LastFreeSession
) {
2268 LastFreeSession
->next
= ses
;
2269 LastFreeSession
= ses
;
2272 LastFreeSession
= ses
;
2275 /* Initialize fields to sane values */
2276 ses
->funcs
= &DefaultSessionFunctionTable
;
2278 memset(ses
->eth
, 0, ETH_ALEN
);
2281 ses
->l2tp_ses
= NULL
;
2283 NumActiveSessions
--;
2287 /**********************************************************************
2288 * %FUNCTION: sendHURLorMOTM
2290 * conn -- PPPoE connection
2291 * url -- a URL, which *MUST* begin with "http://" or it won't be sent, or
2293 * tag -- one of TAG_HURL or TAG_MOTM
2297 * Sends a PADM packet contaning a HURL or MOTM tag to the victim...er, peer.
2298 ***********************************************************************/
2300 sendHURLorMOTM(PPPoEConnection
*conn
, char const *url
, UINT16_t tag
)
2305 unsigned char *cursor
= packet
.payload
;
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
);
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
);
2326 packet
.code
= CODE_PADM
;
2327 packet
.session
= conn
->session
;
2331 syslog(LOG_WARNING
, "MOTM or HURL too long: %d", (int) elen
);
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
);