⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if.c

📁 linux下的拨号程序rp-pppoe.3.7
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************************* if.c** Implementation of user-space PPPoE redirector for Linux.** Functions for opening a raw socket and reading/writing raw Ethernet frames.** 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.** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: if.c,v 1.17 2005/08/08 03:51:35 dfs Exp $";#include "pppoe.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_NETPACKET_PACKET_H#include <netpacket/packet.h>#elif defined(HAVE_LINUX_IF_PACKET_H)#include <linux/if_packet.h>#endif#ifdef HAVE_NET_ETHERNET_H#include <net/ethernet.h>#endif#ifdef HAVE_ASM_TYPES_H#include <asm/types.h>#endif#ifdef HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#include <errno.h>#include <stdlib.h>#include <string.h>#ifdef HAVE_NET_IF_ARP_H#include <net/if_arp.h>#endif#ifdef USE_DLPI#include <limits.h>#include <fcntl.h>#include <stdlib.h>#include <sys/types.h>#include <sys/time.h>#include <sys/stream.h>#include <sys/stropts.h>#include <sys/dlpi.h>#include <sys/bufmod.h>#include <stdio.h>#include <signal.h>#include <stropts.h>/* function declarations */void dlpromisconreq( int fd, u_long  level);void dlinforeq(int fd);void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);void dlinfoack(int fd, char *bufp);void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);void dlattachreq(int fd, u_long ppa);void dlokack(int fd, char *bufp);void dlbindack(int fd, char *bufp);int strioctl(int fd, int cmd, int timout, int len, char *dp);void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);void sigalrm(int sig);void expecting(int prim, union DL_primitives *dlp);char *dlprim(u_long prim);/* #define DL_DEBUG */static	int     dl_abssaplen;static	int     dl_saplen;static	int	dl_addrlen;#endif#ifdef USE_BPF#include <net/bpf.h>#include <fcntl.h>unsigned char *bpfBuffer;	/* Packet filter buffer */int bpfLength = 0;		/* Packet filter buffer length */int bpfSize = 0;		/* Number of unread bytes in buffer */int bpfOffset = 0;		/* Current offset in bpfBuffer */#endif/* 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_tetherType(PPPoEPacket *packet){    UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);    if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {	syslog(LOG_ERR, "Invalid ether type 0x%x", type);    }    return type;}#ifdef USE_BPF/***********************************************************************%FUNCTION: getHWaddr*%ARGUMENTS:* ifname -- name of interface* hwaddr -- buffer for ehthernet address*%RETURNS:* Nothing*%DESCRIPTION:* Locates the Ethernet hardware address for an interface.***********************************************************************/voidgetHWaddr(int sock, char const *ifname, unsigned char *hwaddr){    char inbuf[8192];    const struct sockaddr_dl *sdl;    struct ifconf ifc;    struct ifreq ifreq, *ifr;    int i;    int found = 0;    ifc.ifc_len = sizeof(inbuf);    ifc.ifc_buf = inbuf;    if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {	fatalSys("SIOCGIFCONF");    }    ifr = ifc.ifc_req;    ifreq.ifr_name[0] = '\0';    for (i = 0; i < ifc.ifc_len; ) {	ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);	i += sizeof(ifr->ifr_name) +		    (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)		    ? ifr->ifr_addr.sa_len		    : sizeof(struct sockaddr));	if (ifr->ifr_addr.sa_family == AF_LINK) {	    sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;	    if ((sdl->sdl_type == IFT_ETHER) &&		(sdl->sdl_alen == ETH_ALEN) &&		!strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {		if (found) {		    char buffer[256];		    sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);		    rp_fatal(buffer);		} else {		    found = 1;		    memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);		}	    }	}    }    if (!found) {	char buffer[256];	sprintf(buffer, "interface %.16s has no ethernet address", ifname);	rp_fatal(buffer);    }}/***********************************************************************%FUNCTION: initFilter*%ARGUMENTS:* fd -- file descriptor of BSD device* type -- Ethernet frame type (0 for watch mode)* hwaddr -- buffer with ehthernet address*%RETURNS:* Nothing*%DESCRIPTION:* Initializes the packet filter rules.***********************************************************************/voidinitFilter(int fd, UINT16_t type, unsigned char *hwaddr){    /* Packet Filter Instructions:     * Note that the ethernet type names come from "pppoe.h" and are     * used here to maintain consistency with the rest of this file. */    static struct bpf_insn bpfRun[] = {         /* run PPPoE */	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),     /* ethernet type */	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */#define PPPOE_BCAST_CMPW 4                     /* offset of word compare */	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */#define PPPOE_BCAST_CMPH 6                     /* offset of 1/2 word compare */	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */#define PPPOE_FILTER_CMPW 8                     /* offset of word compare */	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */#define PPPOE_FILTER_CMPH 10                    /* offset of 1/rd compare */	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),	BPF_STMT(BPF_RET+BPF_K, (u_int) -1),    /* keep packet */	BPF_STMT(BPF_RET+BPF_K, 0),             /* drop packet */    };    /* Fix the potentially varying parts */    bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;    bpfRun[1].jt   = 5;    bpfRun[1].jf   = 0;    bpfRun[1].k    = Eth_PPPOE_Session;    bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;    bpfRun[2].jt   = 0;    bpfRun[2].jf   = 9;    bpfRun[2].k    = Eth_PPPOE_Discovery;    {      struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];      struct bpf_program bpfProgram;      memcpy(bpfInsn, bpfRun, sizeof(bpfRun));      bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |				     (0xff << 8) | 0xff);      bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);      bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |				      (hwaddr[2] << 8) | hwaddr[3]);      bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);      bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));      bpfProgram.bf_insns = &bpfInsn[0];      /* Apply the filter */      if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {	fatalSys("ioctl(BIOCSETF)");      }    }}/***********************************************************************%FUNCTION: openInterface*%ARGUMENTS:* ifname -- name of interface* type -- Ethernet frame type (0 for any frame type)* hwaddr -- if non-NULL, set to the hardware address*%RETURNS:* A file descriptor for talking with the Ethernet card.  Exits on error.* Note that the Linux version of this routine returns a socket instead.*%DESCRIPTION:* Opens a BPF on an interface for all PPPoE traffic (discovery and* session).  If 'type' is 0, uses promiscuous mode to watch any PPPoE* traffic on this network.***********************************************************************/intopenInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr){    static int fd = -1;    char bpfName[32];    u_int optval;    struct bpf_version bpf_ver;    struct ifreq ifr;    int sock;    int i;    /* BSD only opens one socket for both Discovery and Session packets */    if (fd >= 0) {	return fd;    }    /* Find a free BPF device */    for (i = 0; i < 256; i++) {	sprintf(bpfName, "/dev/bpf%d", i);	if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||	    (errno != EBUSY)) {	    break;	}    }    if (fd < 0) {	switch (errno) {	case EACCES:		/* permission denied */	    {		char buffer[256];		sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);		rp_fatal(buffer);	    }	    break;	case EBUSY:	case ENOENT:		/* no such file */	    if (i == 0) {		rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");	    } else {		rp_fatal("All /dev/bpf* devices are in use");	    }	    break;	}	fatalSys(bpfName);    }    if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {	fatalSys("socket");    }    /* Check that the interface is up */    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));    if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {	fatalSys("ioctl(SIOCGIFFLAGS)");    }    if ((ifr.ifr_flags & IFF_UP) == 0) {	char buffer[256];	sprintf(buffer, "Interface %.16s is not up\n", ifname);	rp_fatal(buffer);    }    /* Fill in hardware address and initialize the packet filter rules */    if (hwaddr == NULL) {	rp_fatal("openInterface: no hwaddr arg.");    }    getHWaddr(sock, ifname, hwaddr);    initFilter(fd, type, hwaddr);    /* Sanity check on MTU -- apparently does not work on OpenBSD */#if !defined(__OpenBSD__)    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));    if (ioctl(sock, 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);    }#endif    /* done with the socket */    if (close(sock) < 0) {	fatalSys("close");    }    /* Check the BPF version number */    if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {	fatalSys("ioctl(BIOCVERSION)");    }    if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||	(bpf_ver.bv_minor < BPF_MINOR_VERSION)) {	char buffer[256];	sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",			BPF_MAJOR_VERSION, BPF_MINOR_VERSION,			bpf_ver.bv_major, bpf_ver.bv_minor);	rp_fatal(buffer);    }    /* allocate a receive packet buffer */    if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {	fatalSys("ioctl(BIOCGBLEN)");    }    if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {	rp_fatal("malloc");    }    /* reads should return as soon as there is a packet available */    optval = 1;    if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {	fatalSys("ioctl(BIOCIMMEDIATE)");    }    /* Bind the interface to the filter */    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));    if (ioctl(fd, BIOCSETIF, &ifr) < 0) {	char buffer[256];	sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",		ifname);	rp_fatal(buffer);    }    syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",	   ifname,	   hwaddr[0], hwaddr[1], hwaddr[2],	   hwaddr[3], hwaddr[4], hwaddr[5],	   bpfName, bpfLength);    return fd;}#endif /* USE_BPF */#ifdef USE_LINUX_PACKET/***********************************************************************%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***********************************************************************/intopenInterface(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;}#endif /* USE_LINUX *//************************************************************************%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***********************************************************************/intsendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size){#if defined(USE_BPF)    if (write(sock, pkt, size) < 0) {	sysErr("write (sendPacket)");	return -1;    }#elif defined(HAVE_STRUCT_SOCKADDR_LL)    if (send(sock, pkt, size, 0) < 0 && (errno != ENOBUFS)) {	sysErr("send (sendPacket)");	return -1;    }#else#ifdef USE_DLPI#define ABS(x)          ((x) < 0 ? -(x) : (x))	u_char  addr[MAXDLADDR];	u_char  phys[MAXDLADDR];	u_char  sap[MAXDLADDR];	u_char    xmitbuf[MAXDLBUF];	int	data_size;	short	tmp_sap;	tmp_sap = htons(pkt->ethHdr.h_proto);	data_size = size - sizeof(struct ethhdr);	memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);	memcpy((char *)sap,  (char *)&tmp_sap, sizeof(ushort_t));	memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -