Example #1
0
/**********************************************************************
*%FUNCTION: relayHandlePADI
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADI packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADI packet.
***********************************************************************/
void
relayHandlePADI(PPPoEInterface const *iface,
		PPPoEPacket *packet,
		int size)
{
    PPPoETag tag;
    unsigned char *loc;
    int i, r;

    int ifIndex;

    /* Can a client legally be behind this interface? */
    if (!iface->clientOK) {
	syslog(LOG_ERR,
	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Source address must be unicast */
    if (NOT_UNICAST(packet->ethHdr.h_source)) {
	syslog(LOG_ERR,
	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Destination address must be broadcast */
    if (NOT_BROADCAST(packet->ethHdr.h_dest)) {
	syslog(LOG_ERR,
	       "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Get array index of interface */
    ifIndex = iface - Interfaces;

    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
    if (!loc) {
	tag.type = htons(TAG_RELAY_SESSION_ID);
	tag.length = htons(MY_RELAY_TAG_LEN);
	memcpy(tag.payload, &ifIndex, sizeof(ifIndex));
	memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);
	/* Add a relay tag if there's room */
	r = addTag(packet, &tag);
	if (r < 0) return;
	size += r;
    } else {
	/* We do not re-use relay-id tags.  Drop the frame.  The RFC says the
	   relay agent SHOULD return a Generic-Error tag, but this does not
	   make sense for PADI packets. */
	return;
    }

    /* Broadcast the PADI on all AC-capable interfaces except the interface
       on which it came */
    for (i=0; i < NumInterfaces; i++) {
	if (iface == &Interfaces[i]) continue;
	if (!Interfaces[i].acOK) continue;
	memcpy(packet->ethHdr.h_source, Interfaces[i].mac, ETH_ALEN);
	sendPacket(NULL, Interfaces[i].discoverySock, packet, size);
    }

}
Example #2
0
/**********************************************************************
*%FUNCTION: relayHandlePADR
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADR packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADR packet.
***********************************************************************/
void
relayHandlePADR(PPPoEInterface const *iface,
		PPPoEPacket *packet,
		int size)
{
    PPPoETag tag;
    unsigned char *loc;
    int ifIndex;
    int cliIndex;

    /* Can a client legally be behind this interface? */
    if (!iface->clientOK) {
	syslog(LOG_ERR,
	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    cliIndex = iface - Interfaces;

    /* Source address must be unicast */
    if (NOT_UNICAST(packet->ethHdr.h_source)) {
	syslog(LOG_ERR,
	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Destination address must be interface's MAC address */
    if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
	return;
    }

    /* Find relay tag */
    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
    if (!loc) {
	syslog(LOG_ERR,
	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* If it's the wrong length, ignore it */
    if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
	syslog(LOG_ERR,
	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Extract interface index */
    memcpy(&ifIndex, tag.payload, sizeof(ifIndex));

    if (ifIndex < 0 || ifIndex >= NumInterfaces ||
	!Interfaces[ifIndex].acOK ||
	iface == &Interfaces[ifIndex]) {
	syslog(LOG_ERR,
	       "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Replace Relay-ID tag with opposite-direction tag */
    memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex));
    memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN);

    /* Set destination address to MAC address in relay ID */
    memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);

    /* Set source address to MAC address of interface */
    memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);

    /* Send the PADR to the proper access concentrator */
    sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
}
Example #3
0
/**********************************************************************
*%FUNCTION: relayHandlePADS
*%ARGUMENTS:
* iface -- interface on which packet was received
* packet -- the PADS packet
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Receives and processes a PADS packet.
***********************************************************************/
void
relayHandlePADS(PPPoEInterface const *iface,
		PPPoEPacket *packet,
		int size)
{
    PPPoETag tag;
    unsigned char *loc;
    int ifIndex;
    int acIndex;
    PPPoESession *ses = NULL;
    SessionHash *sh;

    /* Can a server legally be behind this interface? */
    if (!iface->acOK) {
	syslog(LOG_ERR,
	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    acIndex = iface - Interfaces;

    /* Source address must be unicast */
    if (NOT_UNICAST(packet->ethHdr.h_source)) {
	syslog(LOG_ERR,
	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Destination address must be interface's MAC address */
    if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) {
	return;
    }

    /* Find relay tag */
    loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag);
    if (!loc) {
	syslog(LOG_ERR,
	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* If it's the wrong length, ignore it */
    if (ntohs(tag.length) != MY_RELAY_TAG_LEN) {
	syslog(LOG_ERR,
	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* Extract interface index */
    memcpy(&ifIndex, tag.payload, sizeof(ifIndex));

    if (ifIndex < 0 || ifIndex >= NumInterfaces ||
	!Interfaces[ifIndex].clientOK ||
	iface == &Interfaces[ifIndex]) {
	syslog(LOG_ERR,
	       "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag",
	       packet->ethHdr.h_source[0],
	       packet->ethHdr.h_source[1],
	       packet->ethHdr.h_source[2],
	       packet->ethHdr.h_source[3],
	       packet->ethHdr.h_source[4],
	       packet->ethHdr.h_source[5],
	       iface->name);
	return;
    }

    /* If session ID is zero, it's the AC respoding with an error.
       Just relay it; do not create a session */
    if (packet->session != htons(0)) {
	/* Check for existing session */
	sh = findSession(packet->ethHdr.h_source, packet->session);
	if (sh) ses = sh->ses;

	/* If already an existing session, assume it's a duplicate PADS.  Send
	   the frame, but do not create a new session.  Is this the right
	   thing to do?  Arguably, should send an error to the client and
	   a PADT to the server, because this could happen due to a
	   server crash and reboot. */

	if (!ses) {
	    /* Create a new session */
	    ses = createSession(iface, &Interfaces[ifIndex],
				packet->ethHdr.h_source,
				loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session);
	    if (!ses) {
		/* Can't allocate session -- send error PADS to client and
		   PADT to server */
		PPPoETag hostUniq, *hu;
		if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) {
		    hu = &hostUniq;
		} else {
		    hu = NULL;
		}
		relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex],
			       loc + TAG_HDR_SIZE + sizeof(ifIndex),
			       hu, "RP-PPPoE: Relay: Unable to allocate session");
		relaySendError(CODE_PADT, packet->session, iface,
			       packet->ethHdr.h_source, NULL,
			       "RP-PPPoE: Relay: Unable to allocate session");
		return;
	    }
	}
	/* Replace session number */
	packet->session = ses->sesNum;
    }

    /* Remove relay-ID tag */
    removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE);
    size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE);

    /* Set destination address to MAC address in relay ID */
    memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN);

    /* Set source address to MAC address of interface */
    memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN);

    /* Send the PADS to the proper client */
    sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size);
}
Example #4
0
/**********************************************************************
*%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)
{
    fd_set readable;
    int r;
    struct timeval tv;
    struct timeval expire_at;

    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->seenMaxPayload = 0;
    conn->error = 0;

    if (gettimeofday(&expire_at, NULL) < 0) {
	error("gettimeofday (waitForPADO): %m");
	return;
    }
    expire_at.tv_sec += timeout;

    do {
	if (BPF_BUFFER_IS_EMPTY) {
	    if (!time_left(&tv, &expire_at))
		return;		/* Timed out */

	    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) {
		error("select (waitForPADO): %m");
		return;
	    }
	    if (r == 0)
		return;		/* Timed out */
	}

	/* Get the packet */
	receivePacket(conn->discoverySocket, &packet, &len);

	/* Check length */
	if (ntohs(packet.length) + HDR_SIZE > len) {
	    error("Bogus PPPoE length field (%u)",
		   (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 it's not for us, loop again */
	if (!packetIsForMe(conn, &packet)) continue;

	if (packet.code == CODE_PADO) {
	    if (NOT_UNICAST(packet.ethHdr.h_source)) {
		error("Ignoring PADO packet from non-unicast MAC address");
		continue;
	    }
	    if (conn->req_peer
		&& memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) {
		warn("Ignoring PADO packet from wrong MAC address");
		continue;
	    }
	    if (parsePacket(&packet, parsePADOTags, &pc) < 0)
		return;
	    if (conn->error)
		return;
	    if (!pc.seenACName) {
		error("Ignoring PADO packet with no AC-Name tag");
		continue;
	    }
	    if (!pc.seenServiceName) {
		error("Ignoring PADO packet with no Service-Name tag");
		continue;
	    }
	    conn->numPADOs++;
	    if (pc.acNameOK && pc.serviceNameOK) {
		memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
		conn->discoveryState = STATE_RECEIVED_PADO;
		break;
	    }
	}
    } while (conn->discoveryState != STATE_RECEIVED_PADO);
}
Example #5
0
/**********************************************************************
*%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)
{
    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;
	
    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) {
		fatalSys("select (waitForPADO)");
	    }
	    if (r == 0) return;        /* Timed out */
	}
	
	/* Get the packet */
	receivePacket(conn->discoverySocket, &packet, &len);

	/* Check length */
	if (ntohs(packet.length) + HDR_SIZE > len) {
	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
		   (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 (NOT_UNICAST(packet.ethHdr.h_source)) {
		printErr("Ignoring PADO packet from non-unicast MAC address");
		continue;
	    }
	    parsePacket(&packet, parsePADOTags, &pc);
	    if (!pc.seenACName) {
		printErr("Ignoring PADO packet with no AC-Name tag");
		continue;
	    }
	    if (!pc.seenServiceName) {
		printErr("Ignoring PADO packet with no Service-Name tag");
		continue;
	    }
	    conn->numPADOs++;
	    if (conn->printACNames) {
		printf("--------------------------------------------------\n");
	    }
	    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]);
		    continue;
		}
		conn->discoveryState = STATE_RECEIVED_PADO;
		break;
	    }
	}
    } while (conn->discoveryState != STATE_RECEIVED_PADO);
}
Example #6
0
/**********************************************************************
*%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)
{
    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) {
	    rp_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) {
	    char buffer[256];
	    sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
	    rp_fatal(buffer);
	}
#endif
	if (NOT_UNICAST(hwaddr)) {
	    char buffer[256];
	    sprintf(buffer,
		    "Interface %.16s has broadcast/multicast MAC address??",
		    ifname);
	    rp_fatal(buffer);
	}
    }

    /* 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) {
	char buffer[256];
	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
	printErr(buffer);
    }

#ifdef HAVE_STRUCT_SOCKADDR_LL
    /* Get interface index */
    sa.sll_family = AF_PACKET;
    sa.sll_protocol = htons(type);

    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    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;
}
Example #7
0
/**********************************************************************
*%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)
{
    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.");
	}
	error("Can't open socket for pppoe: %m");
	return -1;
    }

    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
	error("Can't set socket options for pppoe: %m");
	close(fd);
	return -1;
    }

    /* Fill in hardware address */
    if (hwaddr) {
	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
	    error("Can't get hardware address for %s: %m", ifname);
	    close(fd);
	    return -1;
	}
	memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
#ifdef ARPHRD_ETHER
	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
	    warn("Interface %.16s is not Ethernet", ifname);
	}
#endif
	if (NOT_UNICAST(hwaddr)) {
	    fatal("Can't use interface %.16s: it 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) {
	error("Can't get MTU for %s: %m", ifname);
    } else if (ifr.ifr_mtu < ETH_DATA_LEN) {
	error("Interface %.16s has MTU of %d -- should be at least %d.",
	      ifname, ifr.ifr_mtu, ETH_DATA_LEN);
	error("This may cause serious connection problems.");
    }

#ifdef HAVE_STRUCT_SOCKADDR_LL
    /* Get interface index */
    sa.sll_family = AF_PACKET;
    sa.sll_protocol = htons(type);

    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
	error("Could not get interface index for %s: %m", ifname);
	close(fd);
	return -1;
    }
    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) {
	error("Failed to bind to interface %s: %m", ifname);
	close(fd);
	return -1;
    }

    return fd;
}
Example #8
0
static int
wait_for_pado (int n, PPPoEConnection* conns)
{
    int r, i, all;
    size_t len;
    fd_set readable;
    PPPoEPacket packet;
    PacketCriteria pc;

    struct timeval tv;
    tv.tv_sec = PADO_TIMEOUT;
    tv.tv_usec = 0;

    while (1)
    {
	FD_ZERO (&readable);
	for (i = 0; i < n; i++)
	    if (conns[i].fd != -1)
		FD_SET (conns[i].fd, &readable);

	do {
	    r = select (FD_SETSIZE, &readable, NULL, NULL, &tv);
	} while (r == -1 && errno == EINTR);

	if (r < 0) {
	    ADD2LOG ("select: %m\n");
	    return 0;
	}

	if (r == 0) {
	    ADD2LOG ("Timeout waiting for PADO packets\n");
	    return 0;
	}

	for (i = 0; i < n; i++)
	{
	    PPPoEConnection* conn = &conns[i];

	    if (conn->fd == -1 || !FD_ISSET (conn->fd, &readable))
		continue;

	    pc.conn = conn;
	    pc.acname_ok = 0;
	    pc.servicename_ok = 0;
	    pc.error = 0;

	    /* Get the packet */
	    if (!receive_packet (conn->fd, &packet, &len))
		continue;

	    /* Check length */
	    if (ntohs (packet.length) + HDR_SIZE > len) {
		ADD2LOG ("%s: Bogus PPPoE length field (%u)\n", conn->ifname,
			(unsigned int) ntohs (packet.length));
		continue;
	    }

	    /* If it's not for us, loop again */
	    if (!packet_for_me (conn, &packet))
		continue;

	    if (packet.code != CODE_PADO)
		continue;

	    if (NOT_UNICAST (packet.ethHdr.h_source)) {
		ADD2LOG ("%s: Ignoring PADO packet from non-unicast MAC "
			 "address\n", conn->ifname);
		continue;
	    }

	    parse_packet (conn, &packet, parse_pado_tags, &pc);

	    if (!pc.acname_ok) {
		ADD2LOG ("%s: Wrong or missing AC-Name tag\n", conn->ifname);
		continue;
	    }

	    if (!pc.servicename_ok) {
		ADD2LOG ("%s: Wrong or missing Service-Name tag\n",
			 conn->ifname);
		continue;
	    }

	    if (pc.error) {
		ADD2LOG ("%s: Ignoring PADO packet with some Error tag\n",
			 conn->ifname);
		continue;
	    }

	    memcpy (conn->peer_mac, packet.ethHdr.h_source, ETH_ALEN);
	    ADD2LOG ("%s: Received correct PADO packet\n", conn->ifname);
	    conn->received_pado = 1;
	}

	all = 1;
	for (i = 0; i < n; i++)
	    if (conns[i].fd != -1 && !conns[i].received_pado)
		all = 0;
	if (all)
	    return 1;
    }
}
Example #9
0
static int
open_interfaces (int n, PPPoEConnection* conns)
{
    int ret = 0, i;

    for (i = 0; i < n; i++)
    {
	PPPoEConnection* conn = &conns[i];

	conn->fd = socket (PF_PACKET, SOCK_RAW, htons (ETH_PPPOE_DISCOVERY));
	if (conn->fd < 0) {
	    ADD2LOG ("%s: socket failed: %m\n", conn->ifname);
	    continue;
	}

	int one = 1;
	if (setsockopt (conn->fd, SOL_SOCKET, SO_BROADCAST, &one,
			sizeof (one)) < 0) {
	    ADD2LOG ("%s: setsockopt failed: %m\n", conn->ifname);
	    goto error;
	}

	/* Fill in hardware address */
	struct ifreq ifr;
	struct sockaddr_ll sa;
	memset (&sa, 0, sizeof (sa));
	strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name));
	if (ioctl (conn->fd, SIOCGIFHWADDR, &ifr) < 0) {
	    ADD2LOG ("%s: ioctl (SIOCGIFHWADDR) failed: %m\n", conn->ifname);
	    goto error;
	}

	memcpy (conn->my_mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
	    ADD2LOG ("%s: Interface is not ethernet\n", conn->ifname);
	    goto error;
	}

	if (NOT_UNICAST (conn->my_mac)) {
	    ADD2LOG ("%s: Interface has broadcast/multicast MAC address?\n",
		    conn->ifname);
	    goto error;
	}

	/* Sanity check on MTU */
	strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name));
	if (ioctl (conn->fd, SIOCGIFMTU, &ifr) < 0) {
	    ADD2LOG ("%s: ioctl (SIOCGIFMTU) failed: %m\n", conn->ifname);
	    goto error;
	}
	if (ifr.ifr_mtu < ETH_DATA_LEN) {
	    ADD2LOG ("%s: Interface has too low MTU\n", conn->ifname);
	    goto error;
	}

	/* Skip interfaces that have the SLAVE flag set */
	strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name));
	if (ioctl (conn->fd, SIOCGIFFLAGS, &ifr) < 0) {
		ADD2LOG ("%s: ioctl (SIOCGIFFLAGS) failed: %m\n", conn->ifname);
		goto error;
	}
	if (ifr.ifr_ifru.ifru_flags & IFF_SLAVE) {
		ADD2LOG ("%s: Interface has SLAVE flag set\n", conn->ifname);
		goto error;
	}

	/* Get interface index */
	sa.sll_family = AF_PACKET;
	sa.sll_protocol = htons (ETH_PPPOE_DISCOVERY);
	strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name));
	if (ioctl (conn->fd, SIOCGIFINDEX, &ifr) < 0) {
	    ADD2LOG ("%s: ioctl (SIOCFIGINDEX) failed: Could not get interface "
		     "index\n", conn->ifname);
	    goto error;
	}
	sa.sll_ifindex = ifr.ifr_ifindex;

	/* We're only interested in packets on specified interface */
	if (bind (conn->fd, (struct sockaddr*) &sa, sizeof (sa)) < 0) {
	    ADD2LOG ("%s: bind failed: %m\n", conn->ifname);
	    goto error;
	}

	ret = 1;
	continue;

error:

	close (conn->fd);
	conn->fd = -1;

    }

    return ret;
}
Example #10
0
static void waitForPADO(PPPoEConnection * conn, int timeout)
{
	fd_set readable;
	int r = -1;
	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;

	do
	{
		tv.tv_sec = timeout;
		tv.tv_usec = 0;

		FD_ZERO(&readable);
		FD_SET(conn->discoverySocket, &readable);

		while (!got_sigterm) /* Modified by Kwest Wan 20080919 to terminate pppd immediately if PPPoE server don't reponse */
		{
			d_dbg("[%d]: waitPADO select >>>>\n", getpid());
			r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
			d_dbg("[%d]: waitPADO select (%d) <<<<\n", getpid(), r);
			if (r >= 0 || errno != EINTR) break;
		}
		if (r < 0)
		{
			d_error("[%d]: select (waitForPADS)\n", getpid());
			return;
		}
		if (r == 0) return;

		/* Get the packet */
		d_dbg("[%d]: receivePacket >>>\n", getpid());
		receivePacket(conn->discoverySocket, &packet, &len);
		d_dbg("[%d]: receivePacket <<<\n", getpid());

		/* Check length */
		if (ntohs(packet.length) + HDR_SIZE > len)
		{
			d_error("[%d]: Bogus PPPoE length field (%u)\n", getpid(), (unsigned int)ntohs(packet.length));
			continue;
		}

		/* If it's not for us, loop again */
		if (!packetIsForMe(conn, &packet))
		{
			d_dbg("[%d]: packet is not for me!\n", getpid());
			continue;
		}

		/* Is it PADS ? */
		if (packet.code == CODE_PADO)
		{
			if (NOT_UNICAST(packet.ethHdr.h_source))
			{
				d_info("[%d]: Ignoring PADO packet from non-unicast MAC address\n", getpid());
#ifndef LOGNUM
#ifdef ELBOX_PROGS_GPL_SYSLOGD_AP	
				syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet from non-unicast MAC address. (%s)", linkname);
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet from non-unicast MAC address. (%s)", linkname);
#endif	
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:029[%s]", linkname);
#endif
				continue;
			}
			kpppoe_parsePacket(&packet, parsePADOTags, &pc);
			if (!pc.seenACName)
			{
				d_info("[%d]: Ignoring PADO packet with no AC-Name tag\n", getpid());
#ifndef LOGNUM
#ifdef ELBOX_PROGS_GPL_SYSLOGD_AP	
				syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet with no AC-Name tag. (%s)", linkname);
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet with no AC-Name tag. (%s)", linkname);
#endif	
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:030[%s]", linkname);
#endif
				continue;
			}
			if (!pc.seenServiceName)
			{
				d_info("[%d]: Ignoring PADO packet with no Service-Name tag\n", getpid());
#ifndef LOGNUM
#ifdef ELBOX_PROGS_GPL_SYSLOGD_AP	
				syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet with no Service-Name tag. (%s)", linkname);
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet with no Service-Name tag. (%s)", linkname);
#endif	
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:031[%s]", linkname);
#endif
				continue;
			}
			conn->numPADOs++;
			if (conn->printACNames) printf("------------------------------------------------------\n");
			update_statusfile("PPPoE:PADO");
			d_dbg("[%d]: acNameOK:%d, serviceNameOK:%d\n", getpid(), pc.acNameOK, pc.serviceNameOK);
			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]);
					continue;
				}
				conn->discoveryState = STATE_RECEIVED_PADO;
#ifndef LOGNUM
#ifdef ELBOX_PROGS_GPL_SYSLOGD_AP	
				syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Received PADO for %s, from: %02x:%02x:%02x:%02x:%02x:%02x",
						linkname,
						(unsigned)conn->peerEth[0],
						(unsigned)conn->peerEth[1],
						(unsigned)conn->peerEth[2],
						(unsigned)conn->peerEth[3],
						(unsigned)conn->peerEth[4],
						(unsigned)conn->peerEth[5]);
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Received PADO for %s, from: %02x:%02x:%02x:%02x:%02x:%02x",
						linkname,
						(unsigned)conn->peerEth[0],
						(unsigned)conn->peerEth[1],
						(unsigned)conn->peerEth[2],
						(unsigned)conn->peerEth[3],
						(unsigned)conn->peerEth[4],
						(unsigned)conn->peerEth[5]);
#endif	
#else
				syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:026[%s][%02x:%02x:%02x:%02x:%02x:%02x]",
						linkname,
						(unsigned)conn->peerEth[0],
						(unsigned)conn->peerEth[1],
						(unsigned)conn->peerEth[2],
						(unsigned)conn->peerEth[3],
						(unsigned)conn->peerEth[4],
						(unsigned)conn->peerEth[5]);
#endif
				break;
			}
		}
		else
		{
			d_dbg("[%d]: this is not PADO!\n", getpid());
		}
	} while (conn->discoveryState != STATE_RECEIVED_PADO);
}