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

📄 pppoe.c

📁 This a free PPPoE redirector for Linux.基于LINUX环境下的PPPOE协议源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * pppoe, a PPP-over-Ethernet redirector * Copyright (C) 1999 Luke Stras <stras@ecf.toronto.edu> * *    This program is free software; you can redistribute it and/or modify *    it under the terms of the GNU General Public License as published by *    the Free Software Foundation; either version 2 of the License, or *    (at your option) any later version. * *    This program is distributed in the hope that it will be useful, *    but WITHOUT ANY WARRANTY; without even the implied warranty of *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *    GNU General Public License for more details. * *    You should have received a copy of the GNU General Public License *    along with this program; if not, write to the Free Software *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Revision History * 1999/09/22 stras Initial version * 1999/09/24 stras Changed header files for greater portability * 1999/10/02 stras Added more logging, bug fixes * 1999/10/02 mr    Port to bpf/OpenBSD; starvation fixed; efficiency fixes * 1999/10/18 stras added BUGGY_AC code, partial forwarding */#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <net/if.h>#ifdef __linux__#include <net/if_arp.h>#endif /* __linux__ */#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6#include <linux/if_ether>#else#include <netinet/if_ether.h>#endif#include <assert.h> #ifdef __linux__#include <getopt.h>#endif#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/wait.h>#ifdef USE_BPF#ifndef ETH_ALEN#define ETH_ALEN 6#endif /* ETH_ALEN *//* set this to desired size - you may not get this */int bpf_buf_size = 65536; #include <net/bpf.h>#include <fcntl.h>#include <nlist.h>#include <kvm.h>unsigned char local_ether[ETH_ALEN]; /* need to this filter packets */#endif /* USE_BPF */#include <errno.h>#ifdef __linux__extern int errno;#endif/* used as the size for a packet buffer *//* should be > 2 * size of max packet size */#define PACKETBUF 4096#define VERSION_MAJOR 0#define VERSION_MINOR 3/* references: RFC 2516 *//* ETHER_TYPE fields for PPPoE */#define ETH_P_PPPOE_DISC 0x8863 /* discovery stage */#define ETH_P_PPPOE_SESS 0x8864 /* session stage *//* ethernet broadcast address */#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"/* PPPoE packet; includes Ethernet headers and such */struct pppoe_packet {#ifdef __linux__    struct ethhdr ethhdr; /* ethernet header */#else     struct ether_header ethhdr; /* ethernet header */#endif    unsigned int ver:4; /* pppoe version */    unsigned int type:4; /* pppoe type */    unsigned int code:8; /* pppoe code CODE_* */    unsigned int session:16; /* session id */    unsigned short length; /* payload length */    /* payload follows */};/* maximum payload length */#define MAX_PAYLOAD (1484 - sizeof(struct pppoe_packet))/* PPPoE codes */#define CODE_SESS 0x00 /* PPPoE session */#define CODE_PADI 0x09 /* PPPoE Active Discovery Initiation */#define CODE_PADO 0x07 /* PPPoE Active Discovery Offer */#define CODE_PADR 0x19 /* PPPoE Active Discovery Request */#define CODE_PADS 0x65 /* PPPoE Active Discovery Session-confirmation */#define CODE_PADT 0xa7 /* PPPoE Active Discovery Terminate *//* also need */#define STATE_RUN (-1)/* PPPoE tag; the payload is a sequence of these */struct pppoe_tag {    unsigned short type; /* tag type TAG_* */    unsigned short length; /* tag length */    /* payload follows */};/* PPPoE tag types */#define TAG_END_OF_LIST        0x0000#define TAG_SERVICE_NAME       0x0101#define TAG_AC_NAME            0x0102#define TAG_HOST_UNIQ          0x0103#define TAG_AC_COOKIE          0x0104#define TAG_VENDOR_SPECIFIC    0x0105#define TAG_RELAY_SESSION_ID   0x0110#define TAG_SERVICE_NAME_ERROR 0x0201#define TAG_AC_SYSTEM_ERROR    0x0202#define TAG_GENERIC_ERROR      0x0203/* globals */int opt_verbose = 0;   /* logging */int opt_fwd = 0;       /* forward invalid packets */int opt_fwd_search = 0; /* search for next packet when forwarding */FILE *log_file = NULL;FILE *error_file = NULL;pid_t sess_listen = 0, pppd_listen = 0; /* child processes */int disc_sock = 0, sess_sock = 0; /* PPPoE sockets */char src_addr[ETH_ALEN]; /* source hardware address */char dst_addr[ETH_ALEN]; /* destination hardware address */char *if_name = NULL; /* interface to use */int session = 0; /* identifier for our session */int clean_child = 0; /* flag set when SIGCHLD received */voidprint_hex(unsigned char *buf, int len){    int i;        if (opt_verbose == 0)      return;    for (i = 0; i < len; i++)      fprintf(log_file, "%02x ", (unsigned char)*(buf+i));    fprintf(log_file, "\n");}void print_packet(struct pppoe_packet *p){    int i;    struct pppoe_tag *t = (struct pppoe_tag*)(p + 1);    struct pppoe_tag tag; /* needed to avoid alignment problems */    char *buf;    time_t tm;        if (opt_verbose == 0)	return;        time(&tm);        fprintf(log_file, "Ethernet header:\n");    fprintf(log_file, "h_dest: ");#ifdef __linux__    for (i = 0; i < 6; i++)	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.h_dest[i]);#else     for (i = 0; i < 6; i++)	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.ether_dhost[i]);#endif    fprintf(log_file, "\nh_source: ");#ifdef __linux__    for (i = 0; i < 6; i++)	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.h_source[i]);#else    for (i = 0; i < 6; i++)	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.ether_shost[i]);#endif#ifdef __linux__    fprintf(log_file, "\nh_proto: 0x%04x ", 	    (unsigned)ntohs(p->ethhdr.h_proto));#else    fprintf(log_file, "\nh_proto: 0x%04x ", 	    (unsigned)ntohs(p->ethhdr.ether_type));#endif#ifdef __linux__    switch((unsigned)ntohs(p->ethhdr.h_proto))#else    switch((unsigned)ntohs(p->ethhdr.ether_type))#endif    {    case ETH_P_PPPOE_DISC:	fprintf(log_file, "(PPPOE Discovery)\n");	break;    case ETH_P_PPPOE_SESS:	fprintf(log_file, "(PPPOE Session)\n");	break;    default:	fprintf(log_file, "(Unknown)\n");    }    fprintf(log_file, "PPPoE header: \nver: 0x%01x type: 0x%01x code: 0x%02x "	   "session: 0x%04x length: 0x%04x ", (unsigned)p->ver, 	   (unsigned)p->type, (unsigned)p->code, (unsigned)p->session,	   (unsigned)ntohs(p->length));    switch(p->code)    {    case CODE_PADI: 	fprintf(log_file, "(PADI)\n");	break;    case CODE_PADO:	fprintf(log_file, "(PADO)\n");	break;    case CODE_PADR:	fprintf(log_file, "(PADR)\n");	break;    case CODE_PADS:	fprintf(log_file, "(PADS)\n");	break;    case CODE_PADT:	fprintf(log_file, "(PADT)\n");	break;    default:	fprintf(log_file, "(Unknown)\n");    }#ifdef __linux__    if (ntohs(p->ethhdr.h_proto) != ETH_P_PPPOE_DISC)#else    if (ntohs(p->ethhdr.ether_type) != ETH_P_PPPOE_DISC)#endif    {	print_hex((unsigned char *)(p+1), ntohs(p->length));	return;    }    while (t < (struct pppoe_tag *)((char *)(p+1) + ntohs(p->length)))    {	/* no guarantee in PPPoE spec that t is aligned at all... */	memcpy(&tag,t,sizeof(tag));	fprintf(log_file, "PPPoE tag:\ntype: %04x length: %04x ", 		ntohs(tag.type), ntohs(tag.length));	switch(ntohs(tag.type))	{	case TAG_END_OF_LIST:	    fprintf(log_file, "(End of list)\n");	    break;	case TAG_SERVICE_NAME:	    fprintf(log_file, "(Service name)\n");	    break;	case TAG_AC_NAME:	    fprintf(log_file, "(AC Name)\n");	    break;	case TAG_HOST_UNIQ:	    fprintf(log_file, "(Host Uniq)\n");	    break;	case TAG_AC_COOKIE:	    fprintf(log_file, "(AC Cookie)\n");	    break;	case TAG_VENDOR_SPECIFIC:	    fprintf(log_file, "(Vendor Specific)\n");	    break;	case TAG_RELAY_SESSION_ID:	    fprintf(log_file, "(Relay Session ID)\n");	    break;	case TAG_SERVICE_NAME_ERROR:	    fprintf(log_file, "(Service Name Error)\n");	    break;	case TAG_AC_SYSTEM_ERROR:	    fprintf(log_file, "(AC System Error)\n");	    break;	case TAG_GENERIC_ERROR:	    fprintf(log_file, "(Generic Error)\n");	    break;	default:	    fprintf(log_file, "(Unknown)\n");	}	if (ntohs(tag.length) > 0)	    switch (ntohs(tag.type))	    {	    case TAG_SERVICE_NAME:	    case TAG_AC_NAME:	    case TAG_SERVICE_NAME_ERROR:	    case TAG_AC_SYSTEM_ERROR:	    case TAG_GENERIC_ERROR: /* ascii data */		buf = malloc(ntohs(tag.length) + 1);		memset(buf, 0, ntohs(tag.length)+1);		strncpy(buf, (char *)(t+1), ntohs(tag.length));		buf[ntohs(tag.length)] = '\0';		fprintf(log_file, "data (UTF-8): %s\n", buf);		free(buf);		break;	    case TAG_HOST_UNIQ:	    case TAG_AC_COOKIE:	    case TAG_RELAY_SESSION_ID:		fprintf(log_file, "data (bin): ");		for (i = 0; i < ntohs(tag.length); i++)		    fprintf(log_file, "%02x", (unsigned)*((char *)(t+1) + i));		fprintf(log_file, "\n");		break;			    default:		fprintf(log_file, "unrecognized data\n");	    }	t = (struct pppoe_tag *)((char *)(t+1)+ntohs(tag.length));    }}    int open_interface(char *if_name, unsigned short type, char *hw_addr){/* BSD stuff by mr */#ifdef USE_BPF  int fd;  struct ifreq ifr;  char bpf[16];  int i, opt;#ifdef SIMPLE_BPF  /* a simple BPF program which just grabs the packets of the given type */  /* by default use the clever BPF program - it works on my SPARC which     has the same endian as network order.  If someone can confirm that     the ordering also works on the opposite ending (e.g. ix86) I'll      remove the simple filter BPF program for good */  struct bpf_insn filt[] = {    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 1), /* check type */    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),    BPF_STMT(BPF_RET+BPF_K, 0)  };#else  /* by default use the clever BPF program which filters out packets      originating from us in the kernel */  /* note that we split the 6-byte ethernet address into a 4-byte word     and 2-byte half-word to minimize the number of comparisons */  struct bpf_insn filt[] = {    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 5), /* check type */    /* check src address != our hw address */    BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 6),    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 2), /* 4 bytes */    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 10),    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 1, 0), /* 2 bytes */    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),    BPF_STMT(BPF_RET+BPF_K, 0)  };#endif /* SIMPLE_BPF */  struct bpf_program prog;    /* hunt for an open bpf */  for(i = 0; i < 10; i++) {  /* this max is arbitrary */    sprintf(bpf,"/dev/bpf%d",i);    if ((fd = open(bpf, O_RDWR)) >= 0)      break;  }  if (fd < 0) {    perror("pppoe: open(bpf)");    return -1;  }   /* try to increase BPF size if possible */   (void) ioctl(fd, BIOCSBLEN, &bpf_buf_size); /* try to set buffer size */   if (ioctl(fd, BIOCGBLEN, &bpf_buf_size) < 0) { /* but find out for sure */     perror("pppoe: bpf(BIOCGBLEN)");     return -1;   }   /* attach to given interface */  strncpy(ifr.ifr_name,if_name,sizeof(ifr.ifr_name));  if (ioctl(fd, BIOCSETIF, &ifr) < 0) {    perror("pppoe: bpf(BIOCSETIF)");    return -1;  }  /* setup BPF */  opt = 1;  if (ioctl(fd, BIOCIMMEDIATE, &opt) < 0) {    perror("pppoe: bpf(BIOCIMMEDIATE)");    return -1;  }  if (ioctl(fd, BIOCGDLT, &opt) < 0) {    perror("pppoe: bpf(BIOCGDLT)");    return -1;  }  if (opt != DLT_EN10MB) {    fprintf(stderr, "pppoe: interface %s is not Ethernet!\n", if_name);    return -1;  }  /*************************************************************************   *   * WARNING - Really non-portable stuff follows.  This works on OpenBSD 2.5    * and may not work anywhere else.   *   * What's going on - there's no obvious user-level interface to determine   * the MAC address of a network interface in BSD that I know of.  (If   * anyone has an idea, please let me know.)  What happens here is that we   * dig around in the kernel symbol list to find its list of interfaces,   * walk through the list to find the interface we are interested in and   * then we can (inobviously) get the ethernet info from that.   * I don't like this solution, but it's the best I've got at this point.   *   *************************************************************************/  {    kvm_t *k;    struct nlist n[2];

⌨️ 快捷键说明

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