From: Roy Marples Date: Wed, 8 Mar 2017 08:41:07 +0000 (+0000) Subject: Rename if_*raw functions to bpf_* so it's more descriptive and move X-Git-Tag: v7.0.0-beta1~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5fb1b714ea587c381ea45510feb2a190ca309f48;p=thirdparty%2Fdhcpcd.git Rename if_*raw functions to bpf_* so it's more descriptive and move them from if-bsd.c to bpf.c so they can be re-used on SunOS in the future. Linux is a special snowflake, so the BPF functions for opening, reading and attaching remain in if-linux.c. On Linux, open PF_PACKET as SOCK_RAW so we see the datalink frame header just as BPF elsewhere so we don't have to mess around with offsets. The BPF filters themselves have been improved to filter out more gunk such as ensuring BOOTP messages are in an IPv4 packet and from the BOOTPS port. ARP messages now check protocol family as well. More improvements to T101. --- diff --git a/arp.c b/arp.c index 716a7231..9c0e3ade 100644 --- a/arp.c +++ b/arp.c @@ -43,7 +43,7 @@ #define ELOOP_QUEUE 5 #include "config.h" #include "arp.h" -#include "if.h" +#include "bpf.h" #include "ipv4.h" #include "common.h" #include "dhcpcd.h" @@ -98,7 +98,7 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip) APPEND(&tip, sizeof(tip)); state = ARP_CSTATE(ifp); - return if_sendraw(ifp, state->fd, ETHERTYPE_ARP, arp_buffer, len); + return bpf_send(ifp, state->fd, ETHERTYPE_ARP, arp_buffer, len); eexit: errno = ENOBUFS; @@ -119,11 +119,12 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len) if (len < sizeof(ar)) return; memcpy(&ar, data, sizeof(ar)); + + /* These checks are enforced in the BPF filter. */ +#if 0 /* Families must match */ if (ar.ar_hrd != htons(ifp->family)) return; -#if 0 - /* These checks are enforced in the BPF filter. */ /* Protocol must be IP. */ if (ar.ar_pro != htons(ETHERTYPE_IP)) continue; @@ -131,9 +132,10 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len) if (ar.ar_op != htons(ARPOP_REPLY) && ar.ar_op != htons(ARPOP_REQUEST)) continue; -#endif + /* Protocol length must match in_addr_t */ if (ar.ar_pln != sizeof(arm.sip.s_addr)) return; +#endif /* Get pointers to the hardware addresses */ hw_s = data + sizeof(ar); @@ -190,7 +192,7 @@ arp_close(struct interface *ifp) if ((state = ARP_STATE(ifp)) != NULL && state->fd != -1) { eloop_event_delete(ifp->ctx->eloop, state->fd); - if_closeraw(ifp, state->fd); + bpf_close(state->fd); state->fd = -1; } } @@ -209,11 +211,11 @@ arp_read(void *arg) * so we have to process the entire buffer. */ state = ARP_CSTATE(ifp); flags = 0; - while (!(flags & RAW_EOF)) { - bytes = if_readraw(ifp, state->fd, buf, sizeof(buf), &flags); + while (!(flags & BPF_EOF)) { + bytes = bpf_read(ifp, state->fd, buf, sizeof(buf), &flags); if (bytes == -1) { logger(ifp->ctx, LOG_ERR, - "%s: arp if_readrawpacket: %m", ifp->name); + "%s: arp bpf_read: %m", ifp->name); arp_close(ifp); return; } @@ -228,7 +230,7 @@ arp_open(struct interface *ifp) state = ARP_STATE(ifp); if (state->fd == -1) { - state->fd = if_openraw(ifp, ETHERTYPE_ARP, bpf_arp); + state->fd = bpf_open(ifp, bpf_arp); if (state->fd == -1) { logger(ifp->ctx, LOG_ERR, "%s: %s: %m", __func__, ifp->name); diff --git a/bpf.c b/bpf.c index 4ab7c964..1de88739 100644 --- a/bpf.c +++ b/bpf.c @@ -1,5 +1,5 @@ /* - * dhcpcd: BPF arp and bootp functions + * dhcpcd: BPF arp and bootp filtering * Copyright (c) 2006-2017 Roy Marples * All rights reserved @@ -25,6 +25,8 @@ * SUCH DAMAGE. */ +#include + #include #include @@ -32,17 +34,22 @@ #include #ifdef __linux__ +/* Special BPF snowflake. */ #include +#define bpf_insn sock_filter #else #include #endif #include +#include #include +#include #include #include "common.h" #include "arp.h" +#include "bpf.h" #include "dhcp.h" #include "if.h" @@ -50,12 +57,8 @@ /* BPF helper macros */ #ifdef __linux__ -#define BPF_L2L 0 -#define BPF_L2I 0 -#define BPF_WHOLEPACKET 0x0fffffff /* work around buggy LPF filters */ +#define BPF_WHOLEPACKET 0x7fffffff /* work around buggy LPF filters */ #else -#define BPF_L2L ETHER_ADDR_LEN + ETHER_ADDR_LEN + 2 -#define BPF_L2I 3 #define BPF_WHOLEPACKET ~0U #endif @@ -74,6 +77,203 @@ (insn)->k = (uint32_t)(v); \ }; +size_t +bpf_frame_header_len(const struct interface *ifp) +{ + + switch(ifp->family) { + case ARPHRD_ETHER: + return sizeof(struct ether_header); + default: + return 0; + } +} + +#ifndef __linux__ +/* Linux is a special snowflake for opening, attaching and reading BPF. + * See if-linux.c for the Linux specific BPF functions. */ + +const char *bpf_name = "Berkley Packet Filter"; + +int +bpf_open(struct interface *ifp, int (*filter)(struct interface *, int)) +{ + struct ipv4_state *state; + int fd = -1; + struct ifreq ifr; + int ibuf_len = 0; + size_t buf_len; + struct bpf_version pv; +#ifdef BIOCIMMEDIATE + int flags; +#endif +#ifndef O_CLOEXEC + int fd_opts; +#endif + +#ifdef _PATH_BPF + fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK +#ifdef O_CLOEXEC + | O_CLOEXEC +#endif + ); +#else + char device[32]; + int n = 0; + + do { + snprintf(device, sizeof(device), "/dev/bpf%d", n++); + fd = open(device, O_RDWR | O_NONBLOCK +#ifdef O_CLOEXEC + | O_CLOEXEC +#endif + ); + } while (fd == -1 && errno == EBUSY); +#endif + + if (fd == -1) + return -1; + +#ifndef O_CLOEXEC + if ((fd_opts = fcntl(fd, F_GETFD)) == -1 || + fcntl(fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1) { + close(fd); + return -1; + } +#endif + + memset(&pv, 0, sizeof(pv)); + if (ioctl(fd, BIOCVERSION, &pv) == -1) + goto eexit; + if (pv.bv_major != BPF_MAJOR_VERSION || + pv.bv_minor < BPF_MINOR_VERSION) { + logger(ifp->ctx, LOG_ERR, "BPF version mismatch - recompile"); + goto eexit; + } + + if (filter(ifp, fd) != 0) + goto eexit; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, &ifr) == -1) + goto eexit; + + /* Get the required BPF buffer length from the kernel. */ + if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1) + goto eexit; + buf_len = (size_t)ibuf_len; + state = IPV4_STATE(ifp); + if (state->buffer_size != buf_len) { + void *nb; + + if ((nb = realloc(state->buffer, buf_len)) == NULL) + goto eexit; + state->buffer = nb; + state->buffer_size = buf_len; + state->buffer_len = state->buffer_pos = 0; + } + +#ifdef BIOCIMMEDIATE + flags = 1; + if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1) + goto eexit; +#endif + + return fd; + +eexit: + close(fd); + return -1; +} + +/* BPF requires that we read the entire buffer. + * So we pass the buffer in the API so we can loop on >1 packet. */ +ssize_t +bpf_read(struct interface *ifp, int fd, void *data, size_t len, int *flags) +{ + ssize_t fl = (ssize_t)bpf_frame_header_len(ifp); + ssize_t bytes; + struct ipv4_state *state = IPV4_STATE(ifp); + + struct bpf_hdr packet; + const char *payload; + + *flags = 0; + for (;;) { + if (state->buffer_len == 0) { + bytes = read(fd, state->buffer, state->buffer_size); + if (bytes == -1 || bytes == 0) + return bytes; + state->buffer_len = (size_t)bytes; + state->buffer_pos = 0; + } + bytes = -1; + memcpy(&packet, state->buffer + state->buffer_pos, + sizeof(packet)); + if (packet.bh_caplen != packet.bh_datalen) + goto next; /* Incomplete packet, drop. */ + if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen > + state->buffer_len) + goto next; /* Packet beyond buffer, drop. */ + payload = state->buffer + state->buffer_pos + + packet.bh_hdrlen + fl; + bytes = (ssize_t)packet.bh_caplen - fl; + if ((size_t)bytes > len) + bytes = (ssize_t)len; + memcpy(data, payload, (size_t)bytes); +next: + state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen + + packet.bh_caplen); + if (state->buffer_pos >= state->buffer_len) { + state->buffer_len = state->buffer_pos = 0; + *flags |= BPF_EOF; + } + if (bytes != -1) + return bytes; + } + + return bytes; +} + +int +bpf_attach(int fd, void *filter, unsigned int filter_len) +{ + struct bpf_program pf; + + /* Install the filter. */ + memset(&pf, 0, sizeof(pf)); + pf.bf_insns = filter; + pf.bf_len = filter_len; + return ioctl(fd, BIOCSETF, &pf); +} +#endif + +ssize_t +bpf_send(const struct interface *ifp, int fd, uint16_t protocol, + const void *data, size_t len) +{ + struct iovec iov[2]; + struct ether_header eh; + + switch(ifp->family) { + case ARPHRD_ETHER: + memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); + memcpy(&eh.ether_shost, ifp->hwaddr, sizeof(eh.ether_shost)); + eh.ether_type = htons(protocol); + iov[0].iov_base = &eh; + iov[0].iov_len = sizeof(eh); + break; + default: + iov[0].iov_base = NULL; + iov[0].iov_len = 0; + break; + } + iov[1].iov_base = UNCONST(data); + iov[1].iov_len = len; + return writev(fd, iov, 2); +} + static unsigned int bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off, bool equal, uint8_t *hwaddr, size_t hwaddr_len) @@ -120,23 +320,20 @@ bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off, if (hwaddr_len >= 4) { maclen = sizeof(mac32); memcpy(&mac32, hwaddr, maclen); - BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_ABS, - BPF_L2L + off); + BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off); bp++; BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(mac32), jt, jf); } else if (hwaddr_len >= 2) { maclen = sizeof(mac16); memcpy(&mac16, hwaddr, maclen); - BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_ABS, - BPF_L2L + off); + BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off); bp++; BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htons(mac16), jt, jf); } else { maclen = sizeof(*hwaddr); - BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_ABS, - BPF_L2L + off); + BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off); bp++; BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, *hwaddr, jt, jf); @@ -157,64 +354,81 @@ bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off, } #ifdef ARP -static const struct bpf_insn arp_bpf_filter [] = { + +static const struct bpf_insn bpf_arp_ether [] = { /* Ensure packet is at least correct size. */ BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, - BPF_L2L + sizeof(struct arphdr) - + (ETHER_ADDR_LEN * 2) - + (sizeof(in_addr_t) * 2), 1, 0), + BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), -#if BPF_L2L > 0 - /* Make sure this is an ARP packet. */ + + /* Check this is an ARP packet. */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_header, ether_type)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), -#endif + + /* Load frame header length into X */ + BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), + + /* Make sure the hardware family matches. */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), + BPF_STMT(BPF_RET + BPF_K, 0), + + /* Make sure the hardware length matches. */ + BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, + sizeof((struct ether_arp *)0)->arp_sha, 1, 0), + BPF_STMT(BPF_RET + BPF_K, 0), +}; +#define bpf_arp_ether_len __arraycount(bpf_arp_ether) + +static const struct bpf_insn bpf_arp_filter [] = { /* Make sure this is for IP. */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - BPF_L2L + offsetof(struct arphdr, ar_pro)), + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), /* Make sure this is an ARP REQUEST. */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - BPF_L2L + offsetof(struct arphdr, ar_op)), + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* or ARP REPLY. */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 1), BPF_STMT(BPF_RET + BPF_K, 0), - /* Make sure the hardware length matches. */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - BPF_L2L + offsetof(struct arphdr, ar_hln)), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHER_ADDR_LEN, 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), /* Make sure the protocol length matches. */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - BPF_L2L + offsetof(struct arphdr, ar_pln)), + BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), - /* Pass back the whole packet. */ - BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET), }; -#define arp_bpf_filter_len __arraycount(arp_bpf_filter) -#define arp_bpf_extra ((ARP_ADDRS_MAX * 2) * 2) + 2 +#define bpf_arp_filter_len __arraycount(bpf_arp_filter) +#define bpf_arp_extra ((ARP_ADDRS_MAX * 2) * 2) + 2 int -bpf_arp(struct interface *ifp, int s) +bpf_arp(struct interface *ifp, int fd) { size_t bpf_hw = ((((size_t)ifp->hwlen / 4) + 2) * 2) + 1; - struct bpf_insn bpf[arp_bpf_filter_len + bpf_hw + arp_bpf_extra]; + struct bpf_insn bpf[3 + bpf_arp_filter_len + bpf_hw + bpf_arp_extra]; struct bpf_insn *bp; struct iarp_state *state; - if (s == -1) + if (fd == -1) return 0; - memcpy(bpf, arp_bpf_filter, sizeof(arp_bpf_filter)); - bp = &bpf[arp_bpf_filter_len]; + bp = bpf; + /* Check frame header. */ + switch(ifp->family) { + case ARPHRD_ETHER: + memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether)); + bp += bpf_arp_ether_len; + break; + default: + errno = EINVAL; + return -1; + } + + /* Copy in the main filter. */ + memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter)); + bp += bpf_arp_filter_len; /* Ensure it's not from us. */ - bp--; bp += bpf_cmp_hwaddr(bp, bpf_hw, sizeof(struct arphdr), false, ifp->hwaddr, ifp->hwlen); @@ -224,8 +438,8 @@ bpf_arp(struct interface *ifp, int s) size_t naddrs; /* Match sender protocol address */ - BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_ABS, - BPF_L2L + sizeof(struct arphdr) + ifp->hwlen); + BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, + sizeof(struct arphdr) + ifp->hwlen); bp++; naddrs = 0; TAILQ_FOREACH(astate, &state->arp_states, next) { @@ -242,8 +456,9 @@ bpf_arp(struct interface *ifp, int s) } /* Match target protocol address */ - BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_ABS, - BPF_L2L + sizeof(struct arphdr) + ifp->hwlen); + BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, + (sizeof(struct arphdr) + + (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t))); bp++; naddrs = 0; TAILQ_FOREACH(astate, &state->arp_states, next) { @@ -264,113 +479,157 @@ bpf_arp(struct interface *ifp, int s) bp++; } - /* Replace ETHER_ADDR_LEN for Infiniband if needed. */ - if (ifp->hwlen != ETHER_ADDR_LEN) { - bpf[1].k += (uint32_t)(ifp->hwlen - ETHER_ADDR_LEN) * 2; - bpf[BPF_L2I + 11].k = ifp->hwlen; - } - - return if_bpf_attach(s, bpf, (unsigned int)(bp - bpf)); + return bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); } #endif -static const struct bpf_insn bootp_bpf_filter[] = { - /* Ensure packet is at least correct size. */ - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, - BPF_L2L + sizeof(struct ip) + sizeof(struct udphdr) - + offsetof(struct bootp, vend), 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), -#if BPF_L2L +static const struct bpf_insn bpf_bootp_ether[] = { /* Make sure this is an IP packet. */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_header, ether_type)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), -#endif + + /* Load frame header length into X. */ + BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), + /* Copy to M0. */ + BPF_STMT(BPF_STX, 0), +}; +#define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether) + +static const struct bpf_insn bpf_bootp_filter[] = { + /* Make sure it's an IPv4 packet. */ + BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x45, 1, 0), + BPF_STMT(BPF_RET + BPF_K, 0), + /* Make sure it's a UDP packet. */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, ip.ip_p)), + BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), + /* Make sure this isn't a fragment. */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, ip.ip_off)), + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)), BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1), BPF_STMT(BPF_RET + BPF_K, 0), - /* Make sure it's to the right port. */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, udp.uh_dport)), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTPC, 1, 0), + + /* Store IP location in M1. */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)), + BPF_STMT(BPF_ST, 1), + + /* Store IP length in M2. */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)), + BPF_STMT(BPF_ST, 2), + + /* Advance to the UDP header. */ + BPF_STMT(BPF_MISC + BPF_TXA, 0), + BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, sizeof(struct ip)), + BPF_STMT(BPF_MISC + BPF_TAX, 0), + + /* Store X in M3. */ + BPF_STMT(BPF_STX, 3), + + /* Make sure it's from and to the right port. */ + BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPS << 16) + BOOTPC, 1, 0), + BPF_STMT(BPF_RET + BPF_K, 0), + + /* Store UDP length in X. */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_ulen)), + BPF_STMT(BPF_MISC + BPF_TAX, 0), + /* Copy IP length in M2 to A. */ + BPF_STMT(BPF_LD + BPF_MEM, 2), + /* Ensure IP length - IP header size == UDP length. */ + BPF_STMT(BPF_ALU + BPF_SUB + BPF_K, sizeof(struct ip)), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), + + /* Advance to the BOOTP packet (UDP X is in M3). */ + BPF_STMT(BPF_LD + BPF_MEM, 3), + BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, sizeof(struct udphdr)), + BPF_STMT(BPF_MISC + BPF_TAX, 0), + /* Make sure it's BOOTREPLY. */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, bootp.op)), + BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct bootp, op)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), - /* Pass back the whole packet. */ - BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET), }; -#define bootp_bpf_filter_len __arraycount(bootp_bpf_filter) -#define bootp_bpf_extra 3 + ((BOOTP_CHADDR_LEN / 4) * 3) +#define BPF_BOOTP_FILTER_LEN __arraycount(bpf_bootp_filter) +#define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3) +#define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */ + +#define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + BPF_BOOTP_FILTER_LEN \ + + BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4 int bpf_bootp(struct interface *ifp, int fd) { const struct dhcp_state *state = D_CSTATE(ifp); - struct bpf_insn bpf[bootp_bpf_filter_len + bootp_bpf_extra]; + struct bpf_insn bpf[BPF_BOOTP_LEN]; struct bpf_insn *bp; - unsigned int bpf_len = bootp_bpf_extra; if (fd == -1) return 0; - memcpy(bpf, bootp_bpf_filter, sizeof(bootp_bpf_filter)); - bp = &bpf[bootp_bpf_filter_len]; + bp = bpf; + /* Check frame header. */ + switch(ifp->family) { + case ARPHRD_ETHER: + memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether)); + bp += BPF_BOOTP_ETHER_LEN; + break; + default: + errno = EINVAL; + return -1; + } - if (state->state != DHS_BOUND || - ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr)) - bp--; + /* Copy in the main filter. */ + memcpy(bp, bpf_bootp_filter, sizeof(bpf_bootp_filter)); + bp += BPF_BOOTP_FILTER_LEN; + + if (ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr)) + bp += bpf_cmp_hwaddr(bp, BPF_BOOTP_CHADDR_LEN, + offsetof(struct bootp, chaddr), + true, ifp->hwaddr, ifp->hwlen); /* Make sure the BOOTP packet is for us. */ if (state->state == DHS_BOUND) { /* If bound, we only expect FORCERENEW messages - * and they need to be unicast to us. */ - BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, ip.ip_dst)); + * and they need to be unicast to us. + * Move back to the IP header in M0 and check dst. */ + BPF_SET_STMT(bp, BPF_LDX + BPF_W + BPF_MEM, 0); + bp++; + BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, + offsetof(struct ip, ip_dst)); bp++; BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(state->lease.addr.s_addr), 1, 0); bp++; BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); bp++; - bpf_len -= 3; } else { /* As we're not bound, we need to check xid to ensure * it's a reply to our transaction. */ - BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_ABS, - BPF_L2L + offsetof(struct bootp_pkt, bootp.xid)); + BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, + offsetof(struct bootp, xid)); bp++; BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, state->xid, 1, 0); bp++; BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); bp++; - bpf_len -= 3; } - if (ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr)) - bp += bpf_cmp_hwaddr(bp, bpf_len, - offsetof(struct bootp_pkt, bootp.chaddr), - true, ifp->hwaddr, ifp->hwlen); - - if (state->state != DHS_BOUND || - ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr)) - { - BPF_SET_STMT(bp, BPF_RET + BPF_K, - BPF_WHOLEPACKET); - bp++; - } + /* All passed, return the packet + * (Frame length in M0, IP length in M2). */ + BPF_SET_STMT(bp, BPF_LD + BPF_MEM, 0); + bp++; + BPF_SET_STMT(bp, BPF_LDX + BPF_MEM, 2); + bp++; + BPF_SET_STMT(bp, BPF_ALU + BPF_ADD + BPF_X, 0); + bp++; + BPF_SET_STMT(bp, BPF_RET + BPF_A, 0); + bp++; - return if_bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); + return bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); } diff --git a/bpf.h b/bpf.h new file mode 100644 index 00000000..e53877e1 --- /dev/null +++ b/bpf.h @@ -0,0 +1,45 @@ +/* + * dhcpcd: BPF arp and bootp filtering + * Copyright (c) 2006-2017 Roy Marples + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#ifndef BPF_HEADER +#define BPF_HEADER + +#define BPF_EOF 1 << 0 +#define BPF_PARTIALCSUM 2 << 0 + +#include "dhcpcd.h" + +extern const char *bpf_name; +size_t bpf_frame_header_len(const struct interface *); +int bpf_open(struct interface *, int (*)(struct interface *, int)); +int bpf_attach(int, void *, unsigned int); +#define bpf_close close +ssize_t bpf_send(const struct interface *, int, uint16_t, const void *, size_t); +ssize_t bpf_read(struct interface *, int, void *, size_t, int *); +int bpf_arp(struct interface *, int); +int bpf_bootp(struct interface *, int); +#endif diff --git a/dhcp.c b/dhcp.c index 1ef8499b..39193b5b 100644 --- a/dhcp.c +++ b/dhcp.c @@ -54,6 +54,7 @@ #define ELOOP_QUEUE 2 #include "config.h" #include "arp.h" +#include "bpf.h" #include "common.h" #include "dhcp.h" #include "dhcpcd.h" @@ -1537,8 +1538,8 @@ dhcp_new_xid(struct interface *ifp) state->xid = arc4random(); /* As the XID changes, re-apply the filter. */ - if (state->raw_fd != -1) - bpf_bootp(ifp, state->raw_fd); + if (state->bpf_fd != -1) + bpf_bootp(ifp, state->bpf_fd); } void @@ -1549,10 +1550,10 @@ dhcp_close(struct interface *ifp) if (state == NULL) return; - if (state->raw_fd != -1) { - eloop_event_delete(ifp->ctx->eloop, state->raw_fd); - if_closeraw(ifp, state->raw_fd); - state->raw_fd = -1; + if (state->bpf_fd != -1) { + eloop_event_delete(ifp->ctx->eloop, state->bpf_fd); + bpf_close(state->bpf_fd); + state->bpf_fd = -1; } state->interval = 0; @@ -1776,7 +1777,7 @@ send_message(struct interface *ifp, uint8_t type, logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m"); r = 0; } else { - r = if_sendraw(ifp, state->raw_fd, + r = bpf_send(ifp, state->bpf_fd, ETHERTYPE_IP, (uint8_t *)udp, ulen); free(udp); } @@ -2289,7 +2290,7 @@ dhcp_bind(struct interface *ifp) } state->state = DHS_BOUND; /* Re-apply the filter because we need to accept any XID anymore. */ - bpf_bootp(ifp, state->raw_fd); + bpf_bootp(ifp, state->bpf_fd); if (!state->lease.frominfo && !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) if (write_lease(ifp, state->new, state->new_len) == -1) @@ -3288,8 +3289,8 @@ dhcp_readpacket(void *arg) * This means we have no kernel call to just get one packet, * so we have to process the entire buffer. */ flags = 0; - while (!(flags & RAW_EOF)) { - bytes = if_readraw(ifp, state->raw_fd, buf,sizeof(buf), &flags); + while (!(flags & BPF_EOF)) { + bytes = bpf_read(ifp, state->bpf_fd, buf,sizeof(buf), &flags); if (bytes == -1) { logger(ifp->ctx, LOG_ERR, "%s: dhcp if_readrawpacket: %m", ifp->name); @@ -3325,12 +3326,12 @@ dhcp_open(struct interface *ifp) struct dhcp_state *state; state = D_STATE(ifp); - if (state->raw_fd == -1) { - state->raw_fd = if_openraw(ifp, ETHERTYPE_IP, bpf_bootp); - if (state->raw_fd == -1) { + if (state->bpf_fd == -1) { + state->bpf_fd = bpf_open(ifp, bpf_bootp); + if (state->bpf_fd == -1) { if (errno == ENOENT) { logger(ifp->ctx, LOG_ERR, - "%s not found", if_pfname); + "%s not found", bpf_name); /* May as well disable IPv4 entirely at * this point as we really need it. */ ifp->options->options &= ~DHCPCD_IPV4; @@ -3340,7 +3341,7 @@ dhcp_open(struct interface *ifp) return -1; } eloop_event_add(ifp->ctx->eloop, - state->raw_fd, dhcp_readpacket, ifp); + state->bpf_fd, dhcp_readpacket, ifp); } return 0; } @@ -3353,7 +3354,7 @@ dhcp_dump(struct interface *ifp) ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); if (state == NULL) goto eexit; - state->raw_fd = -1; + state->bpf_fd = -1; dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), AF_INET, ifp); state->new_len = read_lease(ifp, &state->new); @@ -3423,7 +3424,7 @@ dhcp_init(struct interface *ifp) if (state == NULL) return -1; /* 0 is a valid fd, so init to -1 */ - state->raw_fd = -1; + state->bpf_fd = -1; #ifdef ARPING state->arping_index = -1; diff --git a/dhcp.h b/dhcp.h index 4af1a198..525e0147 100644 --- a/dhcp.h +++ b/dhcp.h @@ -213,7 +213,7 @@ struct dhcp_state { uint32_t xid; int socket; - int raw_fd; + int bpf_fd; struct ipv4_addr *addr; uint8_t added; diff --git a/if-bsd.c b/if-bsd.c index 58809cc6..97674083 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -609,183 +609,6 @@ if_initrt(struct dhcpcd_ctx *ctx, int af) #endif #ifdef INET -const char *if_pfname = "Berkley Packet Filter"; - -void -if_closeraw(__unused struct interface *ifp, int fd) -{ - - close(fd); -} - -int -if_openraw(struct interface *ifp, __unused uint16_t protocol, - int (*filter)(struct interface *, int)) -{ - struct ipv4_state *state; - int fd = -1; - struct ifreq ifr; - int ibuf_len = 0; - size_t buf_len; - struct bpf_version pv; -#ifdef BIOCIMMEDIATE - int flags; -#endif -#ifndef O_CLOEXEC - int fd_opts; -#endif - -#ifdef _PATH_BPF - fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK -#ifdef O_CLOEXEC - | O_CLOEXEC -#endif - ); -#else - char device[32]; - int n = 0; - - do { - snprintf(device, sizeof(device), "/dev/bpf%d", n++); - fd = open(device, O_RDWR | O_NONBLOCK -#ifdef O_CLOEXEC - | O_CLOEXEC -#endif - ); - } while (fd == -1 && errno == EBUSY); -#endif - - if (fd == -1) - return -1; - -#ifndef O_CLOEXEC - if ((fd_opts = fcntl(fd, F_GETFD)) == -1 || - fcntl(fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1) { - close(fd); - return -1; - } -#endif - state = IPV4_STATE(ifp); - memset(&pv, 0, sizeof(pv)); - if (ioctl(fd, BIOCVERSION, &pv) == -1) - goto eexit; - if (pv.bv_major != BPF_MAJOR_VERSION || - pv.bv_minor < BPF_MINOR_VERSION) { - logger(ifp->ctx, LOG_ERR, "BPF version mismatch - recompile"); - goto eexit; - } - - if (filter(ifp, fd) != 0) - goto eexit; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); - if (ioctl(fd, BIOCSETIF, &ifr) == -1) - goto eexit; - - /* Get the required BPF buffer length from the kernel. */ - if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1) - goto eexit; - buf_len = (size_t)ibuf_len; - if (state->buffer_size != buf_len) { - free(state->buffer); - state->buffer = malloc(buf_len); - if (state->buffer == NULL) - goto eexit; - state->buffer_size = buf_len; - state->buffer_len = state->buffer_pos = 0; - } - -#ifdef BIOCIMMEDIATE - flags = 1; - if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1) - goto eexit; -#endif - - return fd; - -eexit: - free(state->buffer); - state->buffer = NULL; - close(fd); - return -1; -} - -ssize_t -if_sendraw(__unused const struct interface *ifp, int fd, uint16_t protocol, - const void *data, size_t len) -{ - struct iovec iov[2]; - struct ether_header hw; - - memset(&hw, 0, ETHER_HDR_LEN); - memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); - hw.ether_type = htons(protocol); - iov[0].iov_base = &hw; - iov[0].iov_len = ETHER_HDR_LEN; - iov[1].iov_base = UNCONST(data); - iov[1].iov_len = len; - return writev(fd, iov, 2); -} - -/* BPF requires that we read the entire buffer. - * So we pass the buffer in the API so we can loop on >1 packet. */ -ssize_t -if_readraw(struct interface *ifp, int fd, void *data, size_t len, int *flags) -{ - struct bpf_hdr packet; - ssize_t bytes; - const char *payload; - struct ipv4_state *state; - - state = IPV4_STATE(ifp); - *flags = 0; - for (;;) { - if (state->buffer_len == 0) { - bytes = read(fd, state->buffer, state->buffer_size); - if (bytes == -1 || bytes == 0) - return bytes; - state->buffer_len = (size_t)bytes; - state->buffer_pos = 0; - } - bytes = -1; - memcpy(&packet, state->buffer + state->buffer_pos, - sizeof(packet)); - if (packet.bh_caplen != packet.bh_datalen) - goto next; /* Incomplete packet, drop. */ - if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen > - state->buffer_len) - goto next; /* Packet beyond buffer, drop. */ - payload = state->buffer + state->buffer_pos + - packet.bh_hdrlen + ETHER_HDR_LEN; - bytes = (ssize_t)packet.bh_caplen - ETHER_HDR_LEN; - if ((size_t)bytes > len) - bytes = (ssize_t)len; - memcpy(data, payload, (size_t)bytes); -next: - state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen + - packet.bh_caplen); - if (state->buffer_pos >= state->buffer_len) { - state->buffer_len = state->buffer_pos = 0; - *flags |= RAW_EOF; - } - if (bytes != -1) - return bytes; - } -} - -int -if_bpf_attach(int s, struct bpf_insn *filter, unsigned int filter_len) -{ - struct bpf_program pf; - - /* Install the filter. */ - memset(&pf, 0, sizeof(pf)); - pf.bf_insns = filter; - pf.bf_len = filter_len; - return ioctl(s, BIOCSETF, &pf); -} - int if_address(unsigned char cmd, const struct ipv4_addr *ia) { diff --git a/if-linux.c b/if-linux.c index 8cda7dd1..01ebf1d0 100644 --- a/if-linux.c +++ b/if-linux.c @@ -58,6 +58,7 @@ #include #include "config.h" +#include "bpf.h" #include "common.h" #include "dev.h" #include "dhcp.h" @@ -1286,19 +1287,15 @@ if_initrt(struct dhcpcd_ctx *ctx, int af) #ifdef INET -const char *if_pfname = "Packet Socket"; - -void -if_closeraw(__unused struct interface *ifp, int fd) -{ - - close(fd); -} +/* Linux is a special snowflake when it comes to BPF. */ +const char *bpf_name = "Packet Socket"; +#define BPF_BUFFER_LEN 1500 int -if_openraw(struct interface *ifp, uint16_t protocol, - int (*filter)(struct interface *, int)) +bpf_open(struct interface *ifp, int (*filter)(struct interface *, int)) { + struct ipv4_state *state = IPV4_STATE(ifp); +/* Linux is a special snowflake for opening BPF. */ int s; union sockunion { struct sockaddr sa; @@ -1310,10 +1307,21 @@ if_openraw(struct interface *ifp, uint16_t protocol, #endif #define SF SOCK_CLOEXEC | SOCK_NONBLOCK - if ((s = xsocket(PF_PACKET, SOCK_DGRAM | SF, htons(protocol))) == -1) + if ((s = xsocket(PF_PACKET, SOCK_RAW | SF, htons(ETH_P_ALL))) == -1) return -1; #undef SF + /* Allocate a suitably large buffer for a single packet. */ + if (state->buffer_size < ETH_DATA_LEN) { + void *nb; + + if ((nb = realloc(state->buffer, ETH_DATA_LEN)) == NULL) + goto eexit; + state->buffer = nb; + state->buffer_size = ETH_DATA_LEN; + state->buffer_len = state->buffer_pos = 0; + } + if (filter(ifp, s) != 0) goto eexit; @@ -1327,77 +1335,54 @@ if_openraw(struct interface *ifp, uint16_t protocol, memset(&su, 0, sizeof(su)); su.sll.sll_family = PF_PACKET; - su.sll.sll_protocol = htons(protocol); + su.sll.sll_protocol = htons(ETH_P_ALL); su.sll.sll_ifindex = (int)ifp->index; if (bind(s, &su.sa, sizeof(su.sll)) == -1) goto eexit; return s; eexit: + free(state->buffer); + state->buffer = NULL; close(s); return -1; } +/* BPF requires that we read the entire buffer. + * So we pass the buffer in the API so we can loop on >1 packet. */ ssize_t -if_sendraw(const struct interface *ifp, int fd, uint16_t protocol, - const void *data, size_t len) +bpf_read(struct interface *ifp, int s, void *data, size_t len, int *flags) { - union sockunion { - struct sockaddr sa; - struct sockaddr_ll sll; - struct sockaddr_storage ss; - } su; - - memset(&su, 0, sizeof(su)); - su.sll.sll_family = AF_PACKET; - su.sll.sll_protocol = htons(protocol); - su.sll.sll_ifindex = (int)ifp->index; - su.sll.sll_hatype = htons(ifp->family); - su.sll.sll_halen = (unsigned char)ifp->hwlen; - if (ifp->family == ARPHRD_INFINIBAND) { - /* sockaddr_ll is not big enough for IPoIB which is why - * sockaddr_storage is included in the union. - * Ugly as sin, but it works. */ - /* coverity[buffer_size] */ - /* coverity[overrun-buffer-arg] */ - memcpy(&su.sll.sll_addr, - &ipv4_bcast_addr, sizeof(ipv4_bcast_addr)); - } else - memset(&su.sll.sll_addr, 0xff, ifp->hwlen); - - return sendto(fd, data, len, 0, &su.sa, sizeof(su.sll)); -} + ssize_t bytes; + struct ipv4_state *state = IPV4_STATE(ifp); -ssize_t -if_readraw(__unused struct interface *ifp, int fd, - void *data, size_t len, int *flags) -{ struct iovec iov = { - .iov_base = data, - .iov_len = len, - }; - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, + .iov_base = state->buffer, + .iov_len = state->buffer_size }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; #ifdef PACKET_AUXDATA unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; struct cmsghdr *cmsg; struct tpacket_auxdata *aux; #endif - ssize_t bytes; - #ifdef PACKET_AUXDATA msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); #endif - bytes = recvmsg(fd, &msg, 0); + bytes = recvmsg(s, &msg, 0); if (bytes == -1) return -1; - *flags = RAW_EOF; /* We only ever read one packet. */ + *flags = BPF_EOF; /* We only ever read one packet. */ if (bytes) { + ssize_t fl = (ssize_t)bpf_frame_header_len(ifp); + + bytes -= fl; + if ((size_t)bytes > len) + bytes = (ssize_t)len; + memcpy(data, state->buffer + fl, (size_t)bytes); #ifdef PACKET_AUXDATA for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; @@ -1407,7 +1392,7 @@ if_readraw(__unused struct interface *ifp, int fd, cmsg->cmsg_type == PACKET_AUXDATA) { aux = (void *)CMSG_DATA(cmsg); if (aux->tp_status & TP_STATUS_CSUMNOTREADY) - *flags |= RAW_PARTIALCSUM; + *flags |= BPF_PARTIALCSUM; } } #endif @@ -1416,7 +1401,7 @@ if_readraw(__unused struct interface *ifp, int fd, } int -if_bpf_attach(int s, struct bpf_insn *filter, unsigned int filter_len) +bpf_attach(int s, void *filter, unsigned int filter_len) { struct sock_fprog pf; diff --git a/if.h b/if.h index 59259e83..f1303c90 100644 --- a/if.h +++ b/if.h @@ -171,20 +171,6 @@ int if_handlelink(struct dhcpcd_ctx *); #endif #ifdef INET -#ifdef __linux__ -#define bpf_insn sock_filter -#endif -struct bpf_insn; -extern const char *if_pfname; -int if_openraw(struct interface *, uint16_t, int (*)(struct interface *, int)); -ssize_t if_sendraw(const struct interface *, int, uint16_t, - const void *, size_t); -ssize_t if_readraw(struct interface *, int, void *, size_t, int *); -void if_closeraw(struct interface *, int); -int if_bpf_attach(int, struct bpf_insn *, unsigned int); -int bpf_arp(struct interface *, int); -int bpf_bootp(struct interface *, int); - int if_address(unsigned char, const struct ipv4_addr *); int if_addrflags(const struct interface *, const struct in_addr *, const char *); diff --git a/ipv4.c b/ipv4.c index 7c2bd4e2..5e5902dd 100644 --- a/ipv4.c +++ b/ipv4.c @@ -533,10 +533,8 @@ ipv4_getstate(struct interface *ifp) return NULL; } TAILQ_INIT(&state->addrs); -#ifdef BSD state->buffer_size = state->buffer_len = state->buffer_pos = 0; state->buffer = NULL; -#endif } return state; } @@ -937,9 +935,7 @@ ipv4_free(struct interface *ifp) TAILQ_REMOVE(&state->addrs, ia, next); free(ia); } -#ifdef BSD free(state->buffer); -#endif free(state); } } diff --git a/ipv4.h b/ipv4.h index a7dec35a..9d1858e9 100644 --- a/ipv4.h +++ b/ipv4.h @@ -95,11 +95,9 @@ TAILQ_HEAD(ipv4_addrhead, ipv4_addr); struct ipv4_state { struct ipv4_addrhead addrs; -#ifdef BSD /* Buffer for BPF */ size_t buffer_size, buffer_len, buffer_pos; char *buffer; -#endif }; #define IPV4_STATE(ifp) \