+++ /dev/null
-/***********************************************************************
-*
-* debug.c
-*
-* Implementation of user-space PPPoE redirector for Linux.
-*
-* Functions for printing debugging information
-*
-* Copyright (C) 2000 by Roaring Penguin Software Inc.
-*
-* This program may be distributed according to the terms of the GNU
-* General Public License, version 2 or (at your option) any later version.
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: debug.c,v 1.2 2008/06/09 08:34:23 paulus Exp $";
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "pppoe.h"
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <ctype.h>
-
-/**********************************************************************
-*%FUNCTION: dumpHex
-*%ARGUMENTS:
-* fp -- file to dump to
-* buf -- buffer to dump
-* len -- length of data
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Dumps buffer to fp in an easy-to-read format
-***********************************************************************/
-void
-dumpHex(FILE *fp, unsigned char const *buf, int len)
-{
- int i;
- int base;
-
- if (!fp) return;
-
- /* do NOT dump PAP packets */
- if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
- fprintf(fp, "(PAP Authentication Frame -- Contents not dumped)\n");
- return;
- }
-
- for (base=0; base<len; base += 16) {
- for (i=base; i<base+16; i++) {
- if (i < len) {
- fprintf(fp, "%02x ", (unsigned) buf[i]);
- } else {
- fprintf(fp, " ");
- }
- }
- fprintf(fp, " ");
- for (i=base; i<base+16; i++) {
- if (i < len) {
- if (isprint(buf[i])) {
- fprintf(fp, "%c", buf[i]);
- } else {
- fprintf(fp, ".");
- }
- } else {
- break;
- }
- }
- fprintf(fp, "\n");
- }
-}
-
-/**********************************************************************
-*%FUNCTION: dumpPacket
-*%ARGUMENTS:
-* fp -- file to dump to
-* packet -- a PPPoE packet
-* dir -- either SENT or RCVD
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Dumps the PPPoE packet to fp in an easy-to-read format
-***********************************************************************/
-void
-dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir)
-{
- int len = ntohs(packet->length);
-
- /* Sheesh... printing times is a pain... */
- struct timeval tv;
- time_t now;
- int millisec;
- struct tm *lt;
- char timebuf[256];
-
- UINT16_t type = etherType(packet);
- if (!fp) return;
- gettimeofday(&tv, NULL);
- now = (time_t) tv.tv_sec;
- millisec = tv.tv_usec / 1000;
- lt = localtime(&now);
- strftime(timebuf, 256, "%H:%M:%S", lt);
- fprintf(fp, "%s.%03d %s PPPoE ", timebuf, millisec, dir);
- if (type == Eth_PPPOE_Discovery) {
- fprintf(fp, "Discovery (%x) ", (unsigned) type);
- } else if (type == Eth_PPPOE_Session) {
- fprintf(fp, "Session (%x) ", (unsigned) type);
- } else {
- fprintf(fp, "Unknown (%x) ", (unsigned) type);
- }
-
- switch(packet->code) {
- case CODE_PADI: fprintf(fp, "PADI "); break;
- case CODE_PADO: fprintf(fp, "PADO "); break;
- case CODE_PADR: fprintf(fp, "PADR "); break;
- case CODE_PADS: fprintf(fp, "PADS "); break;
- case CODE_PADT: fprintf(fp, "PADT "); break;
- case CODE_PADM: fprintf(fp, "PADM "); break;
- case CODE_PADN: fprintf(fp, "PADN "); break;
- case CODE_SESS: fprintf(fp, "SESS "); break;
- }
-
- fprintf(fp, "sess-id %d length %d\n",
- (int) ntohs(packet->session),
- len);
-
- /* Ugly... I apologize... */
- fprintf(fp,
- "SourceAddr %02x:%02x:%02x:%02x:%02x:%02x "
- "DestAddr %02x:%02x:%02x:%02x:%02x:%02x\n",
- (unsigned) packet->ethHdr.h_source[0],
- (unsigned) packet->ethHdr.h_source[1],
- (unsigned) packet->ethHdr.h_source[2],
- (unsigned) packet->ethHdr.h_source[3],
- (unsigned) packet->ethHdr.h_source[4],
- (unsigned) packet->ethHdr.h_source[5],
- (unsigned) packet->ethHdr.h_dest[0],
- (unsigned) packet->ethHdr.h_dest[1],
- (unsigned) packet->ethHdr.h_dest[2],
- (unsigned) packet->ethHdr.h_dest[3],
- (unsigned) packet->ethHdr.h_dest[4],
- (unsigned) packet->ethHdr.h_dest[5]);
- dumpHex(fp, packet->payload, ntohs(packet->length));
-}
switch(type) {
case TAG_AC_NAME:
pc->seenACName = 1;
- if (conn->printACNames) {
+ if (pppoe_verbose >= 1) {
info("Access-Concentrator: %.*s", (int) len, data);
}
if (conn->acName && len == strlen(conn->acName) &&
break;
case TAG_SERVICE_NAME:
pc->seenServiceName = 1;
+ if (pppoe_verbose >= 1 && len > 0) {
+ info("Service-Name: %.*s", (int) len, data);
+ }
if (conn->serviceName && len == strlen(conn->serviceName) &&
!strncmp((char *) data, conn->serviceName, len)) {
pc->serviceNameOK = 1;
}
break;
case TAG_AC_COOKIE:
- conn->cookie.type = htons(type);
- conn->cookie.length = htons(len);
- memcpy(conn->cookie.payload, data, len);
+ if (pppoe_verbose >= 1) {
+ char buffer[100];
+ char *ptr = buffer;
+ ptr += sprintf(ptr, "Cookie:");
+ /* Print first 20 bytes of cookie */
+ for (i=0; i<len && i < 20; i++) {
+ ptr += sprintf(ptr, " %02x", (unsigned) data[i]);
+ }
+ if (i < len) ptr += sprintf(ptr, "...");
+ info(buffer);
+ }
+ if (conn->discoveryState != STATE_RECEIVED_PADO) {
+ conn->cookie.type = htons(type);
+ conn->cookie.length = htons(len);
+ memcpy(conn->cookie.payload, data, len);
+ }
break;
case TAG_RELAY_SESSION_ID:
- conn->relayId.type = htons(type);
- conn->relayId.length = htons(len);
- memcpy(conn->relayId.payload, data, len);
+ if (pppoe_verbose >= 1) {
+ char buffer[100];
+ char *ptr = buffer;
+ ptr += sprintf(ptr, "Relay-ID:");
+ /* Print first 20 bytes of relay ID */
+ for (i=0; i<len && i < 20; i++) {
+ ptr += printf(ptr, " %02x", (unsigned) data[i]);
+ }
+ if (i < len) ptr += printf(ptr, "...");
+ info(buffer);
+ }
+ if (conn->discoveryState != STATE_RECEIVED_PADO) {
+ conn->relayId.type = htons(type);
+ conn->relayId.length = htons(len);
+ memcpy(conn->relayId.payload, data, len);
+ }
break;
case TAG_PPP_MAX_PAYLOAD:
if (len == sizeof(mru)) {
memcpy(&mru, data, sizeof(mru));
mru = ntohs(mru);
- if (mru >= ETH_PPPOE_MTU) {
- if (lcp_allowoptions[0].mru > mru)
- lcp_allowoptions[0].mru = mru;
- if (lcp_wantoptions[0].mru > mru)
- lcp_wantoptions[0].mru = mru;
+ info("Max-Payload: %u", (unsigned) mru);
+ if (mru >= ETH_PPPOE_MTU && conn->discoveryState != STATE_RECEIVED_PADO) {
+ if (conn->mtu > mru)
+ conn->mtu = mru;
+ if (conn->mru > mru)
+ conn->mru = mru;
conn->seenMaxPayload = 1;
}
}
UINT16_t mru;
switch(type) {
case TAG_SERVICE_NAME:
- dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
+ if (pppoe_verbose >= 1 && len > 0) {
+ info("PADS: Service-Name: '%.*s'", (int) len, data);
+ }
break;
case TAG_PPP_MAX_PAYLOAD:
if (len == sizeof(mru)) {
memcpy(&mru, data, sizeof(mru));
mru = ntohs(mru);
if (mru >= ETH_PPPOE_MTU) {
- if (lcp_allowoptions[0].mru > mru)
- lcp_allowoptions[0].mru = mru;
- if (lcp_wantoptions[0].mru > mru)
- lcp_wantoptions[0].mru = mru;
+ if (conn->mtu > mru)
+ conn->mtu = mru;
+ if (conn->mru > mru)
+ conn->mru = mru;
conn->seenMaxPayload = 1;
}
}
}
/* Add our maximum MTU/MRU */
- if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+ if (MIN(conn->mtu, conn->mru) > ETH_PPPOE_MTU) {
PPPoETag maxPayload;
- UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+ UINT16_t mru = htons(MIN(conn->mtu, conn->mru));
maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
maxPayload.length = htons(sizeof(mru));
memcpy(maxPayload.payload, &mru, sizeof(mru));
pc.seenACName = 0;
pc.seenServiceName = 0;
conn->seenMaxPayload = 0;
- conn->error = 0;
if (get_time(&expire_at) < 0) {
error("get_time (waitForPADO): %m");
return; /* Timed out */
}
+ conn->error = 0;
/* Get the packet */
receivePacket(conn->discoverySocket, &packet, &len);
continue;
}
if (parsePacket(&packet, parsePADOTags, &pc) < 0)
- return;
+ continue;
if (conn->error)
- return;
+ continue;
if (!pc.seenACName) {
error("Ignoring PADO packet with no AC-Name tag");
continue;
error("Ignoring PADO packet with no Service-Name tag");
continue;
}
+ if (pppoe_verbose >= 1) {
+ info("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned) packet.ethHdr.h_source[0],
+ (unsigned) packet.ethHdr.h_source[1],
+ (unsigned) packet.ethHdr.h_source[2],
+ (unsigned) packet.ethHdr.h_source[3],
+ (unsigned) packet.ethHdr.h_source[4],
+ (unsigned) packet.ethHdr.h_source[5]);
+ info("--------------------------------------------------");
+ }
conn->numPADOs++;
- if (pc.acNameOK && pc.serviceNameOK) {
+ if (pc.acNameOK && pc.serviceNameOK && conn->discoveryState != STATE_RECEIVED_PADO) {
memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
conn->discoveryState = STATE_RECEIVED_PADO;
- break;
}
}
- } while (conn->discoveryState != STATE_RECEIVED_PADO);
+ } while (pppoe_verbose >= 1 || conn->discoveryState != STATE_RECEIVED_PADO);
}
/***********************************************************************
}
/* Add our maximum MTU/MRU */
- if (MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru) > ETH_PPPOE_MTU) {
+ if (MIN(conn->mtu, conn->mru) > ETH_PPPOE_MTU) {
PPPoETag maxPayload;
- UINT16_t mru = htons(MIN(lcp_allowoptions[0].mru, lcp_wantoptions[0].mru));
+ UINT16_t mru = htons(MIN(conn->mtu, conn->mru));
maxPayload.type = htons(TAG_PPP_MAX_PAYLOAD);
maxPayload.length = htons(sizeof(mru));
memcpy(maxPayload.payload, &mru, sizeof(mru));
}
/**********************************************************************
-*%FUNCTION: discovery
+*%FUNCTION: discovery1
*%ARGUMENTS:
* conn -- PPPoE connection info structure
*%RETURNS:
* Nothing
*%DESCRIPTION:
-* Performs the PPPoE discovery phase
+* Performs the PPPoE discovery phase 1
***********************************************************************/
void
-discovery(PPPoEConnection *conn)
+discovery1(PPPoEConnection *conn)
{
int padiAttempts = 0;
- int padrAttempts = 0;
int timeout = conn->discoveryTimeout;
do {
timeout *= 2;
} while (conn->discoveryState == STATE_SENT_PADI);
+}
+
+/**********************************************************************
+*%FUNCTION: discovery2
+*%ARGUMENTS:
+* conn -- PPPoE connection info structure
+*%RETURNS:
+* Nothing
+*%DESCRIPTION:
+* Performs the PPPoE discovery phase 2
+***********************************************************************/
+void
+discovery2(PPPoEConnection *conn)
+{
+ int padrAttempts = 0;
+ int timeout = conn->discoveryTimeout;
- timeout = conn->discoveryTimeout;
do {
padrAttempts++;
if (got_sigterm || padrAttempts > conn->discoveryAttempts) {
if (!conn->seenMaxPayload) {
/* RFC 4638: MUST limit MTU/MRU to 1492 */
- if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU)
- lcp_allowoptions[0].mru = ETH_PPPOE_MTU;
- if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU)
- lcp_wantoptions[0].mru = ETH_PPPOE_MTU;
+ if (conn->mtu > ETH_PPPOE_MTU)
+ conn->mtu = ETH_PPPOE_MTU;
+ if (conn->mru > ETH_PPPOE_MTU)
+ conn->mru = ETH_PPPOE_MTU;
}
/* We're done. */
#include <errno.h>
#include <string.h>
#include <time.h>
+#include <signal.h>
#include "pppoe.h"
#include <net/if_arp.h>
#endif
-char *xstrdup(const char *s);
-void usage(void);
+int debug;
+int got_sigterm;
+int pppoe_verbose;
+static FILE *debugFile;
-void die(int status)
-{
- exit(status);
-}
-
-void error(char *fmt, ...)
+void
+fatal(char *fmt, ...)
{
va_list pvar;
va_start(pvar, fmt);
vfprintf(stderr, fmt, pvar);
va_end(pvar);
+ fputc('\n', stderr);
+ exit(1);
}
-/* Initialize frame types to RFC 2516 values. Some broken peers apparently
- use different frame types... sigh... */
-
-UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
-UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
-
-/**********************************************************************
-*%FUNCTION: etherType
-*%ARGUMENTS:
-* packet -- a received PPPoE packet
-*%RETURNS:
-* ethernet packet type (see /usr/include/net/ethertypes.h)
-*%DESCRIPTION:
-* Checks the ethernet packet header to determine its type.
-* We should only be receveing DISCOVERY and SESSION types if the BPF
-* is set up correctly. Logs an error if an unexpected type is received.
-* Note that the ethernet type names come from "pppoe.h" and the packet
-* packet structure names use the LINUX dialect to maintain consistency
-* with the rest of this file. See the BSD section of "pppoe.h" for
-* translations of the data structure names.
-***********************************************************************/
-UINT16_t
-etherType(PPPoEPacket *packet)
-{
- UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
- if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
- fprintf(stderr, "Invalid ether type 0x%x\n", type);
- }
- return type;
-}
-
-/**********************************************************************
-*%FUNCTION: openInterface
-*%ARGUMENTS:
-* ifname -- name of interface
-* type -- Ethernet frame type
-* hwaddr -- if non-NULL, set to the hardware address
-*%RETURNS:
-* A raw socket for talking to the Ethernet card. Exits on error.
-*%DESCRIPTION:
-* Opens a raw Ethernet socket
-***********************************************************************/
-int
-openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
+void
+error(char *fmt, ...)
{
- int optval=1;
- int fd;
- struct ifreq ifr;
- int domain, stype;
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- struct sockaddr_ll sa;
-#else
- struct sockaddr sa;
-#endif
-
- memset(&sa, 0, sizeof(sa));
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- domain = PF_PACKET;
- stype = SOCK_RAW;
-#else
- domain = PF_INET;
- stype = SOCK_PACKET;
-#endif
-
- if ((fd = socket(domain, stype, htons(type))) < 0) {
- /* Give a more helpful message for the common error case */
- if (errno == EPERM) {
- fatal("Cannot create raw socket -- pppoe must be run as root.");
- }
- fatalSys("socket");
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
- fatalSys("setsockopt");
- }
-
- /* Fill in hardware address */
- if (hwaddr) {
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
- fatalSys("ioctl(SIOCGIFHWADDR)");
- }
- memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-#ifdef ARPHRD_ETHER
- if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- fatal("Interface %.16s is not Ethernet", ifname);
- }
-#endif
- if (NOT_UNICAST(hwaddr)) {
- fatal("Interface %.16s has broadcast/multicast MAC address??", ifname);
- }
- }
-
- /* Sanity check on MTU */
- strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
- if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
- fatalSys("ioctl(SIOCGIFMTU)");
- }
- if (ifr.ifr_mtu < ETH_DATA_LEN) {
- fprintf(stderr, "Interface %.16s has MTU of %d -- should be %d.\n",
- ifname, ifr.ifr_mtu, ETH_DATA_LEN);
- fprintf(stderr, "You may have serious connection problems.\n");
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_LL
- /* Get interface index */
- sa.sll_family = AF_PACKET;
- sa.sll_protocol = htons(type);
-
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_name[IFNAMSIZ - 1] = 0;
- if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
- fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
- }
- sa.sll_ifindex = ifr.ifr_ifindex;
-
-#else
- strcpy(sa.sa_data, ifname);
-#endif
-
- /* We're only interested in packets on specified interface */
- if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- fatalSys("bind");
- }
-
- return fd;
+ va_list pvar;
+ va_start(pvar, fmt);
+ vfprintf(stderr, fmt, pvar);
+ fputc('\n', stderr);
+ va_end(pvar);
}
-
-/***********************************************************************
-*%FUNCTION: sendPacket
-*%ARGUMENTS:
-* sock -- socket to send to
-* pkt -- the packet to transmit
-* size -- size of packet (in bytes)
-*%RETURNS:
-* 0 on success; -1 on failure
-*%DESCRIPTION:
-* Transmits a packet
-***********************************************************************/
-int
-sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
+void
+warn(char *fmt, ...)
{
-#if defined(HAVE_STRUCT_SOCKADDR_LL)
- if (send(sock, pkt, size, 0) < 0) {
- fatalSys("send (sendPacket)");
- return -1;
- }
-#else
- struct sockaddr sa;
-
- if (!conn) {
- fatal("relay and server not supported on Linux 2.0 kernels");
- }
- strcpy(sa.sa_data, conn->ifName);
- if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
- fatalSys("sendto (sendPacket)");
- return -1;
- }
-#endif
- return 0;
+ va_list pvar;
+ va_start(pvar, fmt);
+ vfprintf(stderr, fmt, pvar);
+ fputc('\n', stderr);
+ va_end(pvar);
}
-/***********************************************************************
-*%FUNCTION: receivePacket
-*%ARGUMENTS:
-* sock -- socket to read from
-* pkt -- place to store the received packet
-* size -- set to size of packet in bytes
-*%RETURNS:
-* >= 0 if all OK; < 0 if error
-*%DESCRIPTION:
-* Receives a packet
-***********************************************************************/
-int
-receivePacket(int sock, PPPoEPacket *pkt, int *size)
+void
+info(char *fmt, ...)
{
- if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
- fatalSys("recv (receivePacket)");
- return -1;
- }
- return 0;
+ va_list pvar;
+ va_start(pvar, fmt);
+ vprintf(fmt, pvar);
+ putchar('\n');
+ va_end(pvar);
}
-/**********************************************************************
-*%FUNCTION: parsePacket
-*%ARGUMENTS:
-* packet -- the PPPoE discovery packet to parse
-* func -- function called for each tag in the packet
-* extra -- an opaque data pointer supplied to parsing function
-*%RETURNS:
-* 0 if everything went well; -1 if there was an error
-*%DESCRIPTION:
-* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
-* "func" is passed the additional argument "extra".
-***********************************************************************/
-int
-parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
+void
+init_pr_log(const char *prefix, int level)
{
- UINT16_t len = ntohs(packet->length);
- unsigned char *curTag;
- UINT16_t tagType, tagLen;
-
- if (PPPOE_VER(packet->vertype) != 1) {
- fprintf(stderr, "Invalid PPPoE version (%d)\n",
- PPPOE_VER(packet->vertype));
- return -1;
- }
- if (PPPOE_TYPE(packet->vertype) != 1) {
- fprintf(stderr, "Invalid PPPoE type (%d)\n",
- PPPOE_TYPE(packet->vertype));
- return -1;
- }
-
- /* Do some sanity checks on packet */
- if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
- fprintf(stderr, "Invalid PPPoE packet length (%u)\n", len);
- return -1;
- }
-
- /* Step through the tags */
- curTag = packet->payload;
- while(curTag - packet->payload < len) {
- /* Alignment is not guaranteed, so do this by hand... */
- tagType = (curTag[0] << 8) + curTag[1];
- tagLen = (curTag[2] << 8) + curTag[3];
- if (tagType == TAG_END_OF_LIST) {
- return 0;
- }
- if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
- fprintf(stderr, "Invalid PPPoE tag length (%u)\n", tagLen);
- return -1;
- }
- func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
- curTag = curTag + TAG_HDR_SIZE + tagLen;
- }
- return 0;
}
-/**********************************************************************
-*%FUNCTION: parseForHostUniq
-*%ARGUMENTS:
-* type -- tag type
-* len -- tag length
-* data -- tag data.
-* extra -- user-supplied pointer. This is assumed to be a pointer to int.
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* If a HostUnique tag is found which matches our PID, sets *extra to 1.
-***********************************************************************/
void
-parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
- void *extra)
+end_pr_log(void)
{
- PPPoETag *tag = extra;
-
- if (type == TAG_HOST_UNIQ && len == ntohs(tag->length))
- tag->length = memcmp(data, tag->payload, len);
+ fflush(debugFile);
}
-/**********************************************************************
-*%FUNCTION: packetIsForMe
-*%ARGUMENTS:
-* conn -- PPPoE connection info
-* packet -- a received PPPoE packet
-*%RETURNS:
-* 1 if packet is for this PPPoE daemon; 0 otherwise.
-*%DESCRIPTION:
-* If we are using the Host-Unique tag, verifies that packet contains
-* our unique identifier.
-***********************************************************************/
-int
-packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
+void
+pr_log(void *arg, char *fmt, ...)
{
- PPPoETag hostUniq = conn->hostUniq;
-
- /* If packet is not directed to our MAC address, forget it */
- if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
-
- /* If we're not using the Host-Unique tag, then accept the packet */
- if (!conn->hostUniq.length) return 1;
-
- parsePacket(packet, parseForHostUniq, &hostUniq);
- return !hostUniq.length;
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(debugFile, fmt, ap);
+ va_end(ap);
}
-/**********************************************************************
-*%FUNCTION: parsePADOTags
-*%ARGUMENTS:
-* type -- tag type
-* len -- tag length
-* data -- tag data
-* extra -- extra user data. Should point to a PacketCriteria structure
-* which gets filled in according to selected AC name and service
-* name.
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Picks interesting tags out of a PADO packet
-***********************************************************************/
-void
-parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
- void *extra)
+size_t
+strlcpy(char *dest, const char *src, size_t len)
{
- struct PacketCriteria *pc = (struct PacketCriteria *) extra;
- PPPoEConnection *conn = pc->conn;
- int i;
-
- switch(type) {
- case TAG_AC_NAME:
- pc->seenACName = 1;
- if (conn->printACNames) {
- printf("Access-Concentrator: %.*s\n", (int) len, data);
- }
- if (conn->acName && len == strlen(conn->acName) &&
- !strncmp((char *) data, conn->acName, len)) {
- pc->acNameOK = 1;
- }
- break;
- case TAG_SERVICE_NAME:
- pc->seenServiceName = 1;
- if (conn->printACNames && len > 0) {
- printf(" Service-Name: %.*s\n", (int) len, data);
- }
- if (conn->serviceName && len == strlen(conn->serviceName) &&
- !strncmp((char *) data, conn->serviceName, len)) {
- pc->serviceNameOK = 1;
- }
- break;
- case TAG_AC_COOKIE:
- if (conn->printACNames) {
- printf("Got a cookie:");
- /* Print first 20 bytes of cookie */
- for (i=0; i<len && i < 20; i++) {
- printf(" %02x", (unsigned) data[i]);
- }
- if (i < len) printf("...");
- printf("\n");
- }
- conn->cookie.type = htons(type);
- conn->cookie.length = htons(len);
- memcpy(conn->cookie.payload, data, len);
- break;
- case TAG_RELAY_SESSION_ID:
- if (conn->printACNames) {
- printf("Got a Relay-ID:");
- /* Print first 20 bytes of relay ID */
- for (i=0; i<len && i < 20; i++) {
- printf(" %02x", (unsigned) data[i]);
- }
- if (i < len) printf("...");
- printf("\n");
- }
- conn->relayId.type = htons(type);
- conn->relayId.length = htons(len);
- memcpy(conn->relayId.payload, data, len);
- break;
- case TAG_SERVICE_NAME_ERROR:
- if (conn->printACNames) {
- printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
- }
- break;
- case TAG_AC_SYSTEM_ERROR:
- if (conn->printACNames) {
- printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ size_t ret = strlen(src);
+
+ if (len != 0) {
+ if (ret < len)
+ strcpy(dest, src);
+ else {
+ strncpy(dest, src, len - 1);
+ dest[len-1] = 0;
}
- break;
- case TAG_GENERIC_ERROR:
- if (conn->printACNames) {
- printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
- }
- break;
}
+ return ret;
}
-/***********************************************************************
-*%FUNCTION: sendPADI
-*%ARGUMENTS:
-* conn -- PPPoEConnection structure
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Sends a PADI packet
-***********************************************************************/
-void
-sendPADI(PPPoEConnection *conn)
+static char *
+xstrdup(const char *s)
{
- PPPoEPacket packet;
- unsigned char *cursor = packet.payload;
- PPPoETag *svc = (PPPoETag *) (&packet.payload);
- UINT16_t namelen = 0;
- UINT16_t plen;
-
- if (conn->serviceName) {
- namelen = (UINT16_t) strlen(conn->serviceName);
- }
- plen = TAG_HDR_SIZE + namelen;
- CHECK_ROOM(cursor, packet.payload, plen);
-
- /* Set destination to Ethernet broadcast address */
- memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
- memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
-
- packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
- packet.vertype = PPPOE_VER_TYPE(1, 1);
- packet.code = CODE_PADI;
- packet.session = 0;
-
- svc->type = TAG_SERVICE_NAME;
- svc->length = htons(namelen);
- CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
-
- if (conn->serviceName) {
- memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
- }
- cursor += namelen + TAG_HDR_SIZE;
-
- /* If we're using Host-Uniq, copy it over */
- if (conn->hostUniq.length) {
- int len = ntohs(conn->hostUniq.length);
- CHECK_ROOM(cursor, packet.payload, len + TAG_HDR_SIZE);
- memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
- cursor += len + TAG_HDR_SIZE;
- plen += len + TAG_HDR_SIZE;
- }
-
- packet.length = htons(plen);
-
- sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
- if (conn->debugFile) {
- dumpPacket(conn->debugFile, &packet, "SENT");
- fprintf(conn->debugFile, "\n");
- fflush(conn->debugFile);
+ char *ret = strdup(s);
+ if (!ret) {
+ perror("strdup");
+ exit(1);
}
+ return ret;
}
-/**********************************************************************
-*%FUNCTION: waitForPADO
-*%ARGUMENTS:
-* conn -- PPPoEConnection structure
-* timeout -- how long to wait (in seconds)
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Waits for a PADO packet and copies useful information
-***********************************************************************/
-void
-waitForPADO(PPPoEConnection *conn, int timeout)
+int
+get_time(struct timeval *tv)
{
- fd_set readable;
- int r;
- struct timeval tv;
- PPPoEPacket packet;
- int len;
-
- struct PacketCriteria pc;
- pc.conn = conn;
- pc.acNameOK = (conn->acName) ? 0 : 1;
- pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
- pc.seenACName = 0;
- pc.seenServiceName = 0;
- conn->error = 0;
-
- do {
- if (BPF_BUFFER_IS_EMPTY) {
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- FD_ZERO(&readable);
- FD_SET(conn->discoverySocket, &readable);
-
- while(1) {
- r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
- if (r >= 0 || errno != EINTR) break;
- }
- if (r < 0) {
- perror("select (waitForPADO)");
- return;
- }
- if (r == 0) return; /* Timed out */
- }
-
- /* Get the packet */
- receivePacket(conn->discoverySocket, &packet, &len);
-
- /* Check length */
- if (ntohs(packet.length) + HDR_SIZE > len) {
- fprintf(stderr, "Bogus PPPoE length field (%u)\n",
- (unsigned int) ntohs(packet.length));
- continue;
- }
-
-#ifdef USE_BPF
- /* If it's not a Discovery packet, loop again */
- if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
-#endif
-
- if (conn->debugFile) {
- dumpPacket(conn->debugFile, &packet, "RCVD");
- fprintf(conn->debugFile, "\n");
- fflush(conn->debugFile);
- }
- /* If it's not for us, loop again */
- if (!packetIsForMe(conn, &packet)) continue;
-
- if (packet.code == CODE_PADO) {
- if (BROADCAST(packet.ethHdr.h_source)) {
- fprintf(stderr, "Ignoring PADO packet from broadcast MAC address\n");
- continue;
- }
- parsePacket(&packet, parsePADOTags, &pc);
- if (conn->error)
- return;
- if (!pc.seenACName) {
- fprintf(stderr, "Ignoring PADO packet with no AC-Name tag\n");
- continue;
- }
- if (!pc.seenServiceName) {
- fprintf(stderr, "Ignoring PADO packet with no Service-Name tag\n");
- continue;
- }
- conn->numPADOs++;
- if (pc.acNameOK && pc.serviceNameOK) {
- memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
- if (conn->printACNames) {
- printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (unsigned) conn->peerEth[0],
- (unsigned) conn->peerEth[1],
- (unsigned) conn->peerEth[2],
- (unsigned) conn->peerEth[3],
- (unsigned) conn->peerEth[4],
- (unsigned) conn->peerEth[5]);
- printf("--------------------------------------------------\n");
- continue;
- }
- conn->discoveryState = STATE_RECEIVED_PADO;
- break;
- }
- }
- } while (conn->discoveryState != STATE_RECEIVED_PADO);
+ return gettimeofday(tv, NULL);
}
-/**********************************************************************
-*%FUNCTION: discovery
-*%ARGUMENTS:
-* conn -- PPPoE connection info structure
-*%RETURNS:
-* Nothing
-*%DESCRIPTION:
-* Performs the PPPoE discovery phase
-***********************************************************************/
-void
-discovery(PPPoEConnection *conn)
+static void
+term_handler(int signum)
{
- int padiAttempts = 0;
- int timeout = conn->discoveryTimeout;
-
- conn->discoverySocket =
- openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
-
- do {
- padiAttempts++;
- if (padiAttempts > conn->discoveryAttempts) {
- fprintf(stderr, "Timeout waiting for PADO packets\n");
- close(conn->discoverySocket);
- conn->discoverySocket = -1;
- return;
- }
- sendPADI(conn);
- conn->discoveryState = STATE_SENT_PADI;
- waitForPADO(conn, timeout);
- } while (!conn->numPADOs);
+ got_sigterm = 1;
}
+static void usage(void);
+
int main(int argc, char *argv[])
{
int opt;
PPPoEConnection *conn;
+ signal(SIGINT, term_handler);
+ signal(SIGTERM, term_handler);
+
conn = malloc(sizeof(PPPoEConnection));
- if (!conn)
- fatalSys("malloc");
+ if (!conn) {
+ perror("malloc");
+ exit(1);
+ }
memset(conn, 0, sizeof(PPPoEConnection));
- conn->printACNames = 1;
+ pppoe_verbose = 1;
conn->discoveryTimeout = PADI_TIMEOUT;
conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
}
break;
case 'D':
- conn->debugFile = fopen(optarg, "w");
- if (!conn->debugFile) {
+ pppoe_verbose = 2;
+ debug = 1;
+ debugFile = fopen(optarg, "w");
+ if (!debugFile) {
fprintf(stderr, "Could not open %s: %s\n",
optarg, strerror(errno));
exit(1);
}
- fprintf(conn->debugFile, "pppoe-discovery from pppd %s\n", VERSION);
+ fprintf(debugFile, "pppoe-discovery from pppd %s\n", VERSION);
break;
case 'I':
conn->ifName = xstrdup(optarg);
break;
case 'Q':
- conn->printACNames = 0;
+ pppoe_verbose = 0;
break;
case 'V':
case 'h':
/* default interface name */
if (!conn->ifName)
- conn->ifName = strdup("eth0");
+ conn->ifName = xstrdup("eth0");
- conn->discoverySocket = -1;
conn->sessionSocket = -1;
- discovery(conn);
+ conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
+ if (conn->discoverySocket < 0) {
+ perror("Cannot create PPPoE discovery socket");
+ exit(1);
+ }
+
+ discovery1(conn);
if (!conn->numPADOs)
exit(1);
exit(0);
}
-void fatal(char * fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fputc('\n', stderr);
- exit(1);
-}
-
-void fatalSys(char const *str)
-{
- perror(str);
- exit(1);
-}
-
-char *xstrdup(const char *s)
-{
- register char *ret = strdup(s);
- if (!ret)
- fatalSys("strdup");
- return ret;
-}
-
-void usage(void)
+static void
+usage(void)
{
fprintf(stderr, "Usage: pppoe-discovery [options]\n");
fprintf(stderr, "Options:\n");