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 | |
parent | a9a8db41f99fc2b2bd057e21ca6bec6059a826af (diff) |
import my pppoe code
Diffstat (limited to 'usr.sbin/pppoe')
-rw-r--r-- | usr.sbin/pppoe/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/pppoe/client.c | 566 | ||||
-rw-r--r-- | usr.sbin/pppoe/common.c | 293 | ||||
-rw-r--r-- | usr.sbin/pppoe/debug.c | 202 | ||||
-rw-r--r-- | usr.sbin/pppoe/pppoe.8 | 129 | ||||
-rw-r--r-- | usr.sbin/pppoe/pppoe.c | 420 | ||||
-rw-r--r-- | usr.sbin/pppoe/pppoe.h | 146 | ||||
-rw-r--r-- | usr.sbin/pppoe/rfc2516.txt | 955 | ||||
-rw-r--r-- | usr.sbin/pppoe/server.c | 478 | ||||
-rw-r--r-- | usr.sbin/pppoe/session.c | 140 | ||||
-rw-r--r-- | usr.sbin/pppoe/tag.c | 188 |
11 files changed, 3524 insertions, 0 deletions
diff --git a/usr.sbin/pppoe/Makefile b/usr.sbin/pppoe/Makefile new file mode 100644 index 00000000000..600f58f625d --- /dev/null +++ b/usr.sbin/pppoe/Makefile @@ -0,0 +1,7 @@ + +PROG= pppoe +MAN= pppoe.8 +SRCS= client.c common.c debug.c pppoe.c server.c session.c tag.c +CFLAGS+= -Werror -Wall -Wstrict-prototypes -Wmissing-prototypes + +.include <bsd.prog.mk> diff --git a/usr.sbin/pppoe/client.c b/usr.sbin/pppoe/client.c new file mode 100644 index 00000000000..519c70b60df --- /dev/null +++ b/usr.sbin/pppoe/client.c @@ -0,0 +1,566 @@ +/* $OpenBSD: client.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/param.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 <net/ppp_defs.h> +#include <errno.h> +#include <string.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <sysexits.h> +#include <stdlib.h> +#include <syslog.h> +#include <signal.h> + +#include "pppoe.h" + +#define PPP_PROG "/usr/sbin/ppp" + +#define STATE_EXPECT_PADO 1 +#define STATE_EXPECT_PADS 2 +#define STATE_EXPECT_SESSION 3 + +u_int32_t client_cookie = 0; +u_int16_t client_sessionid = 0xffff; +int pppfd = -1; +int client_state = -1; +u_int8_t etherremoteaddr[6], etherlocaladdr[6]; + +static int getpackets __P((int, char *, char *, struct ether_addr *, + struct ether_addr *)); +static int send_padi __P((int, struct ether_addr *, u_int8_t *)); +static int send_padr __P((int, char *, struct ether_addr *, + struct ether_addr *, struct ether_header *, struct pppoe_header *, + struct tag_list *)); +static int recv_pado __P((int, char *, struct ether_addr *, + struct ether_addr *, struct ether_header *, struct pppoe_header *, + u_long, u_int8_t *)); +static int recv_pads __P((int, char *, char *, struct ether_addr *, + struct ether_addr *, struct ether_header *, struct pppoe_header *, + u_long, u_int8_t *)); +static int recv_padt __P((int, struct ether_addr *, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); + +void timer_handler __P((int)); +int timer_set __P((u_int)); +int timer_clr __P((void)); +int timer_hit __P((void)); + +int +client_mode(bfd, sysname, srvname, myea) + int bfd; + char *sysname, *srvname; + struct ether_addr *myea; +{ + struct ether_addr rmea; + fd_set fds; + int r = 0, max; + + pppfd = -1; + client_sessionid = 0xffff; + + r = send_padi(bfd, myea, srvname); + if (r <= 0) + return (r); + + FD_ZERO(&fds); + for (;;) { + FD_SET(bfd, &fds); + max = bfd + 1; + if (pppfd >= 0) { + if (pppfd >= max) + max = pppfd + 1; + FD_SET(pppfd, &fds); + } + + r = select(max, &fds, NULL, NULL, NULL); + if (r < 0) { + if (errno == EINTR) { + if (timer_hit()) + timer_clr(); + break; + } + break; + } + if (FD_ISSET(bfd, &fds)) { + r = getpackets(bfd, srvname, sysname, myea, &rmea); + if (r <= 0) + break; + } + if (pppfd >= 0 && FD_ISSET(pppfd, &fds)) { + r = ppp_to_bpf(bfd, pppfd, myea, &rmea, + client_sessionid); + if (r < 0) + break; + } + } + + if (pppfd >= 0) { + send_padt(bfd, myea, &rmea, client_sessionid); + close(pppfd); + pppfd = -1; + } + return (r); +} + +static int +send_padi(fd, ea, srv) + int fd; + struct ether_addr *ea; + u_int8_t *srv; +{ + struct iovec iov[10]; + struct pppoe_header ph = { + PPPOE_VERTYPE(1, 1), + PPPOE_CODE_PADI, 0, 0 + }; + struct pppoe_tag thost, tserv; + u_int16_t etype = htons(ETHERTYPE_PPPOEDISC); + int i = 0; + + /* ether_header */ + iov[0].iov_base = etherbroadcastaddr; + iov[0].iov_len = ETHER_ADDR_LEN; + iov[1].iov_base = ea; + iov[1].iov_len = ETHER_ADDR_LEN; + iov[2].iov_base = &etype; + iov[2].iov_len = sizeof(etype); + + /* pppoe_header */ + iov[3].iov_base = &ph; + iov[3].iov_len = sizeof(ph); + + /* host-uniq tag */ + client_cookie = cookie_bake(); + thost.type = htons(PPPOE_TAG_HOST_UNIQ); + thost.len = htons(sizeof(client_cookie)); + ph.len += sizeof(thost.type)+sizeof(thost.len)+sizeof(client_cookie); + iov[4].iov_base = &thost; + iov[4].iov_len = sizeof(thost.len) + sizeof(thost.type) ; + iov[5].iov_base = &client_cookie; + iov[5].iov_len = sizeof(client_cookie); + + /* service-name tag */ + tserv.type = htons(PPPOE_TAG_SERVICE_NAME); + tserv.len = (srv == NULL) ? 0 : strlen(srv); + tserv.val = srv; + ph.len += tserv.len + sizeof(tserv.type) + sizeof(tserv.len); + iov[6].iov_base = &tserv; + iov[6].iov_len = sizeof(tserv.len) + sizeof(tserv.type); + i = 7; + if (tserv.len) { + iov[7].iov_base = tserv.val; + iov[7].iov_len = tserv.len; + i = 8; + } + tserv.len = htons(tserv.len); + + ph.len = htons(ph.len); + + client_state = STATE_EXPECT_PADO; + timer_set(10); + return (writev(fd, iov, i)); +} + +static int +send_padr(bfd, srv, myea, rmea, eh, ph, tl) + int bfd; + char *srv; + struct ether_addr *myea, *rmea; + struct ether_header *eh; + struct pppoe_header *ph; + struct tag_list *tl; +{ + struct iovec iov[12]; + u_int16_t etype = htons(ETHERTYPE_PPPOEDISC); + struct pppoe_tag hutag, svtag; + struct tag_node *n; + int idx = 0, slen; + + timer_set(5); + client_state = STATE_EXPECT_PADS; + + iov[idx].iov_base = rmea; + iov[idx++].iov_len = ETHER_ADDR_LEN; + iov[idx].iov_base = myea; + iov[idx++].iov_len = ETHER_ADDR_LEN; + iov[idx].iov_base = &etype; + iov[idx++].iov_len = sizeof(etype); + + ph->vertype = PPPOE_VERTYPE(1, 1); + ph->code = PPPOE_CODE_PADR; + ph->len = 0; + ph->sessionid = 0; + iov[idx].iov_base = ph; + iov[idx++].iov_len = sizeof(struct pppoe_header); + + /* Host-Uniq */ + hutag.type = htons(PPPOE_TAG_HOST_UNIQ); + hutag.len = htons(sizeof(client_cookie)); + iov[idx].iov_base = &hutag; + iov[idx++].iov_len = sizeof(hutag.type) + sizeof(hutag.len); + ph->len += sizeof(hutag.type)+sizeof(hutag.len)+sizeof(client_cookie); + iov[idx].iov_base = &client_cookie; + iov[idx++].iov_len = sizeof(client_cookie); + + /* Service-Name */ + slen = (srv == NULL) ? 0 : strlen(srv); + svtag.type = htons(PPPOE_TAG_SERVICE_NAME); + svtag.len = htons(slen); + iov[idx].iov_base = &svtag; + iov[idx++].iov_len = sizeof(hutag.type) + sizeof(hutag.len); + ph->len += slen + sizeof(hutag.type) + sizeof(hutag.len); + if (slen) { + iov[idx].iov_base = srv; + iov[idx++].iov_len = slen; + } + + n = tag_lookup(tl, PPPOE_TAG_RELAY_SESSION, 0); + if (n != NULL) { + iov[idx].iov_base = &n->type; + iov[idx++].iov_len = sizeof(n->type) + sizeof(n->len); + if (n->len) { + iov[idx].iov_base = &n->val; + iov[idx++].iov_len = n->len; + } + ph->len += sizeof(n->type) + sizeof(n->len) + n->len; + } + + n = tag_lookup(tl, PPPOE_TAG_AC_COOKIE, 0); + if (n != NULL) { + iov[idx].iov_base = &n->type; + iov[idx++].iov_len = sizeof(n->type) + sizeof(n->len); + if (n->len) { + iov[idx].iov_base = n->val; + iov[idx++].iov_len = n->len; + } + ph->len += sizeof(n->type) + sizeof(n->len) + n->len; + } + + ph->len = htons(ph->len); + tag_hton(tl); + + return (writev(bfd, iov, idx)); +} + +static int +getpackets(bfd, srv, sysname, myea, rmea) + int bfd; + char *srv, *sysname; + struct ether_addr *myea, *rmea; +{ + static u_int8_t *pktbuf; + u_int8_t *mpkt, *pkt, *epkt; + struct ether_header eh; + struct pppoe_header ph; + struct bpf_hdr *bh; + int rlen, r; + u_long len; + + if (pktbuf == NULL) { + pktbuf = (u_int8_t *)malloc(PPPOE_BPF_BUFSIZ); + if (pktbuf == NULL) + return (-1); + } + + rlen = read(bfd, pktbuf, PPPOE_BPF_BUFSIZ); + if (rlen < 0) { + if (errno == EINTR) + return (0); + return (-1); + } + + pkt = pktbuf; + epkt = pkt + rlen; + while (pkt < epkt) { + bh = (struct bpf_hdr *)pkt; + len = bh->bh_caplen; + mpkt = pkt + bh->bh_hdrlen; + + debug_packet(mpkt, len); + + /* Pull out ethernet header */ + if (len < sizeof(struct ether_header)) + goto next; + bcopy(mpkt, &eh, sizeof(struct ether_header)); + eh.ether_type = ntohs(eh.ether_type); + len -= sizeof(struct ether_header); + mpkt += sizeof(struct ether_header); + + /* Pull out pppoe header */ + if (len < sizeof(struct pppoe_header)) + goto next; + bcopy(mpkt, &ph, sizeof(struct pppoe_header)); + len -= sizeof(struct pppoe_header); + mpkt += sizeof(struct pppoe_header); + ph.len = ntohs(ph.len); + ph.sessionid = ntohs(ph.sessionid); + + if (PPPOE_VER(ph.vertype) != 1 || + PPPOE_TYPE(ph.vertype) != 1) + goto next; + + if (len > ph.len) + len = ph.len; + + if (eh.ether_type == ETHERTYPE_PPPOEDISC) { + /* Discovery Stage */ + switch (ph.code) { + case PPPOE_CODE_PADO: + r = recv_pado(bfd, srv, myea, rmea, &eh, + &ph, len, mpkt); + break; + case PPPOE_CODE_PADS: + r = recv_pads(bfd, srv, sysname, myea, rmea, + &eh, &ph, len, mpkt); + break; + case PPPOE_CODE_PADT: + r = recv_padt(bfd, myea, rmea, &eh, &ph, + len, mpkt); + break; + default: + recv_debug(bfd, myea, &eh, &ph, len, mpkt); + r = 0; + } + if (r < 0) + return (r); + } + else if (eh.ether_type == ETHERTYPE_PPPOE) { + if (client_state != STATE_EXPECT_SESSION) + goto next; + if (bcmp(rmea, &eh.ether_shost[0], ETHER_ADDR_LEN)) + goto next; + if (pppfd <= 0) + goto next; + if (bpf_to_ppp(pppfd, len, mpkt) <= 0) + return (-1); + } +next: + pkt += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + } + return (1); +} + + +static int +recv_pado(bfd, srv, myea, rmea, eh, ph, len, pkt) + int bfd; + char *srv; + struct ether_addr *myea, *rmea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long len; + u_int8_t *pkt; +{ + struct tag_list tl; + struct tag_node *n; + int r, slen; + + if (timer_hit()) { + timer_clr(); + return (0); + } + + if (client_state != STATE_EXPECT_PADO) + return (0); + + tag_init(&tl); + if (tag_pkt(&tl, len, pkt) < 0) + goto out; + + if (ph->sessionid != 0) + goto out; + + if (tag_lookup(&tl, PPPOE_TAG_AC_NAME, 0) == NULL) + goto out; + + n = tag_lookup(&tl, PPPOE_TAG_HOST_UNIQ, 0); + if (n == NULL || n->len != sizeof(client_cookie)) + goto out; + if (bcmp(n->val, &client_cookie, sizeof(client_cookie))) + goto out; + + r = 0; + slen = (srv == NULL) ? 0 : strlen(srv); + while ((n = tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, r)) != NULL) { + if (slen == 0 || n->len == 0) + break; + if (n->len == slen && !strncmp(srv, n->val, slen)) + break; + r++; + } + + if (n == NULL) + goto out; + + bcopy(&eh->ether_shost[0], rmea, ETHER_ADDR_LEN); + + timer_clr(); + r = send_padr(bfd, srv, myea, rmea, eh, ph, &tl); + tag_destroy(&tl); + return (r); + +out: + tag_destroy(&tl); + return (0); +} + +static int +recv_pads(bfd, srv, sysname, myea, rmea, eh, ph, len, pkt) + int bfd; + char *srv, *sysname; + struct ether_addr *myea, *rmea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long len; + u_int8_t *pkt; +{ + struct tag_node *n; + struct tag_list tl; + + if (timer_hit()) { + timer_clr(); + return (0); + } + + if (bcmp(rmea, &eh->ether_shost[0], ETHER_ADDR_LEN)) + return (0); + + if (client_state != STATE_EXPECT_PADS) + return (0); + + tag_init(&tl); + if (tag_pkt(&tl, len, pkt) < 0) + goto out; + + n = tag_lookup(&tl, PPPOE_TAG_HOST_UNIQ, 0); + if (n == NULL || n->len != sizeof(client_cookie)) + goto out; + if (bcmp(n->val, &client_cookie, sizeof(client_cookie))) + goto out; + + if (ph->sessionid == 0) { + timer_clr(); + return (-1); + } + + timer_clr(); + + pppfd = runppp(bfd, sysname); + if (pppfd < 0) { + send_padt(bfd, myea, rmea, ph->sessionid); + return (-1); + } + + client_state = STATE_EXPECT_SESSION; + client_sessionid = ph->sessionid; + +out: + tag_destroy(&tl); + return (0); +} + +static int +recv_padt(bfd, myea, rmea, eh, ph, len, pkt) + int bfd; + struct ether_addr *myea, *rmea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long len; + u_int8_t *pkt; +{ + if (bcmp(&eh->ether_shost[0], rmea, ETHER_ADDR_LEN)) + return (0); + + if (client_sessionid != 0xffff && ph->sessionid == client_sessionid) + return (-1); + + return (0); +} + +static volatile int timer_alarm; +static struct sigaction timer_oact; + +void +timer_handler(sig) + int sig; +{ + timer_alarm = 1; +} + +int +timer_set(sec) + u_int sec; +{ + struct sigaction act; + + timer_alarm = 0; + if (sigemptyset(&act.sa_mask) < 0) + return (-1); + act.sa_flags = 0; + act.sa_handler = timer_handler; + if (sigaction(SIGALRM, &act, &timer_oact) < 0) + return (-1); + alarm(sec); + return (0); +} + +int +timer_clr(void) +{ + alarm(0); + if (sigaction(SIGALRM, &timer_oact, NULL) < 0) + return (-1); + timer_alarm = 0; + return (0); +} + +int +timer_hit(void) +{ + return (timer_alarm); +} diff --git a/usr.sbin/pppoe/common.c b/usr.sbin/pppoe/common.c new file mode 100644 index 00000000000..e47537bbb0f --- /dev/null +++ b/usr.sbin/pppoe/common.c @@ -0,0 +1,293 @@ +/* $OpenBSD: common.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/stat.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/ppp_defs.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 <grp.h> +#include <syslog.h> +#include <md5.h> + +#include "pppoe.h" + +#define PPP_PROG "/usr/sbin/ppp" + +void debugv __P((char *, struct iovec *, int)); + +int +runppp(bpffd, sysname) + int bpffd; + char *sysname; +{ + int socks[2], fdm, fds, closeit; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) < 0) + return (-1); + + fdm = socks[0]; + fds = socks[1]; + + pid = fork(); + if (pid < 0) { + close(fds); + close(fdm); + return (-1); + } + + if (pid != 0) { + /* Parent */ + close(fds); + return (fdm); + } + + if (setsid() < 0) + _exit(99); + + /* Child */ + close(bpffd); + close(fdm); + closeit = 1; + + if (fds == STDIN_FILENO) + closeit = 0; + else + dup2(fds, STDIN_FILENO); + + if (fds == STDOUT_FILENO) + closeit = 0; + else + dup2(fds, STDOUT_FILENO); + + if (fds == STDERR_FILENO) + closeit = 0; + else + dup2(fds, STDERR_FILENO); + + if (closeit) + close(fds); + + execlp(PPP_PROG, "ppp", "-direct", sysname, NULL); + perror("execlp"); + syslog(LOG_INFO, "%s exec failed: %m", PPP_PROG); + _exit(-1); +} + +int +bpf_to_ppp(pppfd, len, pkt) + int pppfd; + u_long len; + u_int8_t *pkt; +{ + int r; + u_int8_t hdr[2] = { PPP_ALLSTATIONS, PPP_UI }; + struct iovec iov[2]; + + iov[0].iov_base = hdr; + iov[0].iov_len = sizeof(hdr); + iov[1].iov_base = pkt; + iov[1].iov_len = len; + + r = writev(pppfd, iov, 2); + if (r < 0) { + if (errno == EINTR || errno == EPIPE) + return (0); + return (-1); + } + return (1); +} + +int +ppp_to_bpf(bfd, pppfd, myea, rmea, id) + int bfd, pppfd; + struct ether_addr *myea, *rmea; + u_int16_t id; +{ + static u_int8_t *pktbuf = NULL; + struct pppoe_header ph; + struct iovec iov[5]; + u_int16_t etype; + u_int8_t trash[2]; + int r; + + if (pktbuf == NULL) { + pktbuf = (u_int8_t *)malloc(PPPOE_MTU); + if (pktbuf == NULL) + return (-1); + } + + iov[0].iov_base = trash; + iov[0].iov_len = 2; + iov[1].iov_base = pktbuf; + iov[1].iov_len = PPPOE_MTU; + r = readv(pppfd, iov, 2); + if (r <= 0) + return (-1); + r -= 2; + + iov[0].iov_len = 2; + iov[1].iov_len = r; + + ph.vertype = PPPOE_VERTYPE(1, 1); + ph.code = PPPOE_CODE_SESSION; + ph.len = htons(r); + ph.sessionid = htons(id); + etype = htons(ETHERTYPE_PPPOE); + + iov[0].iov_base = rmea; iov[0].iov_len = ETHER_ADDR_LEN; + iov[1].iov_base = myea; iov[1].iov_len = ETHER_ADDR_LEN; + iov[2].iov_base = &etype; iov[2].iov_len = sizeof(etype); + iov[3].iov_base = &ph; iov[3].iov_len = sizeof(ph); + iov[4].iov_base = pktbuf; iov[4].iov_len = r; + + return (writev(bfd, iov, 5)); +} + +void +debugv(s, iov, cnt) + char *s; + struct iovec *iov; + int cnt; +{ + int i, j; + u_int8_t *p; + + printf("%s", s); + for (i = 0; i < cnt; i++) + for (j = 0; j < iov[i].iov_len; j++) { + p = (u_int8_t *)iov[i].iov_base; + printf("%02x:", p[j]); + } + printf("\n\n"); +} + +void +recv_debug(bpffd, ea, eh, ph, pktlen, pktbuf) + int bpffd; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + struct tag_list tl; + + printf("dst %02x:%02x:%02x:%02x:%02x:%02x, " + "src %02x:%02x:%02x:%02x:%02x:%02x, type %04x\n", + eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2], + eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5], + eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2], + eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5], + eh->ether_type); + printf("\tver %d, type %d, code %02x, id %04x, len %d\n", + PPPOE_VER(ph->vertype), PPPOE_TYPE(ph->vertype), + ph->code, ph->sessionid, ph->len); + + tag_init(&tl); + if (tag_pkt(&tl, pktlen, pktbuf) < 0) { + printf("bad tag pkt\n"); + goto out; + } + + tag_show(&tl); +out: + tag_destroy(&tl); +} + +int +send_padt(bpffd, src_ea, dst_ea, id) + int bpffd; + struct ether_addr *src_ea, *dst_ea; + u_int16_t id; +{ + struct iovec iov[4]; + struct pppoe_header ph; + u_int16_t etype = htons(ETHERTYPE_PPPOEDISC); + + iov[0].iov_base = dst_ea; + iov[0].iov_len = ETHER_ADDR_LEN; + iov[1].iov_base = src_ea; + iov[1].iov_len = ETHER_ADDR_LEN; + iov[2].iov_base = &etype; + iov[2].iov_len = sizeof(etype); + iov[3].iov_base = &ph; + iov[3].iov_len = sizeof(ph); + + ph.vertype = PPPOE_VERTYPE(1, 1); + ph.code = PPPOE_CODE_PADT; + ph.len = 0; + ph.sessionid = htons(id); + + return (writev(bpffd, iov, 4)); +} + +u_int32_t +cookie_bake() +{ + MD5_CTX ctx; + char buf[40]; + u_int32_t x, y; + + x = arc4random(); + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char *)&x, sizeof(x)); + MD5Final(buf, &ctx); + bcopy(buf, &y, sizeof(y)); + x = x ^ y; + bcopy(buf + 4, &y, sizeof(y)); + x = x ^ y; + bcopy(buf + 8, &y, sizeof(y)); + x = x ^ y; + bcopy(buf + 12, &y, sizeof(y)); + x = x ^ y; + return (x); +} diff --git a/usr.sbin/pppoe/debug.c b/usr.sbin/pppoe/debug.c new file mode 100644 index 00000000000..068ead724ce --- /dev/null +++ b/usr.sbin/pppoe/debug.c @@ -0,0 +1,202 @@ +/* $OpenBSD: debug.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/socket.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/ppp_defs.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <string.h> +#include <ctype.h> + +#include "pppoe.h" + +void +debug_packet(u_int8_t *pkt, int len) +{ + struct ether_header eh; + struct pppoe_header ph; + + if (option_verbose == 0) + return; + + if (len < sizeof(eh)) { + printf("short packet (%d)\n", len); + return; + } + bcopy(pkt, &eh, sizeof(eh)); + pkt += sizeof(eh); + len -= sizeof(eh); + eh.ether_type = ntohs(eh.ether_type); + + if (eh.ether_type == ETHERTYPE_PPPOE && option_verbose < 2) + return; + + printf("%s -> %s %04x[", + ether_ntoa((struct ether_addr *)eh.ether_shost), + ether_ntoa((struct ether_addr *)eh.ether_dhost), + eh.ether_type); + switch (eh.ether_type) { + case ETHERTYPE_PPPOEDISC: + printf("discovery]"); + break; + case ETHERTYPE_PPPOE: + printf("session]"); + break; + default: + printf("unknown]\n"); + return; + } + + if (len < sizeof(ph)) { + printf("short packet (%d)\n", len); + return; + } + bcopy(pkt, &ph, sizeof(ph)); + pkt += sizeof(ph); + len -= sizeof(ph); + ph.sessionid = ntohs(ph.sessionid); + ph.len = ntohs(ph.len); + + if (ph.len <= len) + len = ph.len; + else { + printf("missing (%d)\n", ph.len - len); + return; + } + + printf(": version %d, type %d, ", + PPPOE_VER(ph.vertype), PPPOE_TYPE(ph.vertype)); + switch (ph.code) { + case PPPOE_CODE_SESSION: + printf("session"); + case PPPOE_CODE_PADO: + printf("PADO"); + break; + case PPPOE_CODE_PADI: + printf("PADI"); + break; + case PPPOE_CODE_PADR: + printf("PADR"); + break; + case PPPOE_CODE_PADS: + printf("PADS"); + break; + case PPPOE_CODE_PADT: + printf("PADT"); + break; + default: + printf("unknown"); + break; + } + printf(", len %d\n", len); + + while (len > 0 && eh.ether_type == ETHERTYPE_PPPOEDISC) { + int i; + u_int16_t ttype, tlen; + + if (len < sizeof(ttype)) { + printf("|\n"); + return; + } + bcopy(pkt, &ttype, sizeof(ttype)); + len -= sizeof(ttype); + pkt += sizeof(ttype); + ttype = ntohs(ttype); + printf("\ttag "); + switch (ttype) { + case PPPOE_TAG_END_OF_LIST: + printf("end-of-list"); + break; + case PPPOE_TAG_SERVICE_NAME: + printf("service-name"); + break; + case PPPOE_TAG_AC_NAME: + printf("ac-name"); + break; + case PPPOE_TAG_HOST_UNIQ: + printf("host-uniq"); + break; + case PPPOE_TAG_AC_COOKIE: + printf("ac-cookie"); + break; + case PPPOE_TAG_VENDOR_SPEC: + printf("vendor-spec"); + break; + case PPPOE_TAG_RELAY_SESSION: + printf("relay-session"); + break; + case PPPOE_TAG_SERVICE_NAME_ERROR: + printf("service-name-error"); + break; + case PPPOE_TAG_AC_SYSTEM_ERROR: + printf("ac-system-error"); + break; + case PPPOE_TAG_GENERIC_ERROR: + printf("generic-error"); + break; + default: + printf("unknown %04x", ttype); + break; + } + + if (len < sizeof(tlen)) { + printf("|\n"); + return; + } + bcopy(pkt, &tlen, sizeof(tlen)); + len -= sizeof(tlen); + pkt += sizeof(tlen); + tlen = ntohs(tlen); + printf(", len %d", tlen); + + if (len < tlen) { + printf("|\n"); + return; + } + for (i = 0; i < tlen; i++) { + if (isprint(pkt[i])) + printf("%c", pkt[i]); + else + printf("\\%03o", pkt[i]); + } + len -= tlen; + } +} diff --git a/usr.sbin/pppoe/pppoe.8 b/usr.sbin/pppoe/pppoe.8 new file mode 100644 index 00000000000..43469b15ed3 --- /dev/null +++ b/usr.sbin/pppoe/pppoe.8 @@ -0,0 +1,129 @@ +.\" $OpenBSD: pppoe.8,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 Jason L. Wright +.\" 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. +.\" +.\" +.Dd February 8, 2000 +.Dt PPPOE 8 +.Os +.Sh NAME +.Nm pppoe +.Nd PPP Over Ethernet translator +.Sh SYNOPSIS +.Nm pppoe +.Op Ar -s +.Op Ar -v +.Op Ar -i interface +.Op Ar -n service +.Op Ar -p system +.Sh DESCRIPTION +The +.Nm pppoe +program can, with the help of +.Xr ppp 8 , +act as a server or client for running PPP Over Ethernet. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl i Ar interface +Specify the interface that +.Nm +is to use. If this option is not specified, +.Nm +will use the first Ethernet interface that is up and running. +.It Fl n Ar service +Use +.Ar service +as the service name when negotiating with the server. By default, +the client will ask for any service, and expect the server to +respond with the same. +.It Fl p Ar system +This argument is passed, uninterpreted, to +.Xr ppp 8 . +It can be used to specify the configuration data to be used for +PPP Over Ethernet connections. +.It Fl s +If this option is specified, +.Nm +will run as a server. Otherwise, +.Nm +runs as a client. +.It Fl v +For each use of the flag, the verbosity of +.Nm pppoe +increases. +.El +.Sh CLIENT SETUP +Configuring the client involves setting up the +configuration file for +.Xr ppp 8 . +The following statements must be included in the file for +the specified +.Ar system +(or +``default'' +if no +.Ar system +is specified): +.Bl -tag -width XXX -offset XXX +.It set mtu 1492 +.It set mru 1492 +.It set speed sync +.It disable acfcomp +.It deny acfcomp +.It disable protocomp +.El +.Pp +Additionally, the authentication mechanism for the connection +must be specified as well as any other parameters. +.Sh SEE ALSO +.Xr ppp 8 +.Sh HISTORY +This implementation of +.Nm pppoe +first appeared in +.Ox 2.8 . +.Sh BUGS +This is software runs completely in user mode. As such it will have much +more overhead than a kernel implementation. +.Pp +The +.Ar service +is not currently used by the server code. +.Sh AUTHOR +The +.Nm pppoe +program was written by +.An Jason L. Wright +.Aq jason@thought.net +of +.An Network Security Technologies, Inc. +.Aq http://www.netsec.net . 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); +} diff --git a/usr.sbin/pppoe/pppoe.h b/usr.sbin/pppoe/pppoe.h new file mode 100644 index 00000000000..e8f8dacc3b0 --- /dev/null +++ b/usr.sbin/pppoe/pppoe.h @@ -0,0 +1,146 @@ +/* $OpenBSD: pppoe.h,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. + */ + +/* XXX */ +#ifndef ETHERTYPE_PPPOEDISC +#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#endif +#ifndef ETHERTYPE_PPPOE +#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#endif + +#define PPPOE_MAXSESSIONS 32 +#define PPPOE_BPF_BUFSIZ 65536 + +struct pppoe_header { + u_int8_t vertype; /* PPPoE version (low 4), type (high 4) */ + u_int8_t code; /* PPPoE code (packet type) */ + u_int16_t sessionid; /* PPPoE session id */ + u_int16_t len; /* PPPoE payload length */ +}; +#define PPPOE_MTU (ETHERMTU - sizeof(struct pppoe_header) - 2) + +#define PPPOE_VER_S 0 /* Version shift */ +#define PPPOE_VER_M 0x0f /* Version mask */ +#define PPPOE_TYPE_S 4 /* Type shift */ +#define PPPOE_TYPE_M 0xf0 /* Type mask */ + +#define PPPOE_VER(vt) (((vt) & PPPOE_VER_M) >> PPPOE_VER_S) +#define PPPOE_TYPE(vt) (((vt) & PPPOE_TYPE_M) >> PPPOE_TYPE_S) +#define PPPOE_VERTYPE(v,t) \ + ((((v) << PPPOE_VER_S) & PPPOE_VER_M) | \ + (((t) << PPPOE_TYPE_S) & PPPOE_TYPE_M)) + +#define PPPOE_CODE_SESSION 0x00 /* Session */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session-Confirm */ +#define PPPOE_CODE_PADT 0xa7 /* Active Discovery Terminate */ + +struct pppoe_tag { + u_int16_t type; /* Tag Type */ + u_int16_t len; /* Tag Length */ + u_int8_t *val; /* Tag Value */ +}; + +#define PPPOE_TAG_END_OF_LIST 0x0000 /* End Of List */ +#define PPPOE_TAG_SERVICE_NAME 0x0101 /* Service Name */ +#define PPPOE_TAG_AC_NAME 0x0102 /* Access Concentrator Name */ +#define PPPOE_TAG_HOST_UNIQ 0x0103 /* Host Uniq */ +#define PPPOE_TAG_AC_COOKIE 0x0104 /* Access Concentratr Cookie */ +#define PPPOE_TAG_VENDOR_SPEC 0x0105 /* Vendor Specific */ +#define PPPOE_TAG_RELAY_SESSION 0x0110 /* Relay Session Id */ +#define PPPOE_TAG_SERVICE_NAME_ERROR 0x0201 /* Service Name Error */ +#define PPPOE_TAG_AC_SYSTEM_ERROR 0x0202 /* Acc. Concentrator Error */ +#define PPPOE_TAG_GENERIC_ERROR 0x0203 /* Generic Error */ + +extern int option_verbose; +extern u_char etherbroadcastaddr[]; + +void server_mode __P((int, char *, char *, struct ether_addr *)); +int client_mode __P((int, char *, char *, struct ether_addr *)); + +struct tag_list { + LIST_HEAD(, tag_node) thelist; +}; + +struct tag_node { + LIST_ENTRY(tag_node) next; + u_int16_t type; + u_int16_t len; + u_int8_t *val; + int _ref; +}; + +void tag_init __P((struct tag_list *)); +void tag_show __P((struct tag_list *)); +void tag_destroy __P((struct tag_list *)); +struct tag_node *tag_lookup __P((struct tag_list *, u_int16_t, int)); +int tag_add __P((struct tag_list *, u_int16_t, u_int16_t, u_int8_t *)); +int tag_pkt __P((struct tag_list *, u_long, u_int8_t *)); +void tag_hton __P((struct tag_list *)); +void tag_ntoh __P((struct tag_list *)); + +struct pppoe_session { + LIST_ENTRY(pppoe_session) s_next; + struct ether_addr s_ea; /* remote ethernet mac */ + u_int16_t s_id; /* session id */ + int s_fd; /* ttyfd */ + int s_first; +}; + +struct pppoe_session_master { + LIST_HEAD(, pppoe_session) sm_sessions; /* session list */ + int sm_nsessions; /* # of sessions */ +}; + +extern struct pppoe_session_master session_master; + +void session_init __P((void)); +void session_destroy __P((struct pppoe_session *)); +struct pppoe_session *session_new __P((struct ether_addr *)); +struct pppoe_session *session_find_eaid __P((struct ether_addr *, u_int16_t)); +struct pppoe_session *session_find_fd __P((int)); + +int runppp __P((int, char *)); +int bpf_to_ppp __P((int, u_long, u_int8_t *)); +int ppp_to_bpf __P((int, int, struct ether_addr *, struct ether_addr *, + u_int16_t)); +int send_padt __P((int, struct ether_addr *, struct ether_addr *, u_int16_t)); +void recv_debug __P((int, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); +void debug_packet __P((u_int8_t *, int)); + +u_int32_t cookie_bake __P((void)); diff --git a/usr.sbin/pppoe/rfc2516.txt b/usr.sbin/pppoe/rfc2516.txt new file mode 100644 index 00000000000..5397c863dc3 --- /dev/null +++ b/usr.sbin/pppoe/rfc2516.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group L. Mamakos +Request for Comments: 2516 K. Lidl +Category: Informational J. Evarts + UUNET Technologies, Inc. + D. Carrel + D. Simone + RedBack Networks, Inc. + R. Wheeler + RouterWare, Inc. + February 1999 + + + A Method for Transmitting PPP Over Ethernet (PPPoE) + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (1999). All Rights Reserved. + +Abstract + + The Point-to-Point Protocol (PPP) [1] provides a standard method for + transporting multi-protocol datagrams over point-to-point links. + + This document describes how to build PPP sessions and encapsulate PPP + packets over Ethernet. + +Applicability + + This specification is intended to provide the facilities which are + defined for PPP, such as the Link Control Protocol, Network-layer + Control Protocols, authentication, and more. These capabilities + require a point-to-point relationship between the peers, and are not + designed for the multi-point relationships which are available in + Ethernet and other multi-access environments. + + This specification can be used by multiple hosts on a shared, + Ethernet to open PPP sessions to multiple destinations via one or + more bridging modems. It is intended to be used with broadband + remote access technologies that provide a bridged Ethernet topology, + when access providers wish to maintain the session abstraction + associated with PPP. + + + + +Mamakos, et. al. Informational [Page 1] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + This document describes the PPP Over Ethernet encapsulation that is + being deployed by RedBack Networks, RouterWare, UUNET and others. + +1. Introduction + + Modern access technologies are faced with several conflicting goals. + It is desirable to connect multiple hosts at a remote site through + the same customer premise access device. It is also a goal to + provide access control and billing functionality in a manner similar + to dial-up services using PPP. In many access technologies, the most + cost effective method to attach multiple hosts to the customer + premise access device, is via Ethernet. In addition, it is desirable + to keep the cost of this device as low as possible while requiring + little or no configuration. + + PPP over Ethernet (PPPoE) provides the ability to connect a network + of hosts over a simple bridging access device to a remote Access + Concentrator. With this model, each host utilizes it's own PPP stack + and the user is presented with a familiar user interface. Access + control, billing and type of service can be done on a per-user, + rather than a per-site, basis. + + To provide a point-to-point connection over Ethernet, each PPP + session must learn the Ethernet address of the remote peer, as well + as establish a unique session identifier. PPPoE includes a discovery + protocol that provides this. + +2. Conventions + + The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, + SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this + document, are to be interpreted as described in [2]. + +3. Protocol Overview + + PPPoE has two distinct stages. There is a Discovery stage and a PPP + Session stage. When a Host wishes to initiate a PPPoE session, it + must first perform Discovery to identify the Ethernet MAC address of + the peer and establish a PPPoE SESSION_ID. While PPP defines a + peer-to-peer relationship, Discovery is inherently a client-server + relationship. In the Discovery process, a Host (the client) + discovers an Access Concentrator (the server). Based on the network + topology, there may be more than one Access Concentrator that the + Host can communicate with. The Discovery stage allows the Host to + discover all Access Concentrators and then select one. When + Discovery completes successfully, both the Host and the selected + Access Concentrator have the information they will use to build their + point-to-point connection over Ethernet. + + + +Mamakos, et. al. Informational [Page 2] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + The Discovery stage remains stateless until a PPP session is + established. Once a PPP session is established, both the Host and + the Access Concentrator MUST allocate the resources for a PPP virtual + interface. + +4. Payloads + + The following packet formats are defined here. The payload contents + will be defined in the Discovery and PPP sections. + + An Ethernet frame is as follows: + + 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | DESTINATION_ADDR | + | (6 octets) | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SOURCE_ADDR | + | (6 octets) | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ETHER_TYPE (2 octets) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ~ ~ + ~ payload ~ + ~ ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | CHECKSUM | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The DESTINATION_ADDR field contains either a unicast Ethernet + destination address, or the Ethernet broadcast address (0xffffffff). + For Discovery packets, the value is either a unicast or broadcast + address as defined in the Discovery section. For PPP session + traffic, this field MUST contain the peer's unicast address as + determined from the Discovery stage. + + The SOURCE_ADDR field MUST contains the Ethernet MAC address of the + source device. + + The ETHER_TYPE is set to either 0x8863 (Discovery Stage) or 0x8864 + (PPP Session Stage). + + + + + + + +Mamakos, et. al. Informational [Page 3] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + The Ethernet payload for PPPoE is as follows: + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | VER | TYPE | CODE | SESSION_ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LENGTH | payload ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The VER field is four bits and MUST be set to 0x1 for this version of + the PPPoE specification. + + The TYPE field is four bits and MUST be set to 0x1 for this version + of the PPPoE specification. + + The CODE field is eight bits and is defined below for the Discovery + and PPP Session stages. + + The SESSION_ID field is sixteen bits. It is an unsigned value in + network byte order. It's value is defined below for Discovery + packets. The value is fixed for a given PPP session and, in fact, + defines a PPP session along with the Ethernet SOURCE_ADDR and + DESTINATION_ADDR. A value of 0xffff is reserved for future use and + MUST NOT be used + + The LENGTH field is sixteen bits. The value, in network byte order, + indicates the length of the PPPoE payload. It does not include the + length of the Ethernet or PPPoE headers. + +5. Discovery Stage + + There are four steps to the Discovery stage. When it completes, both + peers know the PPPoE SESSION_ID and the peer's Ethernet address, + which together define the PPPoE session uniquely. The steps consist + of the Host broadcasting an Initiation packet, one or more Access + Concentrators sending Offer packets, the Host sending a unicast + Session Request packet and the selected Access Concentrator sending a + Confirmation packet. When the Host receives the Confirmation packet, + it may proceed to the PPP Session Stage. When the Access + Concentrator sends the Confirmation packet, it may proceed to the PPP + Session Stage. + + All Discovery Ethernet frames have the ETHER_TYPE field set to the + value 0x8863. + + + + + + +Mamakos, et. al. Informational [Page 4] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type- + length-value) construct and is defined as follows: + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TAG_TYPE | TAG_LENGTH | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TAG_VALUE ... ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + TAG_TYPE is a sixteen bit field in network byte order. Appendix A + contains a list of all TAG_TYPEs and their TAG_VALUEs. + + TAG_LENGTH is a sixteen bit field. It is an unsigned number in + network byte order, indicating the length in octets of the TAG_VALUE. + + If a discovery packet is received with a TAG of unknown TAG_TYPE, the + TAG MUST be ignored unless otherwise specified in this document. + This provides for backwards compatibility if/when new TAGs are added. + If new mandatory TAGs are added, the version number will be + incremented. + + Some example Discovery packets are shown in Appendix B. + +5.1 The PPPoE Active Discovery Initiation (PADI) packet + + The Host sends the PADI packet with the DESTINATION_ADDR set to the + broadcast address. The CODE field is set to 0x09 and the SESSION_ID + MUST be set to 0x0000. + + The PADI packet MUST contain exactly one TAG of TAG_TYPE Service- + Name, indicating the service the Host is requesting, and any number + of other TAG types. An entire PADI packet (including the PPPoE + header) MUST NOT exceed 1484 octets so as to leave sufficient room + for a relay agent to add a Relay-Session-Id TAG. + +5.2 The PPPoE Active Discovery Offer (PADO) packet + + When the Access Concentrator receives a PADI that it can serve, it + replies by sending a PADO packet. The DESTINATION_ADDR is the + unicast address of the Host that sent the PADI. The CODE field is + set to 0x07 and the SESSION_ID MUST be set to 0x0000. + + + + + + + + +Mamakos, et. al. Informational [Page 5] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + The PADO packet MUST contain one AC-Name TAG containing the Access + Concentrator's name, a Service-Name TAG identical to the one in the + PADI, and any number of other Service-Name TAGs indicating other + services that the Access Concentrator offers. If the Access + Concentrator can not serve the PADI it MUST NOT respond with a PADO. + +5.3 The PPPoE Active Discovery Request (PADR) packet + + Since the PADI was broadcast, the Host may receive more than one + PADO. The Host looks through the PADO packets it receives and + chooses one. The choice can be based on the AC-Name or the Services + offered. The Host then sends one PADR packet to the Access + Concentrator that it has chosen. The DESTINATION_ADDR field is set + to the unicast Ethernet address of the Access Concentrator that sent + the PADO. The CODE field is set to 0x19 and the SESSION_ID MUST be + set to 0x0000. + + The PADR packet MUST contain exactly one TAG of TAG_TYPE Service- + Name, indicating the service the Host is requesting, and any number + of other TAG types. + +5.4 The PPPoE Active Discovery Session-confirmation (PADS) packet + + When the Access Concentrator receives a PADR packet, it prepares to + begin a PPP session. It generates a unique SESSION_ID for the PPPoE + session and replies to the Host with a PADS packet. The + DESTINATION_ADDR field is the unicast Ethernet address of the Host + that sent the PADR. The CODE field is set to 0x65 and the SESSION_ID + MUST be set to the unique value generated for this PPPoE session. + + The PADS packet contains exactly one TAG of TAG_TYPE Service-Name, + indicating the service under which Access Concentrator has accepted + the PPPoE session, and any number of other TAG types. + + If the Access Concentrator does not like the Service-Name in the + PADR, then it MUST reply with a PADS containing a TAG of TAG_TYPE + Service-Name-Error (and any number of other TAG types). In this case + the SESSION_ID MUST be set to 0x0000. + +5.5 The PPPoE Active Discovery Terminate (PADT) packet + + This packet may be sent anytime after a session is established to + indicate that a PPPoE session has been terminated. It may be sent by + either the Host or the Access Concentrator. The DESTINATION_ADDR + field is a unicast Ethernet address, the CODE field is set to 0xa7 + and the SESSION_ID MUST be set to indicate which session is to be + terminated. No TAGs are required. + + + + +Mamakos, et. al. Informational [Page 6] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + When a PADT is received, no further PPP traffic is allowed to be sent + using that session. Even normal PPP termination packets MUST NOT be + sent after sending or receiving a PADT. A PPP peer SHOULD use the + PPP protocol itself to bring down a PPPoE session, but the PADT MAY + be used when PPP can not be used. + +6. PPP Session Stage + + Once the PPPoE session begins, PPP data is sent as in any other PPP + encapsulation. All Ethernet packets are unicast. The ETHER_TYPE + field is set to 0x8864. The PPPoE CODE MUST be set to 0x00. The + SESSION_ID MUST NOT change for that PPPoE session and MUST be the + value assigned in the Discovery stage. The PPPoE payload contains a + PPP frame. The frame begins with the PPP Protocol-ID. + + An example packet is shown in Appendix B. + +7. LCP Considerations + + The Magic Number LCP configuration option is RECOMMENDED, and the + Protocol Field Compression (PFC) option is NOT RECOMMENDED. An + implementation MUST NOT request any of the following options, and + MUST reject a request for such an option: + + Field Check Sequence (FCS) Alternatives, + + Address-and-Control-Field-Compression (ACFC), + + Asynchronous-Control-Character-Map (ACCM) + + The Maximum-Receive-Unit (MRU) option MUST NOT be negotiated to a + larger size than 1492. Since Ethernet has a maximum payload size of + 1500 octets, the PPPoE header is 6 octets and the PPP Protocol ID is + 2 octets, the PPP MTU MUST NOT be greater than 1492. + + It is RECOMMENDED that the Access Concentrator ocassionally send + Echo-Request packets to the Host to determine the state of the + session. Otherwise, if the Host terminates a session without sending + a Terminate-Request packet, the Access Concentrator will not be able + to determine that the session has gone away. + + When LCP terminates, the Host and Access concentrator MUST stop using + that PPPoE session. If the Host wishes to start another PPP session, + it MUST return to the PPPoE Discovery stage. + + + + + + + +Mamakos, et. al. Informational [Page 7] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + +8. Other Considerations + + When a host does not receive a PADO packet within a specified amount + of time, it SHOULD resend it's PADI packet and double the waiting + period. This is repeated as many times as desired. If the Host is + waiting to receive a PADS packet, a similar timeout mechanism SHOULD + be used, with the Host re-sending the PADR. After a specified number + of retries, the Host SHOULD then resend a PADI packet. + + The ETHER_TYPEs used in this document (0x8863 and 0x8864) have been + assigned by the IEEE for use by PPP Over Ethernet (PPPoE). Use of + these values and the PPPoE VER (version) field uniquely identify this + protocol. + + UTF-8 [5] is used throughout this document instead of ASCII. UTF-8 + supports the entire ASCII character set while allowing for + international character sets as well. See [5] for more details. + +9. Security Considerations + + To help protect against Denial of Service (DOS) attacks, the Access + Concentrator can employ the AC-Cookie TAG. The Access Concentrator + SHOULD be able to uniquely regenerate the TAG_VALUE based on the PADR + SOURCE_ADDR. Using this, the Access Concentrator can ensure that the + PADI SOURCE_ADDR is indeed reachable and can then limit concurrent + sessions for that address. What algorithm to use is not defined and + left as an implementation detail. An example is HMAC [3] over the + Host MAC address using a key known only to the Access > Concentrator. + While the AC-Cookie is useful against some DOS attacks, it can not + protect against all DOS attacks and an Access Concentrator MAY employ + other means to protect resources. + + While the AC-Cookie is useful against some DOS attacks, it can not + protect against all DOS attacks and an Access Concentrator MAY employ + other means to protect resources. + + Many Access Concentrators will not wish to offer information + regarding what services they offer to an unauthenticated entity. In + that case the Access Concentrator should employ one of two policies. + It SHOULD never refuse a request based on the Service-Name TAG, and + always return the TAG_VALUE that was sent to it. Or it SHOULD only + accept requests with a Service-Name TAG with a zero TAG_LENGTH + (indicating any service). The former solution is RECOMMENDED. + +10. Acknowledgments + + This document is based on concepts discussed in several forums, + including the ADSL forum. + + + +Mamakos, et. al. Informational [Page 8] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + Copious amounts of text have been stolen from RFC 1661, RFC 1662 and + RFC 2364. + +11. References + + [1] Simpson, W., Editor, "The Point-to-Point Protocol (PPP)", STD 51, + RFC 1661, July 1994 + + [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + [3] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing + for Message Authentication", RFC 2104, February 1998. + + [4] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700, + October 1994. See also: http://www.iana.org/numbers.html + + [5] Yergeau, F., "UTF-8, a transformation format of ISO 10646", RFC + 2279, January 1998. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 9] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + +Appendix A + + TAG_TYPES and TAG_VALUES + + 0x0000 End-Of-List + + This TAG indicates that there are no further TAGs in the list. The + TAG_LENGTH of this TAG MUST always be zero. Use of this TAG is + not required, but remains for backwards compatibility. + + 0x0101 Service-Name + + This TAG indicates that a service name follows. The TAG_VALUE is + an UTF-8 string that is NOT NULL terminated. When the TAG_LENGTH + is zero this TAG is used to indicate that any service is + acceptable. Examples of the use of the Service-Name TAG are to + indicate an ISP name or a class or quality of service. + + 0x0102 AC-Name + + This TAG indicates that a string follows which uniquely identifies + this particular Access Concentrator unit from all others. It may + be a combination of trademark, model, and serial id information, + or simply an UTF-8 rendition of the MAC address of the box. It is + not NULL terminated. + + 0x0103 Host-Uniq + + This TAG is used by a Host to uniquely associate an Access + Concentrator response (PADO or PADS) to a particular Host request + (PADI or PADR). The TAG_VALUE is binary data of any value and + length that the Host chooses. It is not interpreted by the Access + Concentrator. The Host MAY include a Host-Uniq TAG in a PADI or + PADR. If the Access Concentrator receives this TAG, it MUST + include the TAG unmodified in the associated PADO or PADS + response. + + 0x0104 AC-Cookie + + This TAG is used by the Access Concentrator to aid in protecting + against denial of service attacks (see the Security Considerations + section for an explanation of how this works). The Access + Concentrator MAY include this TAG in a PADO packet. If a Host + receives this TAG, it MUST return the TAG unmodified in the + following PADR. The TAG_VALUE is binary data of any value and + length and is not interpreted by the Host. + + + + + +Mamakos, et. al. Informational [Page 10] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + 0x0105 Vendor-Specific + + This TAG is used to pass vendor proprietary information. The + first four octets of the TAG_VALUE contain the vendor id and the + remainder is unspecified. The high-order octet of the vendor id + is 0 and the low-order 3 octets are the SMI Network Management + Private Enterprise Code of the Vendor in network byte order, as + defined in the Assigned Numbers RFC [4]. + + Use of this TAG is NOT RECOMMENDED. To ensure inter-operability, + an implementation MAY silently ignore a Vendor-Specific TAG. + + 0x0110 Relay-Session-Id + + This TAG MAY be added to any discovery packet by an intermediate + agent that is relaying traffic. The TAG_VALUE is opaque to both + the Host and the Access Concentrator. If either the Host or + Access Concentrator receives this TAG they MUST include it + unmodified in any discovery packet they send as a response. All + PADI packets MUST guarantee sufficient room for the addition of a + Relay-Session-Id TAG with a TAG_VALUE length of 12 octets. + + A Relay-Session-Id TAG MUST NOT be added if the discovery packet + already contains one. In that case the intermediate agent SHOULD + use the existing Relay-Session-Id TAG. If it can not use the + existing TAG or there is insufficient room to add a Relay- + Session-Id TAG, then it SHOULD return a Generic-Error TAG to the + sender. + + 0x0201 Service-Name-Error + + This TAG (typically with a zero-length data section) indicates + that for one reason or another, the requested Service-Name request + could not be honored. + + If there is data, and the first octet of the data is nonzero, then + it MUST be a printable UTF-8 string which explains why the request + was denied. This string MAY NOT be NULL terminated. + + 0x0202 AC-System-Error + + This TAG indicates that the Access Concentrator experienced some + error in performing the Host request. (For example insufficient + resources to create a virtual circuit.) It MAY be included in + PADS packets. + + + + + + +Mamakos, et. al. Informational [Page 11] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + If there is data, and the first octet of the data is nonzero, then + it MUST be a printable UTF-8 string which explains the nature of + the error. This string MAY NOT be NULL terminated. + + 0x0203 Generic-Error + + This TAG indicates an error. It can be added to PADO, PADR or + PADS packets when an unrecoverable error occurs and no other error + TAG is appropriate. If there is data then it MUST be an UTF-8 + string which explains the nature of the error. This string MUST + NOT be NULL terminated. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 12] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + +Appendix B + + The following are some example packets: + + A PADI packet: + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0xffffffff | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0xffff | Host_mac_addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Host_mac_addr (cont) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x09 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SESSION_ID = 0x0000 | LENGTH = 0x0004 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 13] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + A PADO packet: + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Host_mac_addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Host_mac_addr (cont) | Access_Concentrator_mac_addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Access_Concentrator_mac_addr (cont) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ETHER_TYPE = 0x8863 | v = 1 | t = 1 | CODE = 0x07 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SESSION_ID = 0x0000 | LENGTH = 0x0020 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TAG_TYPE = 0x0101 | TAG_LENGTH = 0x0000 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | TAG_TYPE = 0x0102 | TAG_LENGTH = 0x0018 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x47 | 0x6f | 0x20 | 0x52 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x65 | 0x64 | 0x42 | 0x61 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x63 | 0x6b | 0x20 | 0x2d | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x20 | 0x65 | 0x73 | 0x68 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x73 | 0x68 | 0x65 | 0x73 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0x68 | 0x6f | 0x6f | 0x74 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 14] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + A PPP LCP packet: The PPP protocol value is shown (0xc021) but the + PPP payload is left to the reader. This is a packet from the Host to + the Access Concentrator. + + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Access_Concentrator_mac_addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Access_Concentrator_mac_addr(c)| Host_mac_addr | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Host_mac_addr (cont) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ETHER_TYPE = 0x8864 | v = 1 | t = 1 | CODE = 0x00 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SESSION_ID = 0x1234 | LENGTH = 0x???? | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | PPP PROTOCOL = 0xc021 | PPP payload ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Authors' Addresses + + Louis Mamakos + UUNET Technologies, Inc. + 3060 Williams Drive + Fairfax, VA 22031-4648 + United States of America + + EMail: louie@uu.net + + + Kurt Lidl + UUNET Technologies, Inc. + 3060 Williams Drive + Fairfax, VA 22031-4648 + United States of America + + EMail: lidl@uu.net + + + Jeff Evarts + UUNET Technologies, Inc. + 3060 Williams Drive + Fairfax, VA 22031-4648 + United States of America + + EMail: jde@uu.net + + + + +Mamakos, et. al. Informational [Page 15] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + + David Carrel + RedBack Networks, Inc. + 1389 Moffett Park Drive + Sunnyvale, CA 94089-1134 + United States of America + + EMail: carrel@RedBack.net + + + Dan Simone + RedBack Networks, Inc. + 1389 Moffett Park Drive + Sunnyvale, CA 94089-1134 + United States of America + + EMail:dan@RedBack.net + + + Ross Wheeler + RouterWare, Inc. + 3961 MacArthur Blvd., Suite 212 + Newport Beach, CA 92660 + United States of America + + EMail: ross@routerware.com + + + + + + + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 16] + +RFC 2516 Transmitting PPP Over Ethernet February 1999 + + +Full Copyright Statement + + Copyright (C) The Internet Society (1999). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + + + + + + + + + + + + + + + + + + + +Mamakos, et. al. Informational [Page 17] + diff --git a/usr.sbin/pppoe/server.c b/usr.sbin/pppoe/server.c new file mode 100644 index 00000000000..4ac0a85d419 --- /dev/null +++ b/usr.sbin/pppoe/server.c @@ -0,0 +1,478 @@ +/* $OpenBSD: server.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/param.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 <net/ppp_defs.h> +#include <errno.h> +#include <string.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <sysexits.h> +#include <stdlib.h> +#include <md5.h> + +#include "pppoe.h" + +#define COOKIE_LEN 4 /* bytes/cookie, must be <= 16 */ +#define COOKIE_MAX 16 + +static char ac_cookie_key[8]; + +static void getpackets __P((int, char *, struct ether_addr *)); + +static void recv_padi __P((int, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); +static void recv_padr __P((int, char *, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); +static void recv_padt __P((int, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); + +static void send_pado __P((int, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); +static void send_pads __P((int, char *, struct ether_addr *, + struct ether_header *, struct pppoe_header *, u_long, u_int8_t *)); +static void key_gen __P((void)); +static u_int8_t *key_make __P((u_int8_t *, int, u_int8_t *, int)); +static int key_cmp __P((u_int8_t *, int, u_int8_t *, int, u_int8_t *, int)); + +void +server_mode(bpffd, sysname, srvname, ea) + int bpffd; + char *sysname, *srvname; + struct ether_addr *ea; +{ + struct pppoe_session *ses; + fd_set rfds; + int n; + + key_gen(); + + while (1) { +reselect: + FD_ZERO(&rfds); + FD_SET(bpffd, &rfds); + n = bpffd; + ses = LIST_FIRST(&session_master.sm_sessions); + while (ses) { + if (ses->s_fd != -1) { + FD_SET(ses->s_fd, &rfds); + if (ses->s_fd > n) + n = ses->s_fd; + } + ses = LIST_NEXT(ses, s_next); + } + + n = select(n+1, &rfds, NULL, NULL, NULL); + if (n < 0) { + if (errno == EINTR) + goto reselect; + err(EX_IOERR, "select"); + return; + } + if (n == 0) + continue; + if (FD_ISSET(bpffd, &rfds)) { + n--; + getpackets(bpffd, sysname, ea); + } + if (n == 0) + continue; + + ses = LIST_FIRST(&session_master.sm_sessions); + while (ses) { + if (ses->s_fd != -1 && FD_ISSET(ses->s_fd, &rfds)) { + if (ppp_to_bpf(bpffd, ses->s_fd, ea, + &ses->s_ea, ses->s_id) < 0) { + send_padt(bpffd, ea, + &ses->s_ea, ses->s_id); + session_destroy(ses); + } + n--; + if (n == 0) + break; + } + ses = LIST_NEXT(ses, s_next); + } + } +} + +void +key_gen() +{ + u_int32_t r; + + r = arc4random(); + memcpy(ac_cookie_key, &r, sizeof(r)); + r = arc4random(); + memcpy(ac_cookie_key + sizeof(r), &r, sizeof(r)); +} + +u_int8_t * +key_make(in1, in1len, in2, in2len) + u_int8_t *in1, *in2; + int in1len, in2len; +{ + u_int8_t *p; + MD5_CTX ctx; + + p = (u_int8_t *)malloc(COOKIE_MAX); + if (p == NULL) + return (p); + + MD5Init(&ctx); + MD5Update(&ctx, in1, in1len); + MD5Update(&ctx, in2, in2len); + MD5Final(p, &ctx); + return (p); +} + +int +key_cmp(k, klen, in1, in1len, in2, in2len) + u_int8_t *k, *in1, *in2; + int klen, in1len, in2len; +{ + u_int8_t *p; + int r; + + if (klen != COOKIE_LEN) + return (-1); + + p = key_make(in1, in1len, in2, in2len); + if (p == NULL) + return (-1); + + r = memcmp(k, p, COOKIE_LEN); + free(p); + return (r); +} + +static void +getpackets(bpffd, sysname, ea) + int bpffd; + char *sysname; + struct ether_addr *ea; +{ + static u_int8_t *pktbuf; + u_int8_t *mpkt, *pkt, *epkt; + struct ether_header eh; + struct pppoe_header ph; + struct bpf_hdr *bh; + int rlen; + u_long len; + + if (pktbuf == NULL) { + pktbuf = (u_int8_t *)malloc(PPPOE_BPF_BUFSIZ); + if (pktbuf == NULL) + return; + } + + rlen = read(bpffd, pktbuf, PPPOE_BPF_BUFSIZ); + if (rlen < 0) + return; + + pkt = pktbuf; + epkt = pkt + rlen; + while (pkt < epkt) { + bh = (struct bpf_hdr *)pkt; + len = bh->bh_caplen; + mpkt = pkt + bh->bh_hdrlen; + + /* Pull out ethernet header */ + if (len < sizeof(struct ether_header)) + goto next; + bcopy(mpkt, &eh, sizeof(struct ether_header)); + eh.ether_type = ntohs(eh.ether_type); + len -= sizeof(struct ether_header); + mpkt += sizeof(struct ether_header); + + /* Pull out pppoe header */ + if (len < sizeof(struct pppoe_header)) + goto next; + bcopy(mpkt, &ph, sizeof(struct pppoe_header)); + mpkt += sizeof(struct pppoe_header); + len -= sizeof(struct pppoe_header); + ph.len = ntohs(ph.len); + ph.sessionid = ntohs(ph.sessionid); + + if (PPPOE_VER(ph.vertype) != 1 || + PPPOE_TYPE(ph.vertype) != 1) + goto next; + + if (len > ph.len) + len = ph.len; + + if (eh.ether_type == ETHERTYPE_PPPOEDISC) { + /* Discovery Stage */ + switch (ph.code) { + case PPPOE_CODE_PADI: + recv_padi(bpffd, ea, &eh, &ph, len, mpkt); + break; + case PPPOE_CODE_PADR: + recv_padr(bpffd, sysname, ea, &eh, &ph, + len, mpkt); + break; + case PPPOE_CODE_PADT: + recv_padt(bpffd, ea, &eh, &ph, len, mpkt); + break; + default: + recv_debug(bpffd, ea, &eh, &ph, len, mpkt); + } + } + else if (eh.ether_type == ETHERTYPE_PPPOE) { + /* Session Stage */ + struct pppoe_session *s; + + s = session_find_eaid( + (struct ether_addr *)&eh.ether_shost[0], + ph.sessionid); + if (s != NULL && bpf_to_ppp(s->s_fd, len, mpkt) <= 0) + session_destroy(s); + } +next: + pkt += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + } +} + +static void +recv_padi(bpffd, ea, eh, ph, pktlen, pktbuf) + int bpffd; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + struct tag_list tl; + + if (ph->sessionid != 0) + return; + if (bcmp(&eh->ether_dhost[0], etherbroadcastaddr, ETHER_ADDR_LEN)) + return; + + tag_init(&tl); + if (tag_pkt(&tl, pktlen, pktbuf) < 0) + goto out; + + if (tag_lookup(&tl, PPPOE_TAG_SERVICE_NAME, 1) != NULL) + goto out; + + send_pado(bpffd, ea, eh, ph, pktlen, pktbuf); + +out: + tag_destroy(&tl); +} + +static void +send_pado(bpffd, ea, eh, ph, pktlen, pktbuf) + int bpffd; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + struct pppoe_tag ktag, htag; + char hn[MAXHOSTNAMELEN]; + u_int8_t *k = NULL; + struct iovec v[7]; + int idx = 0; + + memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN); + memcpy(&eh->ether_shost[0], ea, ETHER_ADDR_LEN); + eh->ether_type = htons(eh->ether_type); + v[idx].iov_base = eh; v[idx].iov_len = sizeof(*eh); idx++; + + ph->code = PPPOE_CODE_PADO; + v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++; + + v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++; + + if (gethostname(hn, sizeof(hn)) < 0) + return; + htag.len = strlen(hn); + htag.type = htons(PPPOE_TAG_AC_NAME); + htag.val = hn; + v[idx].iov_base = &htag; + v[idx].iov_len = sizeof(htag.len) + sizeof(htag.type); + idx++; + v[idx].iov_base = hn; v[idx].iov_len = htag.len; idx++; + ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len; + htag.len = htons(htag.len); + + k = key_make(&eh->ether_dhost[0], ETHER_ADDR_LEN, ac_cookie_key, + sizeof(ac_cookie_key)); + if (k == NULL) + return; + ktag.type = htons(PPPOE_TAG_AC_COOKIE); + ktag.len = COOKIE_LEN; + ktag.val = k; + v[idx].iov_base = &ktag; + v[idx].iov_len = sizeof(ktag.len) + sizeof(ktag.type); + idx++; + v[idx].iov_base = k; v[idx].iov_len = COOKIE_LEN; idx++; + ph->len += sizeof(ktag.len) + sizeof(ktag.type) + COOKIE_LEN; + ktag.len = htons(COOKIE_LEN); + + ph->len = htons(ph->len); + + writev(bpffd, v, idx); + + if (k) + free(k); +} + +static void +recv_padr(bpffd, sysname, ea, eh, ph, pktlen, pktbuf) + int bpffd; + char *sysname; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + struct tag_list tl; + struct tag_node *n; + + if (ph->sessionid != 0) + return; + + tag_init(&tl); + if (tag_pkt(&tl, pktlen, pktbuf) < 0) + return; + + n = tag_lookup(&tl, PPPOE_TAG_AC_COOKIE, 0); + if (n == NULL) + return; + if (key_cmp(n->val, n->len, &eh->ether_shost[0], ETHER_ADDR_LEN, + ac_cookie_key, sizeof(ac_cookie_key))) + return; + + send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf); + + tag_destroy(&tl); +} + +static void +send_pads(bpffd, sysname, ea, eh, ph, pktlen, pktbuf) + int bpffd; + char *sysname; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + char hn[MAXHOSTNAMELEN]; + struct iovec v[16]; + struct pppoe_session *s; + struct pppoe_tag htag; + int idx = 0; + + s = session_new((struct ether_addr *)&eh->ether_shost[0]); + if (s == NULL) + return; + + memcpy(&eh->ether_dhost[0], &eh->ether_shost[0], ETHER_ADDR_LEN); + memcpy(&eh->ether_shost[0], ea, ETHER_ADDR_LEN); + eh->ether_type = htons(eh->ether_type); + v[idx].iov_base = eh; v[idx].iov_len = sizeof(*eh); idx++; + + ph->code = PPPOE_CODE_PADS; + ph->sessionid = htons(s->s_id); + if (gethostname(hn, sizeof(hn)) < 0) + return; + v[idx].iov_base = ph; v[idx].iov_len = sizeof(*ph); idx++; + + v[idx].iov_base = pktbuf; v[idx].iov_len = pktlen; idx++; + + htag.len = strlen(hn); + htag.type = htons(PPPOE_TAG_AC_NAME); + htag.val = hn; + v[idx].iov_base = &htag; + v[idx].iov_len = sizeof(htag.len) + sizeof(htag.type); + idx++; + v[idx].iov_base = hn; v[idx].iov_len = htag.len; idx++; + ph->len += sizeof(htag.len) + sizeof(htag.type) + htag.len; + htag.len = htons(htag.len); + + ph->len = htons(ph->len); + + writev(bpffd, v, idx); + + s->s_fd = runppp(bpffd, sysname); + if (s->s_fd < 0) { + /* XXX Send PADT with Generic-Error */ + s->s_fd = -1; + } +} + +static void +recv_padt(bpffd, ea, eh, ph, pktlen, pktbuf) + int bpffd; + struct ether_addr *ea; + struct ether_header *eh; + struct pppoe_header *ph; + u_long pktlen; + u_int8_t *pktbuf; +{ + struct pppoe_session *s; + struct tag_list tl; + + tag_init(&tl); + if (tag_pkt(&tl, pktlen, pktbuf) < 0) + goto out; + + s = session_find_eaid((struct ether_addr *)&eh->ether_shost[0], + ph->sessionid); + if (s == NULL) + goto out; + session_destroy(s); + +out: + tag_destroy(&tl); +} diff --git a/usr.sbin/pppoe/session.c b/usr.sbin/pppoe/session.c new file mode 100644 index 00000000000..294ec3d84f1 --- /dev/null +++ b/usr.sbin/pppoe/session.c @@ -0,0 +1,140 @@ +/* $OpenBSD: session.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 <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 "pppoe.h" + +struct pppoe_session_master session_master; + +void +session_init(void) +{ + LIST_INIT(&session_master.sm_sessions); + session_master.sm_nsessions = 0; +} + +void +session_destroy(struct pppoe_session *s) +{ + if (s->s_fd != -1) + close(s->s_fd); + LIST_REMOVE(s, s_next); + free(s); +} + +struct pppoe_session * +session_new(struct ether_addr *ea) +{ + struct pppoe_session *s; + u_int32_t x; + u_int16_t id = 1; + int tries = 1000; + + if (session_master.sm_nsessions == PPPOE_MAXSESSIONS) + return (NULL); + + while (tries--) { + x = cookie_bake(); + id = ((x >> 16) & 0xffff) ^ (x & 0xffff); + s = LIST_FIRST(&session_master.sm_sessions); + while (s) { + if (memcmp(ea, &s->s_ea, ETHER_ADDR_LEN) == 0 && + s->s_id == id) + break; + s = LIST_NEXT(s, s_next); + } + if (s == NULL) + break; + } + if (tries == 0) + return (NULL); + + s = (struct pppoe_session *)malloc(sizeof(*s)); + if (s == NULL) + return (NULL); + + s->s_id = id; + s->s_fd = -1; + s->s_first = 1; + memcpy(&s->s_ea, ea, ETHER_ADDR_LEN); + LIST_INSERT_HEAD(&session_master.sm_sessions, s, s_next); + + return (s); +} + +struct pppoe_session * +session_find_eaid(struct ether_addr *ea, u_int16_t id) +{ + struct pppoe_session *s; + + s = LIST_FIRST(&session_master.sm_sessions); + while (s) { + if (memcmp(ea, &s->s_ea, ETHER_ADDR_LEN) == 0 && s->s_id == id) + return (s); + s = LIST_NEXT(s, s_next); + } + return (NULL); +} + +struct pppoe_session * +session_find_fd(int fd) +{ + struct pppoe_session *s; + s = LIST_FIRST(&session_master.sm_sessions); + while (s) { + if (s->s_fd == fd) + return (s); + s = LIST_NEXT(s, s_next); + } + return (NULL); +} diff --git a/usr.sbin/pppoe/tag.c b/usr.sbin/pppoe/tag.c new file mode 100644 index 00000000000..c1968a7b93a --- /dev/null +++ b/usr.sbin/pppoe/tag.c @@ -0,0 +1,188 @@ +/* $OpenBSD: tag.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 <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 "pppoe.h" + +void +tag_init(struct tag_list *l) +{ + LIST_INIT(&l->thelist); +} + +void +tag_destroy(struct tag_list *l) +{ + struct tag_node *p; + + while (1) { + p = LIST_FIRST(&l->thelist); + if (p == NULL) + break; + p->_ref--; + if (p->_ref == 0 && p->val) + free(p->val); + LIST_REMOVE(p, next); + free(p); + } +} + +struct tag_node * +tag_lookup(struct tag_list *l, u_int16_t type, int idx) +{ + struct tag_node *p; + + p = LIST_FIRST(&l->thelist); + while (p != NULL) { + if (p->type == type) { + if (idx == 0) + break; + idx--; + } + p = LIST_NEXT(p, next); + } + return (p); +} + +int +tag_add(struct tag_list *l, u_int16_t type, u_int16_t len, u_int8_t *val) +{ + struct tag_node *p; + + p = (struct tag_node *)malloc(sizeof(*p)); + if (p == NULL) + return (-1); + if (len) { + p->val = (u_int8_t *)malloc(len); + if (p->val == NULL) { + free(p); + return (-1); + } + memcpy(p->val, val, len); + } + else + p->val = NULL; + p->type = type; + p->len = len; + p->_ref = 1; + LIST_INSERT_HEAD(&l->thelist, p, next); + return (0); +} + +int +tag_pkt(struct tag_list *l, u_long pktlen, u_int8_t *pkt) +{ + u_int16_t ttype, tlen; + + while (pktlen != 0) { + if (pktlen < sizeof(u_int16_t)) + break; + ttype = pkt[1] | (pkt[0] << 8); + pkt += sizeof(u_int16_t); + pktlen -= sizeof(u_int16_t); + + if (pktlen < sizeof(u_int16_t)) + break; + tlen = pkt[1] | (pkt[0] << 8); + pkt += sizeof(u_int16_t); + pktlen -= sizeof(u_int16_t); + + if (pktlen < tlen) + break; + + if (tag_add(l, ttype, tlen, pkt) < 0) + return (-1); + pkt += tlen; + pktlen -= tlen; + } + + if (pktlen != 0) + return (-1); + return (0); +} + +void +tag_show(struct tag_list *l) +{ + struct tag_node *p; + int i; + + for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) { + printf("\ttag type=0x%04x, length=%d", p->type, p->len); + for (i = 0; i < p->len; i++) + printf("%c%02x", (i == 0) ? ' ' : ':', p->val[i]); + printf("\n"); + } +} + +void +tag_hton(struct tag_list *l) +{ + struct tag_node *p; + + for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) { + p->len = htons(p->len); + p->type = htons(p->type); + } +} + +void +tag_ntoh(struct tag_list *l) +{ + struct tag_node *p; + + for (p = LIST_FIRST(&l->thelist); p; p = LIST_NEXT(p, next)) { + p->len = htons(p->len); + p->type = htons(p->type); + } +} |