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

📄 pppoe.c

📁 This a free PPPoE redirector for Linux.基于LINUX环境下的PPPOE协议源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	h = (struct bpf_hdr *)&(buf[off]);	memcpy(packet,&(buf[off + h->bh_hdrlen]),h->bh_caplen);	off += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);	if (h->bh_caplen != h->bh_datalen) {	    fprintf(stderr, "pppoe: truncated packet: %d -> %d\n",		    h->bh_datalen, h->bh_caplen);	    return 1; /* try again */	}    } else {	struct bpf_stat s;	if (ioctl(fd,BIOCGSTATS,&s)) {	    perror("pppoe: BIOCGSTATS");	} else {	    if (s.bs_drop > lastdrop) {		fprintf(stderr, "BPF: dropped %d packets\n", s.bs_drop - lastdrop);		lastdrop = s.bs_drop;	    }	}	if ((n = read(fd,buf,bpf_buf_size)) < 0) {	    perror("pppoe: read (read_bpf_packet)");	    return -1;	}	if (n == 0)	    return 0; /* timeout on bpf - try again */	h = (struct bpf_hdr *)(buf);	memcpy(packet,&(buf[h->bh_hdrlen]),h->bh_caplen);	off = BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);    }    /* need to filter packets here - interface could be in promiscuous       mode - we shouldn't see packets that we sent out thanks to BPF, but       a quick double-check here is unlikely to seriously impact performance       Once you know BPF is working, you can pop this out */    if (memcmp(packet->ethhdr.ether_shost,local_ether,6) == 0) {#ifdef SIMPLE_BPF	return 1; /* ignore this packet */#else	/* with the bigger BPF program, we should never get here */	fprintf(stderr, "BPF program is broken\n");	exit(1);#endif /* SIMPLE_BPF */    }        if (memcmp(packet->ethhdr.ether_dhost,MAC_BCAST_ADDR,6) == 0 ||	memcmp(packet->ethhdr.ether_dhost,local_ether,6) == 0)	return 0; /* I should look at this packet */    else {	print_packet(packet);	return 1; /* ignore this packet */    }}int is_bpf(int fd) {    /* is this socket tied to bpf? */    /* quick hack() - try a trivial bpf ioctl */    struct bpf_version v;    return (ioctl(fd,BIOCVERSION,&v) == 0);	}#endif /* USE_BPF */int read_packet(int sock, struct pppoe_packet *packet, int *len) {/*    struct sockaddr_in from; */#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6    int fromlen = PACKETBUF;#else    socklen_t fromlen = PACKETBUF;#endif    time_t tm;    time(&tm);        while(1) {#ifdef USE_BPF	{ 	    int j;	    if ((j = read_bpf_packet(sock, packet)) < 0)		return -1; /* read_bpf_packet() will report error */	    else if (j > 0)		continue; /* read a packet,  but not what we wanted */	}#else	if (recvfrom(sock, packet, PACKETBUF, 0, 		     NULL /*(struct sockaddr *)&from*/, &fromlen) < 0) {	    perror("pppoe: recv (read_packet)");	    return -1;	}#endif /* USE_BPF */	if (opt_verbose)	{	    fprintf(log_file, "Received packet at %s", ctime(&tm));	    print_packet(packet);	    fputc('\n', log_file);	}	return sock;    }}void sigchild(int src) {    clean_child = 1;}void cleanup_and_exit(int status) {    close(disc_sock);    close(sess_sock);    close(1);    if (pppd_listen > 0)#ifdef __linux__	kill(pppd_listen, SIGTERM);#else        kill(SIGTERM, pppd_listen);#endif    if (sess_listen > 0)#ifdef __linux__	kill(sess_listen, SIGTERM);#else	kill(SIGTERM, sess_listen);#endif    exit(status);}void sigint(int src){    cleanup_and_exit(1);}void sess_handler(void) {    /* pull packets of sess_sock and feed to pppd */    struct pppoe_packet *packet = NULL;    int pkt_size;#ifdef BUGGY_AC/* the following code deals with buggy AC software which sometimes sends   duplicate packets */#define DUP_COUNT 10#define DUP_LENGTH 20    unsigned char dup_check[DUP_COUNT][DUP_LENGTH];    int i, ptr = 0;#endif /* BUGGY_AC */#ifdef BUGGY_AC    memset(dup_check, 0, sizeof(dup_check));#endif    /* allocate packet once */    packet = malloc(PACKETBUF);    assert(packet != NULL);        fprintf(error_file, "sess_handler %d\n", getpid());    while(1)     {	while(read_packet(sess_sock,packet,&pkt_size) != sess_sock)	    ;#ifdef __linux__	if (memcmp(packet->ethhdr.h_source, dst_addr, sizeof(dst_addr)) != 0)#else	if (memcmp(packet->ethhdr.ether_shost, dst_addr, sizeof(dst_addr)) 	    != 0)#endif	    continue; /* packet not from AC */	if (packet->session != session)	    continue; /* discard other sessions */#ifdef __linux__	if (packet->ethhdr.h_proto != htons(ETH_P_PPPOE_SESS)) 	{	    fprintf(log_file, "pppoe: invalid session proto %x detected\n",		    ntohs(packet->ethhdr.h_proto));	    continue;	}#else	if (packet->ethhdr.ether_type != htons(ETH_P_PPPOE_SESS)) 	{	    fprintf(log_file, "pppoe: invalid session proto %x detected\n",		    ntohs(packet->ethhdr.ether_type));	    continue;	}#endif	if (packet->code != CODE_SESS) {	    fprintf(log_file, "pppoe: invalid session code %x\n", packet->code);	    continue;	}#if BUGGY_AC	/* we need to go through a list of recently-received packets to	   make sure the AC hasn't sent us a duplicate */	for (i = 0; i < DUP_COUNT; i++)	    if (memcmp(packet, dup_check[i], sizeof(dup_check[0])) == 0)		return; /* we've received a dup packet */#define min(a,b) ((a) < (b) ? (a) : (b))	memcpy(dup_check[ptr], packet, min(ntohs(packet->length), 						 sizeof(dup_check[0])));	ptr = ++ptr % DUP_COUNT;#endif /* BUGGY_AC */	encode_ppp(1, (unsigned char *)(packet+1), ntohs(packet->length));    }}void pppd_handler(void) {  /* take packets from pppd and feed them to sess_sock */  struct pppoe_packet *packet = NULL;  unsigned char buf[PACKETBUF];  int len, pkt_size;  time_t tm;  fprintf(error_file, "pppd_handler %d\n", getpid());  /* allocate packet once */  packet = malloc(PACKETBUF);  assert(packet != NULL);  while(1) {    if ((len = read(0, buf, sizeof(buf))) < 0) {      perror("pppoe");      exit(1);    }    if (len == 0)      continue;     if (opt_verbose == 1) {	time(&tm);	fprintf(log_file, "\n%sInput of %d bytes:\n", ctime(&tm), len);	print_hex(buf, len);	fputc('\n', log_file);    }		    if ((pkt_size = create_sess(packet, src_addr, dst_addr, buf, len, 				session)) == 0) {      fprintf(error_file, "pppoe: unable to create packet\n");      continue;    }        if (send_packet(sess_sock, packet, pkt_size, if_name) < 0) {      fprintf(error_file, "pppoe: unable to send PPPoE packet\n");      exit(1);    }  }}	int main(int argc, char **argv){    struct pppoe_packet *packet = NULL;    int pkt_size;    int opt;    /* initialize error_file here to avoid glibc2.1 issues */     error_file = stderr;        /* parse options */    while ((opt = getopt(argc, argv, "I:L:VE:F:")) != -1)	switch(opt)	{	case 'F': /* sets invalid forwarding */	    if (*optarg == 'a') /* always forward */		opt_fwd = 1;	    else if (*optarg == 's') /* search for flag */		opt_fwd_search = 1;	    else		fprintf(stderr, "Invalid forward option %c\n", *optarg);	    break;	case 'I': /* sets interface */	    if (if_name != NULL)		free(if_name);	    if ((if_name=malloc(strlen(optarg+1))) == NULL)	    {		fprintf(stderr, "malloc\n");		exit(1);	    }	    strcpy(if_name, optarg);	    break;	    	case 'L': /* log file */	    opt_verbose = 1;	    if (log_file != NULL)		fclose(log_file);	    if ((log_file=fopen(optarg, "w")) == NULL)	    {		fprintf(stderr, "fopen\n");		exit(1);	    }	    if (setvbuf(log_file, NULL, _IONBF, 0) != 0)	    {		fprintf(stderr, "setvbuf\n");		exit(1);	    }	    break;	case 'V': /* version */	    printf("pppoe version %d.%d\n", VERSION_MAJOR, VERSION_MINOR);	    exit(0);	    break;	case 'E': /* error file */	    if ((error_file = fopen(optarg, "w")) == NULL)	    {		fprintf(stderr, "fopen\n");		exit(1);	    }	    if (setvbuf(error_file, NULL, _IONBF, 0) != 0)	    {		fprintf(stderr, "setvbuf\n");		exit(1);	    }	    break;	default:	    fprintf(stderr, "Unknown option %c\n", optopt);	    exit(1);	}    if (if_name == 0)	if_name = "eth0";    /* allocate packet once */    packet = malloc(PACKETBUF);    assert(packet != NULL);        /* create the raw socket we need */    signal(SIGINT, sigint);    signal(SIGTERM, sigint);    if ((disc_sock = open_interface(if_name,ETH_P_PPPOE_DISC,src_addr)) < 0)     {	fprintf(error_file, "pppoe: unable to create raw socket\n");	return 1;    }    /* initiate connection */    /* start the PPPoE session */    if ((pkt_size = create_padi(packet, src_addr, NULL)) == 0) {	fprintf(stderr, "pppoe: unable to create PADI packet\n");	exit(1);    }    /* send the PADI packet */    if (send_packet(disc_sock, packet, pkt_size, if_name) < 0) {	fprintf(stderr, "pppoe: unable to send PADI packet\n");	exit(1);    }        /* wait for PADO */    while (read_packet(disc_sock, packet, &pkt_size) != disc_sock || 	   (packet->code != CODE_PADO && packet->code != CODE_PADT)) {	fprintf(log_file, "pppoe: unexpected packet %x\n", 		packet->code);	continue;    }#ifdef __linux__    memcpy(dst_addr, packet->ethhdr.h_source, sizeof(dst_addr));#else    memcpy(dst_addr, packet->ethhdr.ether_shost, sizeof(dst_addr));#endif        /* send PADR */    if ((pkt_size = create_padr(packet, src_addr, dst_addr, NULL)) == 0) {	fprintf(stderr, "pppoe: unable to create PADR packet\n");	exit(1);    }    if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {	fprintf(stderr, "pppoe: unable to send PADR packet\n");	exit(1);    }        /* wait for PADS */#ifdef __linux__    while (read_packet(disc_sock, packet, &pkt_size) != disc_sock ||	   (memcmp(packet->ethhdr.h_source,		   dst_addr, sizeof(dst_addr)) != 0)) #else    while (read_packet(disc_sock, packet, &pkt_size) != disc_sock ||	   (memcmp(packet->ethhdr.ether_shost, 		   dst_addr, sizeof(dst_addr)) != 0)) #endif    {	if (packet->code != CODE_PADS && packet->code != CODE_PADT)	    fprintf(log_file, "pppoe: unexpected packet %x\n", packet->code);	continue;    }    if (packet->code == CODE_PADT) /* early termination */	cleanup_and_exit(0);        session = packet->session;    if ((sess_sock = open_interface(if_name,ETH_P_PPPOE_SESS,NULL)) < 0) {	fprintf(log_file, "pppoe: unable to create raw socket\n");	cleanup_and_exit(1);    }        clean_child = 0;    signal(SIGCHLD, sigchild);        /* all sockets are open fork off handlers */    if ((sess_listen = fork()) == 0) 	sess_handler(); /* child */    if (sess_listen < 0) {	perror("pppoe: fork");	cleanup_and_exit(1);    }    if ((pppd_listen = fork()) == 0)	pppd_handler(); /* child */    if (pppd_listen < 0) {	perror("pppoe: fork");	cleanup_and_exit(1);    }            /* wait for all children to die */    /* this is not perfect - race conditions on dying children are still       possible */    while(1) {	if (waitpid((pid_t)-1,NULL,WNOHANG) < 0 && errno == ECHILD)	    break; /* all children dead */	if (read_packet(disc_sock, packet, &pkt_size) == disc_sock) {	    if (packet->code == CODE_PADT)		cleanup_and_exit(1);	}	/* clean up any dead children */	while (waitpid((pid_t)-1,NULL,WNOHANG) > 0)	    ;	    }        return 0;}

⌨️ 快捷键说明

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