diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2000-06-18 07:30:42 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2000-06-18 07:30:42 +0000 |
commit | 2150d33fb6cf1dfe1016cbf7782271645f323685 (patch) | |
tree | a63b5f9c629d99e6f6e3e99b7e00fb61855ed3c2 /usr.sbin/pppoe/pppoe.c | |
parent | a9a8db41f99fc2b2bd057e21ca6bec6059a826af (diff) |
import my pppoe code
Diffstat (limited to 'usr.sbin/pppoe/pppoe.c')
-rw-r--r-- | usr.sbin/pppoe/pppoe.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/usr.sbin/pppoe/pppoe.c b/usr.sbin/pppoe/pppoe.c new file mode 100644 index 00000000000..ab1e89a0efd --- /dev/null +++ b/usr.sbin/pppoe/pppoe.c @@ -0,0 +1,420 @@ +/* $OpenBSD: pppoe.c,v 1.1 2000/06/18 07:30:41 jason Exp $ */ + +/* + * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Network Security + * Technologies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <net/bpf.h> +#include <errno.h> +#include <string.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <sysexits.h> +#include <stdlib.h> +#include <signal.h> + +#include "pppoe.h" + +int option_verbose = 0; +u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +int main __P((int, char **)); +void usage __P((char *)); +int getifhwaddr __P((char *, char *, struct ether_addr *)); +int setupfilter __P((char *, struct ether_addr *, int)); +void child_handler __P((int)); +int signal_init __P((void)); + +int +main(int argc, char **argv) { + char *ifname = NULL, *sysname = NULL, *srvname = NULL; + char ifnambuf[IFNAMSIZ]; + struct ether_addr ea; + int bpffd, smode = 0, c; + + while ((c = getopt(argc, argv, "svi:n:p:")) != -1) { + switch (c) { + case 'i': + if (ifname != NULL) { + usage(argv[0]); + return (EX_USAGE); + } + ifname = optarg; + break; + case 'n': + if (srvname != NULL) { + usage(argv[0]); + return (EX_USAGE); + } + srvname = optarg; + break; + case 'p': + if (sysname != NULL) { + usage(argv[0]); + return (EX_USAGE); + } + sysname = optarg; + break; + case 's': + if (smode) { + usage(argv[0]); + return (EX_USAGE); + } + smode = 1; + break; + case 'v': + option_verbose++; + break; + default: + usage(argv[0]); + return (EX_USAGE); + } + } + + argc -= optind; + if (argc != 0) { + usage(argv[0]); + return (EX_USAGE); + } + + if (getifhwaddr(ifname, ifnambuf, &ea) < 0) + return (EX_IOERR); + + bpffd = setupfilter(ifnambuf, &ea, smode); + if (bpffd < 0) + return (EX_IOERR); + + signal_init(); + + if (smode) + server_mode(bpffd, sysname, srvname, &ea); + else + client_mode(bpffd, sysname, srvname, &ea); + + return (0); +} + +int +setupfilter(ifn, ea, server_mode) + char *ifn; + struct ether_addr *ea; + int server_mode; +{ + char device[sizeof "/dev/bpf0000000000"]; + u_int8_t *ep = (u_int8_t *)ea; + int fd, idx = 0; + u_int u, i; + struct ifreq ifr; + struct bpf_insn insns[20]; + struct bpf_program filter; + + idx = 0; + + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 12; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ETHERTYPE_PPPOE; + insns[idx].jt = 1; + insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ETHERTYPE_PPPOEDISC; + insns[idx].jt = 0; + insns[idx].jf = 4; + idx++; + + insns[idx].code = BPF_LD | BPF_W | BPF_ABS; + insns[idx].k = 6; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = + (ep[0] << 24) | (ep[1] << 16) | (ep[2] << 8) | (ep[3] << 0); + insns[idx].jt = 0; + insns[idx].jf = 3; + idx++; + + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 10; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ep[4] << 8 | ep[5]; + insns[idx].jt = 0; + insns[idx].jf = 1; + idx++; + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = insns[idx].jt = insns[idx].jf = 0; + idx++; + + if (server_mode) { + insns[idx].code = BPF_LD | BPF_W | BPF_ABS; + insns[idx].k = insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = 0xffffffff; + insns[idx].jt = 0; + insns[idx].jf = 3; + idx++; + + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 4; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = 0xffff; + insns[idx].jt = 4; + insns[idx].jf = 0; + idx++; + } + + insns[idx].code = BPF_LD | BPF_W | BPF_ABS; + insns[idx].k = insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = (ep[0]) | (ep[1] << 8) | (ep[3] << 16) | (ep[3] << 24); + insns[idx].jt = 0; + insns[idx].jf = 3; + idx++; + + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 4; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = (ep[4]) | (ep[5] << 8); + insns[idx].jt = 0; + insns[idx].jf = 1; + idx++; + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = (u_int)-1; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = (u_int)-1; + insns[idx].jt = 0; + insns[idx].jf = 0; + idx++; + + filter.bf_len = idx; + filter.bf_insns = insns; + + for (i = 0; 1; i++) { + snprintf(device, sizeof(device), "/dev/bpf%d", i++); + fd = open(device, O_RDWR); + if (fd < 0) { + if (errno != EBUSY) + err(EX_IOERR, "%s", device); + } + else + break; + } + + u = PPPOE_BPF_BUFSIZ; + if (ioctl(fd, BIOCSBLEN, &u) < 0) { + close(fd); + err(EX_IOERR, "set snaplength"); + } + + u = 1; + if (ioctl(fd, BIOCIMMEDIATE, &u) < 0) { + close(fd); + err(EX_IOERR, "set immediate"); + } + + strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; + if (ioctl(fd, BIOCSETIF, &ifr) < 0) { + close(fd); + err(EX_IOERR, "set interface"); + } + + if (ioctl(fd, BIOCGDLT, &u) < 0) { + close(fd); + err(EX_IOERR, "get interface type"); + } + if (u != DLT_EN10MB) + err(EX_IOERR, "%s is not ethernet", ifn); + + if (ioctl(fd, BIOCSETF, &filter) < 0) { + close(fd); + err(EX_IOERR, "BIOCSETF"); + } + + return (fd); +} + +int +getifhwaddr(ifnhint, ifnambuf, ea) + char *ifnhint, *ifnambuf; + struct ether_addr *ea; +{ + int s; + char *inbuf = NULL; + struct ifconf ifc; + struct ifreq *ifrp, ifreq, req; + struct sockaddr_dl *dl; + int len = 8192, i; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket"); + return (-1); + } + + while (1) { + ifc.ifc_len= len; + ifc.ifc_buf = inbuf = realloc(inbuf, len); + if (inbuf == NULL) + err(1, "malloc"); + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) + err(1, "gifconf"); + if (ifc.ifc_len + sizeof(struct ifreq) < len) + break; + len *= 2; + } + + ifrp = ifc.ifc_req; + ifreq.ifr_name[0] = '\0'; + for (i = 0; i < ifc.ifc_len; ) { + ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i); + i += sizeof(ifrp->ifr_name) + + (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr) ? + ifrp->ifr_addr.sa_len : sizeof(struct sockaddr)); + if (ifrp->ifr_addr.sa_family != AF_LINK) + continue; + if (ifnhint != NULL && strncmp(ifnhint, ifrp->ifr_name, + sizeof(ifrp->ifr_name))) + continue; + if (ifnhint == NULL) { + strncpy(req.ifr_name, ifrp->ifr_name, IFNAMSIZ); + req.ifr_name[IFNAMSIZ-1] = '\0'; + if (ioctl(s, SIOCGIFFLAGS, &req) < 0) + err(EX_IOERR, "get flags"); + if ((req.ifr_flags & IFF_UP) == 0) + continue; + } + dl = (struct sockaddr_dl *)&ifrp->ifr_addr; + if (dl->sdl_type != IFT_ETHER) { + if (ifnhint == NULL) + continue; + fprintf(stderr, "not ethernet interface: %s\n", + ifnhint); + free(inbuf); + close(s); + return (-1); + } + if (dl->sdl_alen != ETHER_ADDR_LEN) { + fprintf(stderr, "invalid hwaddr len: %u\n", + dl->sdl_alen); + free(inbuf); + close(s); + return (-1); + } + bcopy(dl->sdl_data + dl->sdl_nlen, ea, sizeof(*ea)); + strncpy(ifnambuf, ifrp->ifr_name, IFNAMSIZ); + ifnambuf[IFNAMSIZ-1] = '\0'; + free(inbuf); + close(s); + return (0); + } + free(inbuf); + if (ifnhint == NULL) + fprintf(stderr, "no running ethernet found\n"); + else + fprintf(stderr, "no such interface: %s\n", ifnhint); + close(s); + return (-1); +} + +void +usage(progname) + char *progname; +{ + fprintf(stderr, "%s [-s] [-v] [-p system] [-i interface]\n", progname); +} + +void +child_handler(sig) + int sig; +{ + int status; + + while (wait3(&status, WNOHANG, NULL) > 0); +} + +int +signal_init() +{ + struct sigaction act; + + if (sigemptyset(&act.sa_mask) < 0) + return (-1); + act.sa_flags = SA_RESTART; + act.sa_handler = child_handler; + if (sigaction(SIGCHLD, &act, NULL) < 0) + return (-1); + + if (sigemptyset(&act.sa_mask) < 0) + return (-1); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &act, NULL) < 0) + return (-1); + + return (0); +} |