X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/ada95c9321eab3793d485ca026cda54afca9d541..71abe040fa49dfcb8ba3e08e5f21896b0c7cc6e8:/gencode.c diff --git a/gencode.c b/gencode.c index e66d7f54..09f72d43 100644 --- a/gencode.c +++ b/gencode.c @@ -21,33 +21,21 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif +#include #ifdef _WIN32 -#include -#else /* _WIN32 */ -#if HAVE_INTTYPES_H -#include -#elif HAVE_STDINT_H -#include -#endif -#ifdef HAVE_SYS_BITYPES_H -#include -#endif -#include -#include -#endif /* _WIN32 */ - -#ifndef _WIN32 - -#ifdef __NetBSD__ -#include -#endif + #include +#else + #include -#include -#include + #ifdef __NetBSD__ + #include + #endif + #include + #include #endif /* _WIN32 */ #include @@ -62,6 +50,8 @@ #include "pcap-int.h" +#include "extract.h" + #include "ethertype.h" #include "nlpid.h" #include "llc.h" @@ -94,17 +84,17 @@ #define offsetof(s, e) ((size_t)&((s *)0)->e) #endif -#ifdef INET6 #ifdef _WIN32 -#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + #ifdef INET6 + #if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) /* IPv6 address */ struct in6_addr { union { - u_int8_t u6_addr8[16]; - u_int16_t u6_addr16[8]; - u_int32_t u6_addr32[4]; + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; } in6_u; #define s6_addr in6_u.u6_addr8 #define s6_addr16 in6_u.u6_addr16 @@ -121,12 +111,12 @@ typedef unsigned short sa_family_t; struct sockaddr_in6 { __SOCKADDR_COMMON (sin6_); - u_int16_t sin6_port; /* Transport layer port # */ - u_int32_t sin6_flowinfo; /* IPv6 flow information */ + uint16_t sin6_port; /* Transport layer port # */ + uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; -#ifndef EAI_ADDRFAMILY + #ifndef EAI_ADDRFAMILY struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ @@ -137,12 +127,12 @@ struct addrinfo { struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; -#endif /* EAI_ADDRFAMILY */ -#endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */ + #endif /* EAI_ADDRFAMILY */ + #endif /* defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) */ + #endif /* INET6 */ #else /* _WIN32 */ -#include /* for "struct addrinfo" */ + #include /* for "struct addrinfo" */ #endif /* _WIN32 */ -#endif /* INET6 */ #include #include "nametoaddr.h" @@ -277,7 +267,6 @@ struct _compiler_state { /* XXX */ u_int pcap_fddipad; -#ifdef INET6 /* * As errors are handled by a longjmp, anything allocated must * be freed in the longjmp handler, so it must be reachable @@ -288,7 +277,13 @@ struct _compiler_state { * any addrinfo structure that would need to be freed. */ struct addrinfo *ai; -#endif + + /* + * Another thing that's allocated is the result of pcap_ether_aton(); + * it must be freed with free(). This variable points to any + * address that would need to be freed. + */ + u_char *e; /* * Various code constructs need to know the layout of the packet. @@ -357,6 +352,11 @@ struct _compiler_state { */ int is_geneve; + /* + * TRUE if we need variable length part of VLAN offset + */ + int is_vlan_vloffset; + /* * These are offsets for the ATM pseudo-header. */ @@ -426,25 +426,42 @@ struct _compiler_state { int cur_chunk; }; +void PCAP_NORETURN +bpf_parser_error(compiler_state_t *cstate, const char *msg) +{ + bpf_error(cstate, "can't parse filter expression: %s", msg); + /* NOTREACHED */ +} + +/* + * For use by the optimizer, which needs to do its *own* cleanup before + * delivering a longjmp-based exception. + */ void -bpf_syntax_error(compiler_state_t *cstate, const char *msg) +bpf_vset_error(compiler_state_t *cstate, const char *fmt, va_list ap) +{ + if (cstate->bpf_pcap != NULL) + (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap), + PCAP_ERRBUF_SIZE, fmt, ap); +} + +void PCAP_NORETURN +bpf_abort_compilation(compiler_state_t *cstate) { - bpf_error(cstate, "syntax error in filter expression: %s", msg); + longjmp(cstate->top_ctx, 1); /* NOTREACHED */ } /* VARARGS */ -void +void PCAP_NORETURN bpf_error(compiler_state_t *cstate, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - if (cstate->bpf_pcap != NULL) - (void)pcap_vsnprintf(pcap_geterr(cstate->bpf_pcap), - PCAP_ERRBUF_SIZE, fmt, ap); + bpf_vset_error(cstate, fmt, ap); va_end(ap); - longjmp(cstate->top_ctx, 1); + bpf_abort_compilation(cstate); /* NOTREACHED */ } @@ -524,7 +541,7 @@ static struct block *gen_host6(compiler_state_t *, struct in6_addr *, #endif #ifndef INET6 static struct block *gen_gateway(compiler_state_t *, const u_char *, - bpf_u_int32 **, int, int); + struct addrinfo *, int, int); #endif static struct block *gen_ipfrag(compiler_state_t *); static struct block *gen_portatom(compiler_state_t *, int, bpf_int32); @@ -583,7 +600,8 @@ newchunk(compiler_state_t *cstate, size_t n) cp = &cstate->chunks[cstate->cur_chunk]; if (n > cp->n_left) { - ++cp, k = ++cstate->cur_chunk; + ++cp; + k = ++cstate->cur_chunk; if (k >= NCHUNKS) bpf_error(cstate, "out of memory"); size = CHUNK0SIZE << k; @@ -618,7 +636,7 @@ sdup(compiler_state_t *cstate, const char *s) size_t n = strlen(s) + 1; char *cp = newchunk(cstate, n); - strlcpy(cp, s, n); + pcap_strlcpy(cp, s, n); return (cp); } @@ -654,7 +672,7 @@ gen_retblk(compiler_state_t *cstate, int v) return b; } -static inline void +static inline PCAP_NORETURN_DEF void syntax(compiler_state_t *cstate) { bpf_error(cstate, "syntax error in filter expression"); @@ -670,7 +688,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program, compiler_state_t cstate; const char * volatile xbuf = buf; yyscan_t scanner = NULL; - YY_BUFFER_STATE in_buffer = NULL; + volatile YY_BUFFER_STATE in_buffer = NULL; u_int len; int rc; @@ -689,11 +707,34 @@ pcap_compile(pcap_t *p, struct bpf_program *program, pcap_wsockinit(); done = 1; #endif + +#ifdef ENABLE_REMOTE + /* + * If the device on which we're capturing need to be notified + * that a new filter is being compiled, do so. + * + * This allows them to save a copy of it, in case, for example, + * they're implementing a form of remote packet capture, and + * want the remote machine to filter out the packets in which + * it's sending the packets it's captured. + * + * XXX - the fact that we happen to be compiling a filter + * doesn't necessarily mean we'll be installing it as the + * filter for this pcap_t; we might be running it from userland + * on captured packets to do packet classification. We really + * need a better way of handling this, but this is all that + * the WinPcap code did. + */ + if (p->save_current_filter_op != NULL) + (p->save_current_filter_op)(p, buf); +#endif + initchunks(&cstate); cstate.no_optimize = 0; #ifdef INET6 cstate.ai = NULL; #endif + cstate.e = NULL; cstate.ic.root = NULL; cstate.ic.cur_mark = 0; cstate.bpf_pcap = p; @@ -704,6 +745,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program, if (cstate.ai != NULL) freeaddrinfo(cstate.ai); #endif + if (cstate.e != NULL) + free(cstate.e); rc = -1; goto quit; } @@ -719,7 +762,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program, } if (pcap_lex_init(&scanner) != 0) - bpf_error(&cstate, "can't initialize scanner: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't initialize scanner"); in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner); /* @@ -803,8 +847,7 @@ pcap_freecode(struct bpf_program *program) * in each block is already resolved. */ static void -backpatch(list, target) - struct block *list, *target; +backpatch(struct block *list, struct block *target) { struct block *next; @@ -825,8 +868,7 @@ backpatch(list, target) * which of jt and jf is the link. */ static void -merge(b0, b1) - struct block *b0, *b1; +merge(struct block *b0, struct block *b1) { register struct block **p = &b0; @@ -888,8 +930,7 @@ finish_parse(compiler_state_t *cstate, struct block *p) } void -gen_and(b0, b1) - struct block *b0, *b1; +gen_and(struct block *b0, struct block *b1) { backpatch(b0, b1->head); b0->sense = !b0->sense; @@ -900,8 +941,7 @@ gen_and(b0, b1) } void -gen_or(b0, b1) - struct block *b0, *b1; +gen_or(struct block *b0, struct block *b1) { b0->sense = !b0->sense; backpatch(b0, b1->head); @@ -911,8 +951,7 @@ gen_or(b0, b1) } void -gen_not(b) - struct block *b; +gen_not(struct block *b) { b->sense = !b->sense; } @@ -965,13 +1004,22 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, { register struct block *b, *tmp; + /* + * XXX - the actual *instructions* do unsigned comparisons on + * most platforms, and the load instructions don't do sign + * extension, so gen_cmp() should really take an unsigned + * value argument. + * + * As the load instructons also don't do sign-extension, we + * fetch the values from the byte array as unsigned. We don't + * want to use the signed versions of the extract calls. + */ b = NULL; while (size >= 4) { register const u_char *p = &v[size - 4]; - bpf_int32 w = ((bpf_int32)p[0] << 24) | - ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; - tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, w); + tmp = gen_cmp(cstate, offrel, offset + size - 4, BPF_W, + (bpf_int32)EXTRACT_BE_U_4(p)); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -979,9 +1027,9 @@ gen_bcmp(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, } while (size >= 2) { register const u_char *p = &v[size - 2]; - bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; - tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, w); + tmp = gen_cmp(cstate, offrel, offset + size - 2, BPF_H, + (bpf_int32)EXTRACT_BE_U_2(p)); if (b != NULL) gen_and(b, tmp); b = tmp; @@ -1064,25 +1112,30 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) * Assume it's not raw ATM with a pseudo-header, for now. */ cstate->is_atm = 0; - cstate->off_vpi = -1; - cstate->off_vci = -1; - cstate->off_proto = -1; - cstate->off_payload = -1; + cstate->off_vpi = OFFSET_NOT_SET; + cstate->off_vci = OFFSET_NOT_SET; + cstate->off_proto = OFFSET_NOT_SET; + cstate->off_payload = OFFSET_NOT_SET; /* * And not Geneve. */ cstate->is_geneve = 0; + /* + * No variable length VLAN offset by default + */ + cstate->is_vlan_vloffset = 0; + /* * And assume we're not doing SS7. */ - cstate->off_li = -1; - cstate->off_li_hsl = -1; - cstate->off_sio = -1; - cstate->off_opc = -1; - cstate->off_dpc = -1; - cstate->off_sls = -1; + cstate->off_li = OFFSET_NOT_SET; + cstate->off_li_hsl = OFFSET_NOT_SET; + cstate->off_sio = OFFSET_NOT_SET; + cstate->off_opc = OFFSET_NOT_SET; + cstate->off_dpc = OFFSET_NOT_SET; + cstate->off_sls = OFFSET_NOT_SET; cstate->label_stack_depth = 0; cstate->vlan_stack_depth = 0; @@ -1092,7 +1145,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) case DLT_ARCNET: cstate->off_linktype.constant_part = 2; cstate->off_linkpl.constant_part = 6; - cstate->off_nl = 0; /* XXX in reality, variable! */ + cstate->off_nl = 0; /* XXX in reality, variable! */ cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; @@ -1315,13 +1368,20 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; - case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ + case DLT_LINUX_SLL: /* fake header for Linux cooked socket v1 */ cstate->off_linktype.constant_part = 14; cstate->off_linkpl.constant_part = 16; cstate->off_nl = 0; cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ break; + case DLT_LINUX_SLL2: /* fake header for Linux cooked socket v2 */ + cstate->off_linktype.constant_part = 0; + cstate->off_linkpl.constant_part = 20; + cstate->off_nl = 0; + cstate->off_nl_nosnap = 0; /* no 802.2 LLC */ + break; + case DLT_LTALK: /* * LocalTalk does have a 1-byte type field in the LLAP header, @@ -1406,7 +1466,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 4; cstate->off_nl = 0; - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_ATM1: @@ -1437,63 +1497,63 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_linktype.constant_part = 4; cstate->off_linkpl.constant_part = 6; cstate->off_nl = 0; - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_GGSN: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = 12; cstate->off_nl = 0; - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_ES: cstate->off_linktype.constant_part = 6; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ - cstate->off_nl = -1; /* not really a network layer but raw IP addresses */ - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl = OFFSET_NOT_SET; /* not really a network layer but raw IP addresses */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_MONITOR: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = 12; - cstate->off_nl = 0; /* raw IP/IP6 header */ - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl = 0; /* raw IP/IP6 header */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_BACNET_MS_TP: cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_SERVICES: cstate->off_linktype.constant_part = 12; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ - cstate->off_nl = -1; /* L3 proto location dep. on cookie type */ - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl = OFFSET_NOT_SET; /* L3 proto location dep. on cookie type */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_JUNIPER_VP: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_ST: cstate->off_linktype.constant_part = 18; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_ISM: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_JUNIPER_VS: @@ -1502,8 +1562,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) case DLT_JUNIPER_ATM_CEMIC: cstate->off_linktype.constant_part = 8; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_MTP2: @@ -1515,8 +1575,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_sls = 7; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_MTP2_WITH_PHDR: @@ -1528,8 +1588,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_sls = 11; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_ERF: @@ -1541,8 +1601,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->off_sls = 27; cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_PFSYNC: @@ -1558,15 +1618,15 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) */ cstate->off_linktype.constant_part = OFFSET_NOT_SET; /* variable, min 15, max 71 steps of 7 */ cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; /* variable, min 16, max 71 steps of 7 */ - cstate->off_nl_nosnap = -1; /* no 802.2 LLC */ + cstate->off_nl = OFFSET_NOT_SET; /* variable, min 16, max 71 steps of 7 */ + cstate->off_nl_nosnap = OFFSET_NOT_SET; /* no 802.2 LLC */ break; case DLT_IPNET: cstate->off_linktype.constant_part = 1; cstate->off_linkpl.constant_part = 24; /* ipnet header length */ cstate->off_nl = 0; - cstate->off_nl_nosnap = -1; + cstate->off_nl_nosnap = OFFSET_NOT_SET; break; case DLT_NETANALYZER: @@ -1594,8 +1654,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) cstate->linktype <= DLT_MATCHING_MAX) { cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; - cstate->off_nl = -1; - cstate->off_nl_nosnap = -1; + cstate->off_nl = OFFSET_NOT_SET; + cstate->off_nl_nosnap = OFFSET_NOT_SET; } else { bpf_error(cstate, "unknown data link type %d", cstate->linktype); } @@ -1720,7 +1780,7 @@ gen_load_a(compiler_state_t *cstate, enum e_offrel offrel, u_int offset, default: abort(); - return NULL; + /* NOTREACHED */ } return s; } @@ -1784,6 +1844,7 @@ gen_loadx_iphdrlen(compiler_state_t *cstate) return s; } + static struct block * gen_uncond(compiler_state_t *cstate, int rsense) { @@ -2800,6 +2861,28 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b) break; } + /* + * If there there is no initialization yet and we need variable + * length offsets for VLAN, initialize them to zero + */ + if (s == NULL && cstate->is_vlan_vloffset) { + struct slist *s2; + + if (cstate->off_linkpl.reg == -1) + cstate->off_linkpl.reg = alloc_reg(cstate); + if (cstate->off_linktype.reg == -1) + cstate->off_linktype.reg = alloc_reg(cstate); + + s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM); + s->s.k = 0; + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linkpl.reg; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = cstate->off_linktype.reg; + sappend(s, s2); + } + /* * If we have any offset-loading code, append all the * existing statements in the block to those statements, @@ -2886,8 +2969,7 @@ gen_abs_offset_varpart(compiler_state_t *cstate, bpf_abs_offset *off) * Map an Ethernet type to the equivalent PPP type. */ static int -ethertype_to_ppptype(proto) - int proto; +ethertype_to_ppptype(int proto) { switch (proto) { @@ -2974,7 +3056,7 @@ gen_prevlinkhdr_check(compiler_state_t *cstate) */ #define BSD_AFNUM_INET6_BSD 24 /* NetBSD, OpenBSD, BSD/OS, Npcap */ #define BSD_AFNUM_INET6_FREEBSD 28 /* FreeBSD */ -#define BSD_AFNUM_INET6_DARWIN 30 /* OS X, iOS, other Darwin-based OSes */ +#define BSD_AFNUM_INET6_DARWIN 30 /* macOS, iOS, other Darwin-based OSes */ /* * Generate code to match a particular packet type by matching the @@ -3530,14 +3612,14 @@ gen_snap(compiler_state_t *cstate, bpf_u_int32 orgcode, bpf_u_int32 ptype) { u_char snapblock[8]; - snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ - snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ - snapblock[2] = 0x03; /* control = UI */ - snapblock[3] = (orgcode >> 16); /* upper 8 bits of organization code */ - snapblock[4] = (orgcode >> 8); /* middle 8 bits of organization code */ - snapblock[5] = (orgcode >> 0); /* lower 8 bits of organization code */ - snapblock[6] = (ptype >> 8); /* upper 8 bits of protocol type */ - snapblock[7] = (ptype >> 0); /* lower 8 bits of protocol type */ + snapblock[0] = LLCSAP_SNAP; /* DSAP = SNAP */ + snapblock[1] = LLCSAP_SNAP; /* SSAP = SNAP */ + snapblock[2] = 0x03; /* control = UI */ + snapblock[3] = (u_char)(orgcode >> 16); /* upper 8 bits of organization code */ + snapblock[4] = (u_char)(orgcode >> 8); /* middle 8 bits of organization code */ + snapblock[5] = (u_char)(orgcode >> 0); /* lower 8 bits of organization code */ + snapblock[6] = (u_char)(ptype >> 8); /* upper 8 bits of protocol type */ + snapblock[7] = (u_char)(ptype >> 0); /* lower 8 bits of protocol type */ return gen_bcmp(cstate, OR_LLC, 0, 8, snapblock); } @@ -3823,13 +3905,37 @@ gen_hostop(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: b0 = gen_hostop(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + default: abort(); } @@ -3846,7 +3952,7 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, { struct block *b0, *b1; u_int offset; - u_int32_t *a, *m; + uint32_t *a, *m; switch (dir) { @@ -3864,19 +3970,43 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr, gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: b0 = gen_hostop6(cstate, addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop6(cstate, addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + default: abort(); } /* this order is important */ - a = (u_int32_t *)addr; - m = (u_int32_t *)mask; + a = (uint32_t *)addr; + m = (uint32_t *)mask; b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); gen_and(b0, b1); @@ -3916,19 +4046,19 @@ gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir) return b1; case Q_ADDR1: - bpf_error(cstate, "'addr1' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11 with 802.11 headers"); break; case Q_ADDR2: - bpf_error(cstate, "'addr2' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11 with 802.11 headers"); break; case Q_ADDR3: - bpf_error(cstate, "'addr3' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11 with 802.11 headers"); break; case Q_ADDR4: - bpf_error(cstate, "'addr4' is only supported on 802.11 with 802.11 headers"); + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11 with 802.11 headers"); break; case Q_RA: @@ -3972,19 +4102,19 @@ gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) return b1; case Q_ADDR1: - bpf_error(cstate, "'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); break; case Q_ADDR2: - bpf_error(cstate, "'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); break; case Q_ADDR3: - bpf_error(cstate, "'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); break; case Q_ADDR4: - bpf_error(cstate, "'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); break; case Q_RA: @@ -4028,19 +4158,19 @@ gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir) return b1; case Q_ADDR1: - bpf_error(cstate, "'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); break; case Q_ADDR2: - bpf_error(cstate, "'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); break; case Q_ADDR3: - bpf_error(cstate, "'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); break; case Q_ADDR4: - bpf_error(cstate, "'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); break; case Q_RA: @@ -4341,6 +4471,68 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) gen_and(b1, b0); return b0; + case Q_AND: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_and(b0, b1); + return b1; + + case Q_DEFAULT: + case Q_OR: + b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); + b1 = gen_wlanhostop(cstate, eaddr, Q_DST); + gen_or(b0, b1); + return b1; + + /* + * XXX - add BSSID keyword? + */ + case Q_ADDR1: + return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); + + case Q_ADDR2: + /* + * Not present in CTS or ACK control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b1); + b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, + IEEE80211_FC0_SUBTYPE_MASK); + gen_not(b2); + gen_and(b1, b2); + gen_or(b0, b2); + b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); + gen_and(b2, b1); + return b1; + + case Q_ADDR3: + /* + * Not present in control frames. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, + IEEE80211_FC0_TYPE_MASK); + gen_not(b0); + b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); + gen_and(b0, b1); + return b1; + + case Q_ADDR4: + /* + * Present only if the direction mask has both "From DS" + * and "To DS" set. Neither control frames nor management + * frames should have both of those set, so we don't + * check the frame type. + */ + b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, + IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); + b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); + gen_and(b0, b1); + return b1; + case Q_RA: /* * Not present in management frames; addr1 in other @@ -4411,68 +4603,6 @@ gen_wlanhostop(compiler_state_t *cstate, const u_char *eaddr, int dir) b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); gen_and(b2, b1); return b1; - - /* - * XXX - add BSSID keyword? - */ - case Q_ADDR1: - return (gen_bcmp(cstate, OR_LINKHDR, 4, 6, eaddr)); - - case Q_ADDR2: - /* - * Not present in CTS or ACK control frames. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, - IEEE80211_FC0_TYPE_MASK); - gen_not(b0); - b1 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_CTS, - IEEE80211_FC0_SUBTYPE_MASK); - gen_not(b1); - b2 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_SUBTYPE_ACK, - IEEE80211_FC0_SUBTYPE_MASK); - gen_not(b2); - gen_and(b1, b2); - gen_or(b0, b2); - b1 = gen_bcmp(cstate, OR_LINKHDR, 10, 6, eaddr); - gen_and(b2, b1); - return b1; - - case Q_ADDR3: - /* - * Not present in control frames. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 0, BPF_B, IEEE80211_FC0_TYPE_CTL, - IEEE80211_FC0_TYPE_MASK); - gen_not(b0); - b1 = gen_bcmp(cstate, OR_LINKHDR, 16, 6, eaddr); - gen_and(b0, b1); - return b1; - - case Q_ADDR4: - /* - * Present only if the direction mask has both "From DS" - * and "To DS" set. Neither control frames nor management - * frames should have both of those set, so we don't - * check the frame type. - */ - b0 = gen_mcmp(cstate, OR_LINKHDR, 1, BPF_B, - IEEE80211_FC1_DIR_DSTODS, IEEE80211_FC1_DIR_MASK); - b1 = gen_bcmp(cstate, OR_LINKHDR, 24, 6, eaddr); - gen_and(b0, b1); - return b1; - - case Q_AND: - b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); - b1 = gen_wlanhostop(cstate, eaddr, Q_DST); - gen_and(b0, b1); - return b1; - - case Q_DEFAULT: - case Q_OR: - b0 = gen_wlanhostop(cstate, eaddr, Q_SRC); - b1 = gen_wlanhostop(cstate, eaddr, Q_DST); - gen_or(b0, b1); - return b1; } abort(); /* NOTREACHED */ @@ -4509,19 +4639,19 @@ gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir) return b1; case Q_ADDR1: - bpf_error(cstate, "'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); break; case Q_ADDR2: - bpf_error(cstate, "'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); break; case Q_ADDR3: - bpf_error(cstate, "'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); break; case Q_ADDR4: - bpf_error(cstate, "'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); break; case Q_RA: @@ -4580,29 +4710,50 @@ gen_dnhostop(compiler_state_t *cstate, bpf_u_int32 addr, int dir) gen_and(b0, b1); return b1; - case Q_OR: case Q_DEFAULT: + case Q_OR: /* Inefficient because we do our Calvinball dance twice */ b0 = gen_dnhostop(cstate, addr, Q_SRC); b1 = gen_dnhostop(cstate, addr, Q_DST); gen_or(b0, b1); return b1; - case Q_ISO: - bpf_error(cstate, "ISO host filtering not implemented"); + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; - default: - abort(); - } - b0 = gen_linktype(cstate, ETHERTYPE_DN); - /* Check for pad = 1, long header case */ - tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, - (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); - b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, - BPF_H, (bpf_int32)ntohs((u_short)addr)); - gen_and(tmp, b1); - /* Check for pad = 0, long header case */ - tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for addresses other than 802.11 MAC addresses"); + break; + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for addresses other than 802.11 MAC addresses"); + break; + + default: + abort(); + } + b0 = gen_linktype(cstate, ETHERTYPE_DN); + /* Check for pad = 1, long header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_H, + (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); + b1 = gen_cmp(cstate, OR_LINKPL, 2 + 1 + offset_lh, + BPF_H, (bpf_int32)ntohs((u_short)addr)); + gen_and(tmp, b1); + /* Check for pad = 0, long header case */ + tmp = gen_mcmp(cstate, OR_LINKPL, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); b2 = gen_cmp(cstate, OR_LINKPL, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr)); gen_and(tmp, b2); gen_or(b2, b1); @@ -4637,7 +4788,7 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto) case Q_IP: /* match the bottom-of-stack bit */ - b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); + b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x40, 0xf0); gen_and(b0, b1); @@ -4645,7 +4796,7 @@ gen_mpls_linktype(compiler_state_t *cstate, int proto) case Q_IPV6: /* match the bottom-of-stack bit */ - b0 = gen_mcmp(cstate, OR_LINKPL, -2, BPF_B, 0x01, 0x01); + b0 = gen_mcmp(cstate, OR_LINKPL, (u_int)-2, BPF_B, 0x01, 0x01); /* match the IPv4 version number */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_B, 0x60, 0xf0); gen_and(b0, b1); @@ -4684,6 +4835,9 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, } return b0; + case Q_LINK: + bpf_error(cstate, "link-layer modifier applied to %s", typestr); + case Q_IP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_IP, 12, 16); @@ -4693,12 +4847,12 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_ARP: return gen_hostop(cstate, addr, mask, dir, ETHERTYPE_ARP, 14, 24); - case Q_TCP: - bpf_error(cstate, "'tcp' modifier applied to %s", typestr); - case Q_SCTP: bpf_error(cstate, "'sctp' modifier applied to %s", typestr); + case Q_TCP: + bpf_error(cstate, "'tcp' modifier applied to %s", typestr); + case Q_UDP: bpf_error(cstate, "'udp' modifier applied to %s", typestr); @@ -4711,36 +4865,24 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_IGRP: bpf_error(cstate, "'igrp' modifier applied to %s", typestr); - case Q_PIM: - bpf_error(cstate, "'pim' modifier applied to %s", typestr); - - case Q_VRRP: - bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); - - case Q_CARP: - bpf_error(cstate, "'carp' modifier applied to %s", typestr); - case Q_ATALK: - bpf_error(cstate, "ATALK host filtering not implemented"); - - case Q_AARP: - bpf_error(cstate, "AARP host filtering not implemented"); + bpf_error(cstate, "AppleTalk host filtering not implemented"); case Q_DECNET: return gen_dnhostop(cstate, addr, dir); - case Q_SCA: - bpf_error(cstate, "SCA host filtering not implemented"); - case Q_LAT: bpf_error(cstate, "LAT host filtering not implemented"); - case Q_MOPDL: - bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_SCA: + bpf_error(cstate, "SCA host filtering not implemented"); case Q_MOPRC: bpf_error(cstate, "MOPRC host filtering not implemented"); + case Q_MOPDL: + bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_IPV6: bpf_error(cstate, "'ip6' modifier applied to ip host"); @@ -4753,6 +4895,15 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_ESP: bpf_error(cstate, "'esp' modifier applied to %s", typestr); + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); + + case Q_AARP: + bpf_error(cstate, "AARP host filtering not implemented"); + case Q_ISO: bpf_error(cstate, "ISO host filtering not implemented"); @@ -4774,9 +4925,33 @@ gen_host(compiler_state_t *cstate, bpf_u_int32 addr, bpf_u_int32 mask, case Q_NETBEUI: bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to %s", typestr); + case Q_RADIO: bpf_error(cstate, "'radio' modifier applied to %s", typestr); + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to %s", typestr); + default: abort(); } @@ -4813,88 +4988,109 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr, bpf_error(cstate, "'arp' modifier applied to ip6 %s", typestr); case Q_SCTP: - bpf_error(cstate, "'sctp' modifier applied to %s", typestr); + bpf_error(cstate, "'sctp' modifier applied to ip6 %s", typestr); case Q_TCP: - bpf_error(cstate, "'tcp' modifier applied to %s", typestr); + bpf_error(cstate, "'tcp' modifier applied to ip6 %s", typestr); case Q_UDP: - bpf_error(cstate, "'udp' modifier applied to %s", typestr); + bpf_error(cstate, "'udp' modifier applied to ip6 %s", typestr); case Q_ICMP: - bpf_error(cstate, "'icmp' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp' modifier applied to ip6 %s", typestr); case Q_IGMP: - bpf_error(cstate, "'igmp' modifier applied to %s", typestr); + bpf_error(cstate, "'igmp' modifier applied to ip6 %s", typestr); case Q_IGRP: - bpf_error(cstate, "'igrp' modifier applied to %s", typestr); - - case Q_PIM: - bpf_error(cstate, "'pim' modifier applied to %s", typestr); - - case Q_VRRP: - bpf_error(cstate, "'vrrp' modifier applied to %s", typestr); - - case Q_CARP: - bpf_error(cstate, "'carp' modifier applied to %s", typestr); + bpf_error(cstate, "'igrp' modifier applied to ip6 %s", typestr); case Q_ATALK: - bpf_error(cstate, "ATALK host filtering not implemented"); - - case Q_AARP: - bpf_error(cstate, "AARP host filtering not implemented"); + bpf_error(cstate, "AppleTalk modifier applied to ip6 %s", typestr); case Q_DECNET: bpf_error(cstate, "'decnet' modifier applied to ip6 %s", typestr); - case Q_SCA: - bpf_error(cstate, "SCA host filtering not implemented"); - case Q_LAT: - bpf_error(cstate, "LAT host filtering not implemented"); + bpf_error(cstate, "'lat' modifier applied to ip6 %s", typestr); - case Q_MOPDL: - bpf_error(cstate, "MOPDL host filtering not implemented"); + case Q_SCA: + bpf_error(cstate, "'sca' modifier applied to ip6 %s", typestr); case Q_MOPRC: - bpf_error(cstate, "MOPRC host filtering not implemented"); + bpf_error(cstate, "'moprc' modifier applied to ip6 %s", typestr); + + case Q_MOPDL: + bpf_error(cstate, "'mopdl' modifier applied to ip6 %s", typestr); case Q_IPV6: return gen_hostop6(cstate, addr, mask, dir, ETHERTYPE_IPV6, 8, 24); case Q_ICMPV6: - bpf_error(cstate, "'icmp6' modifier applied to %s", typestr); + bpf_error(cstate, "'icmp6' modifier applied to ip6 %s", typestr); case Q_AH: - bpf_error(cstate, "'ah' modifier applied to %s", typestr); + bpf_error(cstate, "'ah' modifier applied to ip6 %s", typestr); case Q_ESP: - bpf_error(cstate, "'esp' modifier applied to %s", typestr); + bpf_error(cstate, "'esp' modifier applied to ip6 %s", typestr); + + case Q_PIM: + bpf_error(cstate, "'pim' modifier applied to ip6 %s", typestr); + + case Q_VRRP: + bpf_error(cstate, "'vrrp' modifier applied to ip6 %s", typestr); + + case Q_AARP: + bpf_error(cstate, "'aarp' modifier applied to ip6 %s", typestr); case Q_ISO: - bpf_error(cstate, "ISO host filtering not implemented"); + bpf_error(cstate, "'iso' modifier applied to ip6 %s", typestr); case Q_ESIS: - bpf_error(cstate, "'esis' modifier applied to %s", typestr); + bpf_error(cstate, "'esis' modifier applied to ip6 %s", typestr); case Q_ISIS: - bpf_error(cstate, "'isis' modifier applied to %s", typestr); + bpf_error(cstate, "'isis' modifier applied to ip6 %s", typestr); case Q_CLNP: - bpf_error(cstate, "'clnp' modifier applied to %s", typestr); + bpf_error(cstate, "'clnp' modifier applied to ip6 %s", typestr); case Q_STP: - bpf_error(cstate, "'stp' modifier applied to %s", typestr); + bpf_error(cstate, "'stp' modifier applied to ip6 %s", typestr); case Q_IPX: - bpf_error(cstate, "IPX host filtering not implemented"); + bpf_error(cstate, "'ipx' modifier applied to ip6 %s", typestr); case Q_NETBEUI: - bpf_error(cstate, "'netbeui' modifier applied to %s", typestr); + bpf_error(cstate, "'netbeui' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L1: + bpf_error(cstate, "'l1' modifier applied to ip6 %s", typestr); + + case Q_ISIS_L2: + bpf_error(cstate, "'l2' modifier applied to ip6 %s", typestr); + + case Q_ISIS_IIH: + bpf_error(cstate, "'iih' modifier applied to ip6 %s", typestr); + + case Q_ISIS_SNP: + bpf_error(cstate, "'snp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_CSNP: + bpf_error(cstate, "'csnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_PSNP: + bpf_error(cstate, "'psnp' modifier applied to ip6 %s", typestr); + + case Q_ISIS_LSP: + bpf_error(cstate, "'lsp' modifier applied to ip6 %s", typestr); case Q_RADIO: - bpf_error(cstate, "'radio' modifier applied to %s", typestr); + bpf_error(cstate, "'radio' modifier applied to ip6 %s", typestr); + + case Q_CARP: + bpf_error(cstate, "'carp' modifier applied to ip6 %s", typestr); default: abort(); @@ -4905,10 +5101,12 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr, #ifndef INET6 static struct block * -gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist, - int proto, int dir) +gen_gateway(compiler_state_t *cstate, const u_char *eaddr, + struct addrinfo *alist, int proto, int dir) { struct block *b0, *b1, *tmp; + struct addrinfo *ai; + struct sockaddr_in *sin; if (dir != 0) bpf_error(cstate, "direction applied to 'gateway'"); @@ -4956,12 +5154,48 @@ gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist, bpf_error(cstate, "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); } - b1 = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, Q_HOST); - while (*alist) { - tmp = gen_host(cstate, **alist++, 0xffffffff, proto, Q_OR, - Q_HOST); - gen_or(b1, tmp); - b1 = tmp; + b1 = NULL; + for (ai = alist; ai != NULL; ai = ai->ai_next) { + /* + * Does it have an address? + */ + if (ai->ai_addr != NULL) { + /* + * Yes. Is it an IPv4 address? + */ + if (ai->ai_addr->sa_family == AF_INET) { + /* + * Generate an entry for it. + */ + sin = (struct sockaddr_in *)ai->ai_addr; + tmp = gen_host(cstate, + ntohl(sin->sin_addr.s_addr), + 0xffffffff, proto, Q_OR, Q_HOST); + /* + * Is it the *first* IPv4 address? + */ + if (b1 == NULL) { + /* + * Yes, so start with it. + */ + b1 = tmp; + } else { + /* + * No, so OR it into the + * existing set of + * addresses. + */ + gen_or(b1, tmp); + b1 = tmp; + } + } + } + } + if (b1 == NULL) { + /* + * No IPv4 addresses found. + */ + return (NULL); } gen_not(b1); gen_and(b0, b1); @@ -5268,17 +5502,41 @@ gen_portop(compiler_state_t *cstate, int port, int proto, int dir) b1 = gen_portatom(cstate, 2, (bpf_int32)port); break; - case Q_OR: - case Q_DEFAULT: + case Q_AND: tmp = gen_portatom(cstate, 0, (bpf_int32)port); b1 = gen_portatom(cstate, 2, (bpf_int32)port); - gen_or(tmp, b1); + gen_and(tmp, b1); break; - case Q_AND: + case Q_DEFAULT: + case Q_OR: tmp = gen_portatom(cstate, 0, (bpf_int32)port); b1 = gen_portatom(cstate, 2, (bpf_int32)port); - gen_and(tmp, b1); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for ports"); + break; + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for ports"); + break; + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for ports"); + break; + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for ports"); + break; + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for ports"); + break; + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for ports"); break; default: @@ -5353,17 +5611,17 @@ gen_portop6(compiler_state_t *cstate, int port, int proto, int dir) b1 = gen_portatom6(cstate, 2, (bpf_int32)port); break; - case Q_OR: - case Q_DEFAULT: + case Q_AND: tmp = gen_portatom6(cstate, 0, (bpf_int32)port); b1 = gen_portatom6(cstate, 2, (bpf_int32)port); - gen_or(tmp, b1); + gen_and(tmp, b1); break; - case Q_AND: + case Q_DEFAULT: + case Q_OR: tmp = gen_portatom6(cstate, 0, (bpf_int32)port); b1 = gen_portatom6(cstate, 2, (bpf_int32)port); - gen_and(tmp, b1); + gen_or(tmp, b1); break; default: @@ -5450,17 +5708,41 @@ gen_portrangeop(compiler_state_t *cstate, int port1, int port2, int proto, b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; - case Q_OR: - case Q_DEFAULT: + case Q_AND: tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_or(tmp, b1); + gen_and(tmp, b1); break; - case Q_AND: + case Q_DEFAULT: + case Q_OR: tmp = gen_portrangeatom(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_and(tmp, b1); + gen_or(tmp, b1); + break; + + case Q_ADDR1: + bpf_error(cstate, "'addr1' and 'address1' are not valid qualifiers for port ranges"); + break; + + case Q_ADDR2: + bpf_error(cstate, "'addr2' and 'address2' are not valid qualifiers for port ranges"); + break; + + case Q_ADDR3: + bpf_error(cstate, "'addr3' and 'address3' are not valid qualifiers for port ranges"); + break; + + case Q_ADDR4: + bpf_error(cstate, "'addr4' and 'address4' are not valid qualifiers for port ranges"); + break; + + case Q_RA: + bpf_error(cstate, "'ra' is not a valid qualifier for port ranges"); + break; + + case Q_TA: + bpf_error(cstate, "'ta' is not a valid qualifier for port ranges"); break; default: @@ -5546,17 +5828,17 @@ gen_portrangeop6(compiler_state_t *cstate, int port1, int port2, int proto, b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); break; - case Q_OR: - case Q_DEFAULT: + case Q_AND: tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_or(tmp, b1); + gen_and(tmp, b1); break; - case Q_AND: + case Q_DEFAULT: + case Q_OR: tmp = gen_portrangeatom6(cstate, 0, (bpf_int32)port1, (bpf_int32)port2); b1 = gen_portrangeatom6(cstate, 2, (bpf_int32)port1, (bpf_int32)port2); - gen_and(tmp, b1); + gen_or(tmp, b1); break; default: @@ -5643,9 +5925,7 @@ lookup_proto(compiler_state_t *cstate, const char *name, int proto) #if 0 struct stmt * -gen_joinsp(s, n) - struct stmt **s; - int n; +gen_joinsp(struct stmt **s, int n) { return NULL; } @@ -5695,7 +5975,7 @@ gen_protochain(compiler_state_t *cstate, int v, int proto, int dir) if (cstate->off_linkpl.is_variable) bpf_error(cstate, "'protochain' not supported with variable length headers"); - cstate->no_optimize = 1; /*this code is not compatible with optimzer yet */ + cstate->no_optimize = 1; /* this code is not compatible with optimizer yet */ /* * s[0] is a dummy entry to protect other BPF insn from damage @@ -6053,13 +6333,13 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) */ b0 = gen_linktype(cstate, LLCSAP_ISONS<<8 | LLCSAP_ISONS); /* OSI in C-HDLC is stuffed with a fudge byte */ - b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (long)v); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 1, BPF_B, (bpf_int32)v); gen_and(b0, b1); return b1; default: b0 = gen_linktype(cstate, LLCSAP_ISONS); - b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (long)v); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 0, BPF_B, (bpf_int32)v); gen_and(b0, b1); return b1; } @@ -6070,7 +6350,7 @@ gen_proto(compiler_state_t *cstate, int v, int proto, int dir) * 4 is the offset of the PDU type relative to the IS-IS * header. */ - b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (long)v); + b1 = gen_cmp(cstate, OR_LINKPL_NOSNAP, 4, BPF_B, (bpf_int32)v); gen_and(b0, b1); return b1; @@ -6199,13 +6479,11 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) int tproto; u_char *eaddr; bpf_u_int32 mask, addr; -#ifndef INET6 - bpf_u_int32 **alist; -#else - int tproto6; + struct addrinfo *res, *res0; struct sockaddr_in *sin4; +#ifdef INET6 + int tproto6; struct sockaddr_in6 *sin6; - struct addrinfo *res, *res0; struct in6_addr mask128; #endif /*INET6*/ struct block *b, *tmp; @@ -6304,46 +6582,39 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) */ return (gen_host(cstate, dn_addr, 0, proto, dir, q.addr)); } else { -#ifndef INET6 - alist = pcap_nametoaddr(name); - if (alist == NULL || *alist == NULL) - bpf_error(cstate, "unknown host '%s'", name); - tproto = proto; - if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && - tproto == Q_DEFAULT) - tproto = Q_IP; - b = gen_host(cstate, **alist++, 0xffffffff, tproto, dir, q.addr); - while (*alist) { - tmp = gen_host(cstate, **alist++, 0xffffffff, - tproto, dir, q.addr); - gen_or(b, tmp); - b = tmp; - } - return b; -#else +#ifdef INET6 memset(&mask128, 0xff, sizeof(mask128)); +#endif res0 = res = pcap_nametoaddrinfo(name); if (res == NULL) bpf_error(cstate, "unknown host '%s'", name); cstate->ai = res; b = tmp = NULL; - tproto = tproto6 = proto; + tproto = proto; +#ifdef INET6 + tproto6 = proto; +#endif if (cstate->off_linktype.constant_part == OFFSET_NOT_SET && tproto == Q_DEFAULT) { tproto = Q_IP; +#ifdef INET6 tproto6 = Q_IPV6; +#endif } for (res = res0; res; res = res->ai_next) { switch (res->ai_family) { case AF_INET: +#ifdef INET6 if (tproto == Q_IPV6) continue; +#endif sin4 = (struct sockaddr_in *) res->ai_addr; tmp = gen_host(cstate, ntohl(sin4->sin_addr.s_addr), 0xffffffff, tproto, dir, q.addr); break; +#ifdef INET6 case AF_INET6: if (tproto6 == Q_IP) continue; @@ -6353,6 +6624,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) tmp = gen_host6(cstate, &sin6->sin6_addr, &mask128, tproto6, dir, q.addr); break; +#endif default: continue; } @@ -6369,7 +6641,6 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) : " for specified address family"); } return b; -#endif /*INET6*/ } case Q_PORT: @@ -6467,11 +6738,15 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q) if (eaddr == NULL) bpf_error(cstate, "unknown ether host: %s", name); - alist = pcap_nametoaddr(name); - if (alist == NULL || *alist == NULL) + res = pcap_nametoaddrinfo(name); + cstate->ai = res; + if (res == NULL) + bpf_error(cstate, "unknown host '%s'", name); + b = gen_gateway(cstate, eaddr, res, proto, dir); + cstate->ai = NULL; + freeaddrinfo(res); + if (b == NULL) bpf_error(cstate, "unknown host '%s'", name); - b = gen_gateway(cstate, eaddr, alist, proto, dir); - free(eaddr); return b; #else bpf_error(cstate, "'gateway' not supported in this configuration"); @@ -6544,7 +6819,6 @@ gen_mcode(compiler_state_t *cstate, const char *s1, const char *s2, /* NOTREACHED */ } /* NOTREACHED */ - return NULL; } struct block * @@ -6663,7 +6937,7 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, struct in6_addr *addr; struct in6_addr mask; struct block *b; - u_int32_t *a, *m; + uint32_t *a, *m; if (s2) bpf_error(cstate, "no mask %s supported", s2); @@ -6685,8 +6959,8 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, (0xff << (8 - masklen % 8)) & 0xff; } - a = (u_int32_t *)addr; - m = (u_int32_t *)&mask; + a = (uint32_t *)addr; + m = (uint32_t *)&mask; if ((a[0] & ~m[0]) || (a[1] & ~m[1]) || (a[2] & ~m[2]) || (a[3] & ~m[3])) { bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen); @@ -6710,50 +6984,60 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2, bpf_error(cstate, "invalid qualifier against IPv6 address"); /* NOTREACHED */ } - return NULL; } #endif /*INET6*/ struct block * -gen_ecode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) +gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) { struct block *b, *tmp; if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); switch (cstate->linktype) { case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: tmp = gen_prevlinkhdr_check(cstate); - b = gen_ehostop(cstate, eaddr, (int)q.dir); + b = gen_ehostop(cstate, cstate->e, (int)q.dir); if (tmp != NULL) gen_and(tmp, b); - return b; + break; case DLT_FDDI: - return gen_fhostop(cstate, eaddr, (int)q.dir); + b = gen_fhostop(cstate, cstate->e, (int)q.dir); + break; case DLT_IEEE802: - return gen_thostop(cstate, eaddr, (int)q.dir); + b = gen_thostop(cstate, cstate->e, (int)q.dir); + break; case DLT_IEEE802_11: case DLT_PRISM_HEADER: case DLT_IEEE802_11_RADIO_AVS: case DLT_IEEE802_11_RADIO: case DLT_PPI: - return gen_wlanhostop(cstate, eaddr, (int)q.dir); + b = gen_wlanhostop(cstate, cstate->e, (int)q.dir); + break; case DLT_IP_OVER_FC: - return gen_ipfchostop(cstate, eaddr, (int)q.dir); + b = gen_ipfchostop(cstate, cstate->e, (int)q.dir); + break; default: + free(cstate->e); + cstate->e = NULL; bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel"); + /* NOTREACHED */ break; } + free(cstate->e); + cstate->e = NULL; + return (b); } bpf_error(cstate, "ethernet address used in non-ether expression"); /* NOTREACHED */ - return NULL; } void -sappend(s0, s1) - struct slist *s0, *s1; +sappend(struct slist *s0, struct slist *s1) { /* * This is definitely not the best way to do this, but the @@ -7003,8 +7287,58 @@ gen_load(compiler_state_t *cstate, int proto, struct arth *inst, int size) inst->b = b; break; case Q_ICMPV6: - bpf_error(cstate, "IPv6 upper-layer protocol is not supported by proto[x]"); - /*NOTREACHED*/ + /* + * Do the computation only if the packet contains + * the protocol in question. + */ + b = gen_proto_abbrev(cstate, Q_IPV6); + if (inst->b) { + gen_and(inst->b, b); + } + inst->b = b; + + /* + * Check if we have an icmp6 next header + */ + b = gen_cmp(cstate, OR_LINKPL, 6, BPF_B, 58); + if (inst->b) { + gen_and(inst->b, b); + } + inst->b = b; + + + s = gen_abs_offset_varpart(cstate, &cstate->off_linkpl); + /* + * If "s" is non-null, it has code to arrange that the + * X register contains the variable part of the offset + * of the link-layer payload. Add to it the offset + * computed into the register specified by "index", + * and move that into the X register. Otherwise, just + * load into the X register the offset computed into + * the register specified by "index". + */ + if (s != NULL) { + sappend(s, xfer_to_a(cstate, inst)); + sappend(s, new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X)); + sappend(s, new_stmt(cstate, BPF_MISC|BPF_TAX)); + } else { + s = xfer_to_x(cstate, inst); + } + + /* + * Load the item at the sum of the offset we've put in the + * X register, the offset of the start of the network + * layer header from the beginning of the link-layer + * payload, and the constant part of the offset of the + * start of the link-layer payload. + */ + tmp = new_stmt(cstate, BPF_LD|BPF_IND|size); + tmp->s.k = cstate->off_linkpl.constant_part + cstate->off_nl + 40; + + sappend(s, tmp); + sappend(inst->s, s); + + break; } inst->regno = regno; s = new_stmt(cstate, BPF_ST); @@ -7121,6 +7455,9 @@ gen_arth(compiler_state_t *cstate, int code, struct arth *a0, /* * Disallow division by, or modulus by, zero; we do this here * so that it gets done even if the optimizer is disabled. + * + * Also disallow shifts by a value greater than 31; we do this + * here, for the same reason. */ if (code == BPF_DIV) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) @@ -7128,6 +7465,15 @@ gen_arth(compiler_state_t *cstate, int code, struct arth *a0, } else if (code == BPF_MOD) { if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0) bpf_error(cstate, "modulus by zero"); + } else if (code == BPF_LSH || code == BPF_RSH) { + /* + * XXX - we need to make up our minds as to what integers + * are signed and what integers are unsigned in BPF programs + * and in our IR. + */ + if (a1->s->s.code == (BPF_LD|BPF_IMM) && + (a1->s->s.k < 0 || a1->s->s.k > 31)) + bpf_error(cstate, "shift by more than 31 bits"); } s0 = xfer_to_x(cstate, a1); s1 = xfer_to_a(cstate, a0); @@ -7176,7 +7522,6 @@ alloc_reg(compiler_state_t *cstate) } bpf_error(cstate, "too many registers needed to evaluate expression"); /* NOTREACHED */ - return 0; } /* @@ -7331,7 +7676,6 @@ gen_broadcast(compiler_state_t *cstate, int proto) } bpf_error(cstate, "only link-layer/IP broadcast filters supported"); /* NOTREACHED */ - return NULL; } /* @@ -7527,7 +7871,6 @@ gen_multicast(compiler_state_t *cstate, int proto) } bpf_error(cstate, "link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel"); /* NOTREACHED */ - return NULL; } /* @@ -7574,6 +7917,15 @@ gen_inbound(compiler_state_t *cstate, int dir) } break; + case DLT_LINUX_SLL2: + /* match outgoing packets */ + b0 = gen_cmp(cstate, OR_LINKHDR, 10, BPF_B, LINUX_SLL_OUTGOING); + if (!dir) { + /* to filter on inbound traffic, invert the match */ + gen_not(b0); + } + break; + #ifdef HAVE_NET_PFVAR_H case DLT_PFLOG: b0 = gen_cmp(cstate, OR_LINKHDR, offsetof(struct pfloghdr, dir), BPF_B, @@ -7628,8 +7980,18 @@ gen_inbound(compiler_state_t *cstate, int dir) default: /* * If we have packet meta-data indicating a direction, - * check it, otherwise give up as this link-layer type - * has nothing in the packet data. + * and that metadata can be checked by BPF code, check + * it. Otherwise, give up, as this link-layer type has + * nothing in the packet data. + * + * Currently, the only platform where a BPF filter can + * check that metadata is Linux with the in-kernel + * BPF interpreter. If other packet capture mechanisms + * and BPF filters also supported this, it would be + * nice. It would be even better if they made that + * metadata available so that we could provide it + * with newer capture APIs, allowing it to be saved + * in pcapng files. */ #if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) /* @@ -7655,7 +8017,6 @@ gen_inbound(compiler_state_t *cstate, int dir) #else /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ bpf_error(cstate, "inbound/outbound not supported on linktype %d", cstate->linktype); - b0 = NULL; /* NOTREACHED */ #endif /* defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER) */ } @@ -7772,51 +8133,45 @@ gen_pf_action(compiler_state_t *cstate, int action) } #else /* !HAVE_NET_PFVAR_H */ struct block * -gen_pf_ifname(compiler_state_t *cstate, const char *ifname) +gen_pf_ifname(compiler_state_t *cstate, const char *ifname _U_) { bpf_error(cstate, "libpcap was compiled without pf support"); /* NOTREACHED */ - return (NULL); } struct block * -gen_pf_ruleset(compiler_state_t *cstate, char *ruleset) +gen_pf_ruleset(compiler_state_t *cstate, char *ruleset _U_) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ - return (NULL); } struct block * -gen_pf_rnr(compiler_state_t *cstate, int rnr) +gen_pf_rnr(compiler_state_t *cstate, int rnr _U_) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ - return (NULL); } struct block * -gen_pf_srnr(compiler_state_t *cstate, int srnr) +gen_pf_srnr(compiler_state_t *cstate, int srnr _U_) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ - return (NULL); } struct block * -gen_pf_reason(compiler_state_t *cstate, int reason) +gen_pf_reason(compiler_state_t *cstate, int reason _U_) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ - return (NULL); } struct block * -gen_pf_action(compiler_state_t *cstate, int action) +gen_pf_action(compiler_state_t *cstate, int action _U_) { bpf_error(cstate, "libpcap was compiled on a machine without pf support"); /* NOTREACHED */ - return (NULL); } #endif /* HAVE_NET_PFVAR_H */ @@ -7869,16 +8224,24 @@ gen_p80211_fcdir(compiler_state_t *cstate, int fcdir) } struct block * -gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) +gen_acode(compiler_state_t *cstate, const char *s, struct qual q) { + struct block *b; + switch (cstate->linktype) { case DLT_ARCNET: case DLT_ARCNET_LINUX: if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && - q.proto == Q_LINK) - return (gen_ahostop(cstate, eaddr, (int)q.dir)); - else { + q.proto == Q_LINK) { + cstate->e = pcap_ether_aton(s); + if (cstate->e == NULL) + bpf_error(cstate, "malloc"); + b = gen_ahostop(cstate, cstate->e, (int)q.dir); + free(cstate->e); + cstate->e = NULL; + return (b); + } else { bpf_error(cstate, "ARCnet address used in non-arc expression"); /* NOTREACHED */ } @@ -7888,9 +8251,6 @@ gen_acode(compiler_state_t *cstate, const u_char *eaddr, struct qual q) bpf_error(cstate, "aid supported only on ARCnet"); /* NOTREACHED */ } - bpf_error(cstate, "ARCnet address used in non-arc expression"); - /* NOTREACHED */ - return NULL; } static struct block * @@ -7920,19 +8280,19 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) return b1; case Q_ADDR1: - bpf_error(cstate, "'addr1' is only supported on 802.11"); + bpf_error(cstate, "'addr1' and 'address1' are only supported on 802.11"); break; case Q_ADDR2: - bpf_error(cstate, "'addr2' is only supported on 802.11"); + bpf_error(cstate, "'addr2' and 'address2' are only supported on 802.11"); break; case Q_ADDR3: - bpf_error(cstate, "'addr3' is only supported on 802.11"); + bpf_error(cstate, "'addr3' and 'address3' are only supported on 802.11"); break; case Q_ADDR4: - bpf_error(cstate, "'addr4' is only supported on 802.11"); + bpf_error(cstate, "'addr4' and 'address4' are only supported on 802.11"); break; case Q_RA: @@ -7947,74 +8307,184 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir) /* NOTREACHED */ } -#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) static struct block * -gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) +gen_vlan_tpid_test(compiler_state_t *cstate) { - struct block *b0, *b1; - struct slist *s; - - /* generate new filter code based on extracting packet - * metadata */ - s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); - s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; - - b0 = new_block(cstate, JMP(BPF_JEQ)); - b0->stmts = s; - b0->s.k = 1; - - if (vlan_num >= 0) { - s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); - s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; + struct block *b0, *b1; - b1 = new_block(cstate, JMP(BPF_JEQ)); - b1->stmts = s; - b1->s.k = (bpf_int32) vlan_num; + /* check for VLAN, including QinQ */ + b0 = gen_linktype(cstate, ETHERTYPE_8021Q); + b1 = gen_linktype(cstate, ETHERTYPE_8021AD); + gen_or(b0,b1); + b0 = b1; + b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ); + gen_or(b0,b1); - gen_and(b0,b1); - b0 = b1; - } + return b1; +} - return b0; +static struct block * +gen_vlan_vid_test(compiler_state_t *cstate, int vlan_num) +{ + return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff); } -#endif static struct block * gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num) { - struct block *b0, *b1; - - /* check for VLAN, including QinQ */ - b0 = gen_linktype(cstate, ETHERTYPE_8021Q); - b1 = gen_linktype(cstate, ETHERTYPE_8021AD); - gen_or(b0,b1); - b0 = b1; - b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ); - gen_or(b0,b1); - b0 = b1; - - /* If a specific VLAN is requested, check VLAN id */ - if (vlan_num >= 0) { - b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, - (bpf_int32)vlan_num, 0x0fff); - gen_and(b0, b1); - b0 = b1; - } + struct block *b0, *b1; + + b0 = gen_vlan_tpid_test(cstate); + + if (vlan_num >= 0) { + b1 = gen_vlan_vid_test(cstate, vlan_num); + gen_and(b0, b1); + b0 = b1; + } /* - * The payload follows the full header, including the - * VLAN tags, so skip past this VLAN tag. + * Both payload and link header type follow the VLAN tags so that + * both need to be updated. */ - cstate->off_linkpl.constant_part += 4; + cstate->off_linkpl.constant_part += 4; + cstate->off_linktype.constant_part += 4; + + return b0; +} + +#if defined(SKF_AD_VLAN_TAG_PRESENT) +/* add v to variable part of off */ +static void +gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s) +{ + struct slist *s2; + + if (!off->is_variable) + off->is_variable = 1; + if (off->reg == -1) + off->reg = alloc_reg(cstate); + + s2 = new_stmt(cstate, BPF_LD|BPF_MEM); + s2->s.k = off->reg; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM); + s2->s.k = v; + sappend(s, s2); + s2 = new_stmt(cstate, BPF_ST); + s2->s.k = off->reg; + sappend(s, s2); +} + +/* + * patch block b_tpid (VLAN TPID test) to update variable parts of link payload + * and link type offsets first + */ +static void +gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid) +{ + struct slist s; + + /* offset determined at run time, shift variable part */ + s.next = NULL; + cstate->is_vlan_vloffset = 1; + gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s); + gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s); + + /* we get a pointer to a chain of or-ed blocks, patch first of them */ + sappend(s.next, b_tpid->head->stmts); + b_tpid->head->stmts = s.next; +} + +/* + * patch block b_vid (VLAN id test) to load VID value either from packet + * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true + */ +static void +gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid) +{ + struct slist *s, *s2, *sjeq; + unsigned cnt; + + s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; + + /* true -> next instructions, false -> beginning of b_vid */ + sjeq = new_stmt(cstate, JMP(BPF_JEQ)); + sjeq->s.k = 1; + sjeq->s.jf = b_vid->stmts; + sappend(s, sjeq); + + s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG; + sappend(s, s2); + sjeq->s.jt = s2; + + /* Jump to the test in b_vid. We need to jump one instruction before + * the end of the b_vid block so that we only skip loading the TCI + * from packet data and not the 'and' instruction extractging VID. + */ + cnt = 0; + for (s2 = b_vid->stmts; s2; s2 = s2->next) + cnt++; + s2 = new_stmt(cstate, JMP(BPF_JA)); + s2->s.k = cnt - 1; + sappend(s, s2); + + /* insert our statements at the beginning of b_vid */ + sappend(s, b_vid->stmts); + b_vid->stmts = s; +} + +/* + * Generate check for "vlan" or "vlan " on systems with support for BPF + * extensions. Even if kernel supports VLAN BPF extensions, (outermost) VLAN + * tag can be either in metadata or in packet data; therefore if the + * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link + * header for VLAN tag. As the decision is done at run time, we need + * update variable part of the offsets + */ +static struct block * +gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num) +{ + struct block *b0, *b_tpid, *b_vid = NULL; + struct slist *s; + + /* generate new filter code based on extracting packet + * metadata */ + s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS); + s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT; + + b0 = new_block(cstate, JMP(BPF_JEQ)); + b0->stmts = s; + b0->s.k = 1; /* - * The link-layer type information follows the VLAN tags, so - * skip past this VLAN tag. + * This is tricky. We need to insert the statements updating variable + * parts of offsets before the the traditional TPID and VID tests so + * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but + * we do not want this update to affect those checks. That's why we + * generate both test blocks first and insert the statements updating + * variable parts of both offsets after that. This wouldn't work if + * there already were variable length link header when entering this + * function but gen_vlan_bpf_extensions() isn't called in that case. */ - cstate->off_linktype.constant_part += 4; + b_tpid = gen_vlan_tpid_test(cstate); + if (vlan_num >= 0) + b_vid = gen_vlan_vid_test(cstate, vlan_num); + + gen_vlan_patch_tpid_test(cstate, b_tpid); + gen_or(b0, b_tpid); + b0 = b_tpid; + + if (vlan_num >= 0) { + gen_vlan_patch_vid_test(cstate, b_vid); + gen_and(b0, b_vid); + b0 = b_vid; + } return b0; } +#endif /* * support IEEE 802.1Q VLAN trunk over ethernet @@ -8064,7 +8534,7 @@ gen_vlan(compiler_state_t *cstate, int vlan_num) case DLT_EN10MB: case DLT_NETANALYZER: case DLT_NETANALYZER_TRANSPARENT: -#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT) +#if defined(SKF_AD_VLAN_TAG_PRESENT) /* Verify that this is the outer part of the packet and * not encapsulated somehow. */ if (cstate->vlan_stack_depth == 0 && !cstate->off_linkhdr.is_variable && @@ -8104,7 +8574,7 @@ gen_vlan(compiler_state_t *cstate, int vlan_num) * support for MPLS */ struct block * -gen_mpls(compiler_state_t *cstate, int label_num) +gen_mpls(compiler_state_t *cstate, bpf_u_int32 label_num, int has_label_num) { struct block *b0, *b1; @@ -8136,14 +8606,17 @@ gen_mpls(compiler_state_t *cstate, int label_num) default: bpf_error(cstate, "no MPLS support for data link type %d", cstate->linktype); - b0 = NULL; /*NOTREACHED*/ break; } } /* If a specific MPLS label is requested, check it */ - if (label_num >= 0) { + if (has_label_num) { + if (label_num > 0xFFFFF) { + bpf_error(cstate, "MPLS label %u greater than maximum %u", + label_num, 0xFFFFF); + } label_num = label_num << 12; /* label is shifted 12 bits on the wire */ b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_W, (bpf_int32)label_num, 0xfffff000); /* only compare the first 20 bits */ @@ -8557,7 +9030,7 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, case A_VPI: if (!cstate->is_atm) bpf_error(cstate, "'vpi' supported only on raw ATM"); - if (cstate->off_vpi == (u_int)-1) + if (cstate->off_vpi == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vpi, BPF_B, 0xffffffff, jtype, reverse, jvalue); @@ -8566,21 +9039,21 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, case A_VCI: if (!cstate->is_atm) bpf_error(cstate, "'vci' supported only on raw ATM"); - if (cstate->off_vci == (u_int)-1) + if (cstate->off_vci == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_vci, BPF_H, 0xffffffff, jtype, reverse, jvalue); break; case A_PROTOTYPE: - if (cstate->off_proto == (u_int)-1) + if (cstate->off_proto == OFFSET_NOT_SET) abort(); /* XXX - this isn't on FreeBSD */ b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0x0f, jtype, reverse, jvalue); break; case A_MSGTYPE: - if (cstate->off_payload == (u_int)-1) + if (cstate->off_payload == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_payload + MSG_TYPE_POS, BPF_B, 0xffffffff, jtype, reverse, jvalue); @@ -8589,7 +9062,7 @@ gen_atmfield_code(compiler_state_t *cstate, int atmfield, bpf_int32 jvalue, case A_CALLREFTYPE: if (!cstate->is_atm) bpf_error(cstate, "'callref' supported only on raw ATM"); - if (cstate->off_proto == (u_int)-1) + if (cstate->off_proto == OFFSET_NOT_SET) abort(); b0 = gen_ncmp(cstate, OR_LINKHDR, cstate->off_proto, BPF_B, 0xffffffff, jtype, reverse, jvalue); @@ -8791,7 +9264,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, /* FALLTHROUGH */ case M_SIO: - if (cstate->off_sio == (u_int)-1) + if (cstate->off_sio == OFFSET_NOT_SET) bpf_error(cstate, "'sio' supported only on SS7"); /* sio coded on 1 byte so max value 255 */ if(jvalue > 255) @@ -8804,7 +9277,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, case MH_OPC: newoff_opc+=3; case M_OPC: - if (cstate->off_opc == (u_int)-1) + if (cstate->off_opc == OFFSET_NOT_SET) bpf_error(cstate, "'opc' supported only on SS7"); /* opc coded on 14 bits so max value 16383 */ if (jvalue > 16383) @@ -8828,7 +9301,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, /* FALLTHROUGH */ case M_DPC: - if (cstate->off_dpc == (u_int)-1) + if (cstate->off_dpc == OFFSET_NOT_SET) bpf_error(cstate, "'dpc' supported only on SS7"); /* dpc coded on 14 bits so max value 16383 */ if (jvalue > 16383) @@ -8848,7 +9321,7 @@ gen_mtp3field_code(compiler_state_t *cstate, int mtp3field, bpf_u_int32 jvalue, case MH_SLS: newoff_sls+=3; case M_SLS: - if (cstate->off_sls == (u_int)-1) + if (cstate->off_sls == OFFSET_NOT_SET) bpf_error(cstate, "'sls' supported only on SS7"); /* sls coded on 4 bits so max value 15 */ if (jvalue > 15)