]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
If parser debugging is enabled, ensure pcap_debug is exported.
[libpcap] / gencode.c
index c5229550243f1ec49a59191c360cb92feb72e282..481c4d9c358a5ade099ba458a907502b837c8139 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -24,9 +24,9 @@
 #include "config.h"
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
 #include <pcap-stdinc.h>
-#else /* WIN32 */
+#else /* _WIN32 */
 #if HAVE_INTTYPES_H
 #include <inttypes.h>
 #elif HAVE_STDINT_H
 #endif
 #include <sys/types.h>
 #include <sys/socket.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
-/*
- * XXX - why was this included even on UNIX?
- */
-#ifdef __MINGW32__
-#include "ip6_misc.h"
-#endif
-
-#ifndef WIN32
+#ifndef _WIN32
 
 #ifdef __NetBSD__
 #include <sys/param.h>
@@ -55,7 +48,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#endif /* WIN32 */
+#endif /* _WIN32 */
 
 #include <stdlib.h>
 #include <string.h>
 #include "pcap/sll.h"
 #include "pcap/ipnet.h"
 #include "arcnet.h"
+
+#include "grammar.h"
+#include "scanner.h"
+
 #if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
 #include <linux/types.h>
 #include <linux/if_packet.h>
 #include <linux/filter.h>
 #endif
+
 #ifdef HAVE_NET_PFVAR_H
 #include <sys/socket.h>
 #include <net/if.h>
 #include <net/pfvar.h>
 #include <net/if_pflog.h>
 #endif
+
 #ifndef offsetof
 #define offsetof(s, e) ((size_t)&((s *)0)->e)
 #endif
+
 #ifdef INET6
-#ifndef WIN32
+#ifdef _WIN32
+#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];
+      } in6_u;
+#define s6_addr                        in6_u.u6_addr8
+#define s6_addr16              in6_u.u6_addr16
+#define s6_addr32              in6_u.u6_addr32
+#define s6_addr64              in6_u.u6_addr64
+  };
+
+typedef unsigned short sa_family_t;
+
+#define        __SOCKADDR_COMMON(sa_prefix) \
+  sa_family_t sa_prefix##family
+
+/* Ditto, for IPv6.  */
+struct sockaddr_in6
+  {
+    __SOCKADDR_COMMON (sin6_);
+    u_int16_t sin6_port;               /* Transport layer port # */
+    u_int32_t sin6_flowinfo;   /* IPv6 flow information */
+    struct in6_addr sin6_addr; /* IPv6 address */
+  };
+
+#ifndef EAI_ADDRFAMILY
+struct addrinfo {
+       int     ai_flags;       /* AI_PASSIVE, AI_CANONNAME */
+       int     ai_family;      /* PF_xxx */
+       int     ai_socktype;    /* SOCK_xxx */
+       int     ai_protocol;    /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+       size_t  ai_addrlen;     /* length of ai_addr */
+       char    *ai_canonname;  /* canonical name for hostname */
+       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) */
+#else /* _WIN32 */
 #include <netdb.h>     /* for "struct addrinfo" */
-#endif /* WIN32 */
-#endif /*INET6*/
+#endif /* _WIN32 */
+#endif /* INET6 */
 #include <pcap/namedb.h>
 
+#include "nametoaddr.h"
+
 #define ETHERMTU       1500
 
+#ifndef ETHERTYPE_TEB
+#define ETHERTYPE_TEB 0x6558
+#endif
+
 #ifndef IPPROTO_HOPOPTS
 #define IPPROTO_HOPOPTS 0
 #endif
 #define IPPROTO_SCTP 132
 #endif
 
+#define GENEVE_PORT 6081
+
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
 #endif
@@ -130,7 +182,7 @@ static jmp_buf top_ctx;
 static pcap_t *bpf_pcap;
 
 /* Hack for handling VLAN and MPLS stacks. */
-#ifdef WIN32
+#ifdef _WIN32
 static u_int   label_stack_depth = (u_int)-1, vlan_stack_depth = (u_int)-1;
 #else
 static u_int   label_stack_depth = -1U, vlan_stack_depth = -1U;
@@ -147,7 +199,7 @@ bpf_error(const char *fmt, ...)
 
        va_start(ap, fmt);
        if (bpf_pcap != NULL)
-               (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE,
+               (void)pcap_vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE,
                    fmt, ap);
        va_end(ap);
        longjmp(top_ctx, 1);
@@ -224,14 +276,14 @@ static struct addrinfo *ai;
 #define NCHUNKS 16
 #define CHUNK0SIZE 1024
 struct chunk {
-       u_int n_left;
+       size_t n_left;
        void *m;
 };
 
 static struct chunk chunks[NCHUNKS];
 static int cur_chunk;
 
-static void *newchunk(u_int);
+static void *newchunk(size_t);
 static void freechunks(void);
 static inline struct block *new_block(int);
 static inline struct slist *new_stmt(int);
@@ -309,13 +361,13 @@ static struct slist *xfer_to_a(struct arth *);
 static struct block *gen_mac_multicast(int);
 static struct block *gen_len(int, int);
 static struct block *gen_check_802_11_data_frame(void);
+static struct block *gen_geneve_ll_check(void);
 
 static struct block *gen_ppi_dlt_check(void);
 static struct block *gen_msg_abbrev(int type);
 
 static void *
-newchunk(n)
-       u_int n;
+newchunk(size_t n)
 {
        struct chunk *cp;
        int k;
@@ -367,7 +419,7 @@ char *
 sdup(s)
        register const char *s;
 {
-       int n = strlen(s) + 1;
+       size_t n = strlen(s) + 1;
        char *cp = newchunk(n);
 
        strlcpy(cp, s, n);
@@ -425,6 +477,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
 {
        extern int n_errors;
        const char * volatile xbuf = buf;
+       yyscan_t scanner = NULL;
+       YY_BUFFER_STATE in_buffer = NULL;
        u_int len;
        int  rc;
 
@@ -433,12 +487,11 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
         * UN*X, if the platform supports pthreads?  If that requires
         * a separate -lpthread, we might not want to do that.
         */
-#ifdef WIN32
-       extern int wsockinit (void);
+#ifdef _WIN32
        static int done = 0;
 
        if (!done)
-               wsockinit();
+               pcap_wsockinit();
        done = 1;
        EnterCriticalSection(&g_PcapCompileCriticalSection);
 #endif
@@ -448,7 +501,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
         * link-layer type, so we can't use it.
         */
        if (!p->activated) {
-               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "not-yet-activated pcap_t passed to pcap_compile");
                rc = -1;
                goto quit;
@@ -466,8 +519,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
                        ai = NULL;
                }
 #endif
-               lex_cleanup();
-               freechunks();
                rc = -1;
                goto quit;
        }
@@ -476,15 +527,17 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
 
        snaplen = pcap_snapshot(p);
        if (snaplen == 0) {
-               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                         "snaplen of 0 rejects all packets");
                rc = -1;
                goto quit;
        }
 
-       lex_init(xbuf ? xbuf : "");
+       if (pcap_lex_init(&scanner) != 0)
+               bpf_error("can't initialize scanner: %s", pcap_strerror(errno));
+       in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
        init_linktype(p);
-       (void)pcap_parse();
+       (void)pcap_parse(scanner);
 
        if (n_errors)
                syntax();
@@ -501,14 +554,23 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        program->bf_insns = icode_to_fcode(root, &len);
        program->bf_len = len;
 
-       lex_cleanup();
-       freechunks();
-
        rc = 0;  /* We're all okay */
 
 quit:
+       /*
+        * Clean up everything for the lexical analyzer.
+        */
+       if (in_buffer != NULL)
+               pcap__delete_buffer(in_buffer, scanner);
+       if (scanner != NULL)
+               pcap_lex_destroy(scanner);
+
+       /*
+        * Clean up our own allocated memory.
+        */
+       freechunks();
 
-#ifdef WIN32
+#ifdef _WIN32
        LeaveCriticalSection(&g_PcapCompileCriticalSection);
 #endif
 
@@ -621,6 +683,15 @@ finish_parse(p)
        /*
         * For DLT_PPI captures, generate a check of the per-packet
         * DLT value to make sure it's DLT_IEEE802_11.
+        *
+        * XXX - TurboCap cards use DLT_PPI for Ethernet.
+        * Can we just define some DLT_ETHERNET_WITH_PHDR pseudo-header
+        * with appropriate Ethernet information and use that rather
+        * than using something such as DLT_PPI where you don't know
+        * the link-layer header type until runtime, which, in the
+        * general case, would force us to generate both Ethernet *and*
+        * 802.11 code (*and* anything else for which PPI is used)
+        * and choose between them early in the BPF program?
         */
        ppi_dlt_check = gen_ppi_dlt_check();
        if (ppi_dlt_check != NULL)
@@ -826,6 +897,7 @@ static bpf_abs_offset off_outermostlinkhdr;
        off_linkhdr.is_variable = new_is_variable; \
        off_linkhdr.constant_part = new_constant_part; \
        off_linkhdr.reg = new_reg; \
+       is_geneve = 0; \
 }
 
 /*
@@ -863,6 +935,13 @@ static bpf_abs_offset off_linktype;
  */
 static int is_atm = 0;
 
+/*
+ * TRUE if "geneve" appeared in the filter; it causes us to generate
+ * code that checks for a Geneve header and assume that later filters
+ * apply to the encapsulated payload.
+ */
+static int is_geneve = 0;
+
 /*
  * These are offsets for the ATM pseudo-header.
  */
@@ -965,6 +1044,11 @@ init_linktype(p)
        off_proto = -1;
        off_payload = -1;
 
+       /*
+        * And not Geneve.
+        */
+       is_geneve = 0;
+
        /*
         * And assume we're not doing SS7.
         */
@@ -2778,6 +2862,9 @@ gen_prevlinkhdr_check(void)
 {
        struct block *b0;
 
+       if (is_geneve)
+               return gen_geneve_ll_check();
+
        switch (prevlinktype) {
 
        case DLT_SUNATM:
@@ -2839,7 +2926,13 @@ gen_linktype(proto)
        case DLT_EN10MB:
        case DLT_NETANALYZER:
        case DLT_NETANALYZER_TRANSPARENT:
-               b0 = gen_prevlinkhdr_check();
+               /* Geneve has an EtherType regardless of whether there is an
+                * L2 header. */
+               if (!is_geneve)
+                       b0 = gen_prevlinkhdr_check();
+               else
+                       b0 = NULL;
+
                b1 = gen_ether_linktype(proto);
                if (b0 != NULL)
                        gen_and(b0, b1);
@@ -5532,7 +5625,7 @@ gen_protochain(v, proto, dir)
        int reg2 = alloc_reg();
 
        memset(s, 0, sizeof(s));
-       fix2 = fix3 = fix4 = fix5 = 0;
+       fix3 = fix4 = fix5 = 0;
 
        switch (proto) {
        case Q_IP:
@@ -6998,6 +7091,17 @@ gen_arth(code, a0, a1)
 {
        struct slist *s0, *s1, *s2;
 
+       /*
+        * Disallow division by, or modulus by, zero; we do this here
+        * so that it gets done even if the optimizer is disabled.
+        */
+       if (code == BPF_DIV) {
+               if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+                       bpf_error("division by zero");
+       } else if (code == BPF_MOD) {
+               if (a1->s->s.code == (BPF_LD|BPF_IMM) && a1->s->s.k == 0)
+                       bpf_error("modulus by zero");
+       }
        s0 = xfer_to_x(a1);
        s1 = xfer_to_a(a0);
        s2 = new_stmt(BPF_ALU|BPF_X|code);
@@ -7875,6 +7979,9 @@ gen_vlan_no_bpf_extensions(int vlan_num)
 
         /* check for VLAN, including QinQ */
         b0 = gen_linktype(ETHERTYPE_8021Q);
+        b1 = gen_linktype(ETHERTYPE_8021AD);
+        gen_or(b0,b1);
+        b0 = b1;
         b1 = gen_linktype(ETHERTYPE_8021QINQ);
         gen_or(b0,b1);
         b0 = b1;
@@ -8140,6 +8247,300 @@ gen_pppoes(sess_num)
        return b0;
 }
 
+/* Check that this is Geneve and the VNI is correct if
+ * specified. Parameterized to handle both IPv4 and IPv6. */
+static struct block *
+gen_geneve_check(struct block *(*gen_portfn)(int, int, int),
+                enum e_offrel offrel, int vni)
+{
+       struct block *b0, *b1;
+
+       b0 = gen_portfn(GENEVE_PORT, IPPROTO_UDP, Q_DST);
+
+       /* Check that we are operating on version 0. Otherwise, we
+        * can't decode the rest of the fields. The version is 2 bits
+        * in the first byte of the Geneve header. */
+       b1 = gen_mcmp(offrel, 8, BPF_B, (bpf_int32)0, 0xc0);
+       gen_and(b0, b1);
+       b0 = b1;
+
+       if (vni >= 0) {
+               vni <<= 8; /* VNI is in the upper 3 bytes */
+               b1 = gen_mcmp(offrel, 12, BPF_W, (bpf_int32)vni,
+                             0xffffff00);
+               gen_and(b0, b1);
+               b0 = b1;
+       }
+
+       return b0;
+}
+
+/* The IPv4 and IPv6 Geneve checks need to do two things:
+ * - Verify that this actually is Geneve with the right VNI.
+ * - Place the IP header length (plus variable link prefix if
+ *   needed) into register A to be used later to compute
+ *   the inner packet offsets. */
+static struct block *
+gen_geneve4(int vni)
+{
+       struct block *b0, *b1;
+       struct slist *s, *s1;
+
+       b0 = gen_geneve_check(gen_port, OR_TRAN_IPV4, vni);
+
+       /* Load the IP header length into A. */
+       s = gen_loadx_iphdrlen();
+
+       s1 = new_stmt(BPF_MISC|BPF_TXA);
+       sappend(s, s1);
+
+       /* Forcibly append these statements to the true condition
+        * of the protocol check by creating a new block that is
+        * always true and ANDing them. */
+       b1 = new_block(BPF_JMP|BPF_JEQ|BPF_X);
+       b1->stmts = s;
+       b1->s.k = 0;
+
+       gen_and(b0, b1);
+
+       return b1;
+}
+
+static struct block *
+gen_geneve6(int vni)
+{
+       struct block *b0, *b1;
+       struct slist *s, *s1;
+
+       b0 = gen_geneve_check(gen_port6, OR_TRAN_IPV6, vni);
+
+       /* Load the IP header length. We need to account for a
+        * variable length link prefix if there is one. */
+       s = gen_abs_offset_varpart(&off_linkpl);
+       if (s) {
+               s1 = new_stmt(BPF_LD|BPF_IMM);
+               s1->s.k = 40;
+               sappend(s, s1);
+
+               s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_X);
+               s1->s.k = 0;
+               sappend(s, s1);
+       } else {
+               s = new_stmt(BPF_LD|BPF_IMM);
+               s->s.k = 40;
+       }
+
+       /* Forcibly append these statements to the true condition
+        * of the protocol check by creating a new block that is
+        * always true and ANDing them. */
+       s1 = new_stmt(BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       b1 = new_block(BPF_JMP|BPF_JEQ|BPF_X);
+       b1->stmts = s;
+       b1->s.k = 0;
+
+       gen_and(b0, b1);
+
+       return b1;
+}
+
+/* We need to store three values based on the Geneve header::
+ * - The offset of the linktype.
+ * - The offset of the end of the Geneve header.
+ * - The offset of the end of the encapsulated MAC header. */
+static struct slist *
+gen_geneve_offsets(void)
+{
+       struct slist *s, *s1, *s_proto;
+
+       /* First we need to calculate the offset of the Geneve header
+        * itself. This is composed of the IP header previously calculated
+        * (include any variable link prefix) and stored in A plus the
+        * fixed sized headers (fixed link prefix, MAC length, and UDP
+        * header). */
+       s = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s->s.k = off_linkpl.constant_part + off_nl + 8;
+
+       /* Stash this in X since we'll need it later. */
+       s1 = new_stmt(BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       /* The EtherType in Geneve is 2 bytes in. Calculate this and
+        * store it. */
+       s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       off_linktype.reg = alloc_reg();
+       off_linktype.is_variable = 1;
+       off_linktype.constant_part = 0;
+
+       s1 = new_stmt(BPF_ST);
+       s1->s.k = off_linktype.reg;
+       sappend(s, s1);
+
+       /* Load the Geneve option length and mask and shift to get the
+        * number of bytes. It is stored in the first byte of the Geneve
+        * header. */
+       s1 = new_stmt(BPF_LD|BPF_IND|BPF_B);
+       s1->s.k = 0;
+       sappend(s, s1);
+
+       s1 = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+       s1->s.k = 0x3f;
+       sappend(s, s1);
+
+       s1 = new_stmt(BPF_ALU|BPF_MUL|BPF_K);
+       s1->s.k = 4;
+       sappend(s, s1);
+
+       /* Add in the rest of the Geneve base header. */
+       s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 8;
+       sappend(s, s1);
+
+       /* Add the Geneve header length to its offset and store. */
+       s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_X);
+       s1->s.k = 0;
+       sappend(s, s1);
+
+       /* Set the encapsulated type as Ethernet. Even though we may
+        * not actually have Ethernet inside there are two reasons this
+        * is useful:
+        * - The linktype field is always in EtherType format regardless
+        *   of whether it is in Geneve or an inner Ethernet frame.
+        * - The only link layer that we have specific support for is
+        *   Ethernet. We will confirm that the packet actually is
+        *   Ethernet at runtime before executing these checks. */
+       PUSH_LINKHDR(DLT_EN10MB, 1, 0, alloc_reg());
+
+       s1 = new_stmt(BPF_ST);
+       s1->s.k = off_linkhdr.reg;
+       sappend(s, s1);
+
+       /* Calculate whether we have an Ethernet header or just raw IP/
+        * MPLS/etc. If we have Ethernet, advance the end of the MAC offset
+        * and linktype by 14 bytes so that the network header can be found
+        * seamlessly. Otherwise, keep what we've calculated already. */
+
+       /* We have a bare jmp so we can't use the optimizer. */
+       no_optimize = 1;
+
+       /* Load the EtherType in the Geneve header, 2 bytes in. */
+       s1 = new_stmt(BPF_LD|BPF_IND|BPF_H);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       /* Load X with the end of the Geneve header. */
+       s1 = new_stmt(BPF_LDX|BPF_MEM);
+       s1->s.k = off_linkhdr.reg;
+       sappend(s, s1);
+
+       /* Check if the EtherType is Transparent Ethernet Bridging. At the
+        * end of this check, we should have the total length in X. In
+        * the non-Ethernet case, it's already there. */
+       s_proto = new_stmt(JMP(BPF_JEQ));
+       s_proto->s.k = ETHERTYPE_TEB;
+       sappend(s, s_proto);
+
+       s1 = new_stmt(BPF_MISC|BPF_TXA);
+       sappend(s, s1);
+       s_proto->s.jt = s1;
+
+       /* Since this is Ethernet, use the EtherType of the payload
+        * directly as the linktype. Overwrite what we already have. */
+       s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 12;
+       sappend(s, s1);
+
+       s1 = new_stmt(BPF_ST);
+       s1->s.k = off_linktype.reg;
+       sappend(s, s1);
+
+       /* Advance two bytes further to get the end of the Ethernet
+        * header. */
+       s1 = new_stmt(BPF_ALU|BPF_ADD|BPF_K);
+       s1->s.k = 2;
+       sappend(s, s1);
+
+       /* Move the result to X. */
+       s1 = new_stmt(BPF_MISC|BPF_TAX);
+       sappend(s, s1);
+
+       /* Store the final result of our linkpl calculation. */
+       off_linkpl.reg = alloc_reg();
+       off_linkpl.is_variable = 1;
+       off_linkpl.constant_part = 0;
+
+       s1 = new_stmt(BPF_STX);
+       s1->s.k = off_linkpl.reg;
+       sappend(s, s1);
+       s_proto->s.jf = s1;
+
+       off_nl = 0;
+
+       return s;
+}
+
+/* Check to see if this is a Geneve packet. */
+struct block *
+gen_geneve(int vni)
+{
+       struct block *b0, *b1;
+       struct slist *s;
+
+       b0 = gen_geneve4(vni);
+       b1 = gen_geneve6(vni);
+
+       gen_or(b0, b1);
+       b0 = b1;
+
+       /* Later filters should act on the payload of the Geneve frame,
+        * update all of the header pointers. Attach this code so that
+        * it gets executed in the event that the Geneve filter matches. */
+       s = gen_geneve_offsets();
+
+       b1 = gen_true();
+       sappend(s, b1->stmts);
+       b1->stmts = s;
+
+       gen_and(b0, b1);
+
+       is_geneve = 1;
+
+       return b1;
+}
+
+/* Check that the encapsulated frame has a link layer header
+ * for Ethernet filters. */
+static struct block *
+gen_geneve_ll_check()
+{
+       struct block *b0;
+       struct slist *s, *s1;
+
+       /* The easiest way to see if there is a link layer present
+        * is to check if the link layer header and payload are not
+        * the same. */
+
+       /* Geneve always generates pure variable offsets so we can
+        * compare only the registers. */
+       s = new_stmt(BPF_LD|BPF_MEM);
+       s->s.k = off_linkhdr.reg;
+
+       s1 = new_stmt(BPF_LDX|BPF_MEM);
+       s1->s.k = off_linkpl.reg;
+       sappend(s, s1);
+
+       b0 = new_block(BPF_JMP|BPF_JEQ|BPF_X);
+       b0->stmts = s;
+       b0->s.k = 0;
+       gen_not(b0);
+
+       return b0;
+}
+
 struct block *
 gen_atmfield_code(atmfield, jvalue, jtype, reverse)
        int atmfield;