]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Merge pull request #1 from the-tcpdump-group/master
[libpcap] / gencode.c
index 0cf2bfa6ae68866b661c8f8ddedb24a0215ee617..e59953fff426bd366d7a7d0415c906639a6ce207 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -193,6 +193,11 @@ struct addrinfo {
        (cs)->is_geneve = 0; \
 }
 
+/*
+ * Offset "not set" value.
+ */
+#define OFFSET_NOT_SET 0xffffffffU
+
 /*
  * Absolute offsets, which are offsets from the beginning of the raw
  * packet data, are, in the general case, the sum of a variable value
@@ -270,7 +275,7 @@ struct _compiler_state {
        u_int vlan_stack_depth;
 
        /* XXX */
-       int pcap_fddipad;
+       u_int pcap_fddipad;
 
 #ifdef INET6
        /*
@@ -335,8 +340,8 @@ struct _compiler_state {
         *
         * For Linux cooked sockets, it's the offset of the type field.
         *
-        * off_linktype.constant_part is set to -1 for no encapsulation,
-        * in which case, IP is assumed.
+        * off_linktype.constant_part is set to OFFSET_NOT_SET for no
+        * encapsulation, in which case, IP is assumed.
         */
        bpf_abs_offset off_linktype;
 
@@ -518,7 +523,8 @@ static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
     struct in6_addr *, int, int, int);
 #endif
 #ifndef INET6
-static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);
+static struct block *gen_gateway(compiler_state_t *, const u_char *,
+    bpf_u_int32 **, int, int);
 #endif
 static struct block *gen_ipfrag(compiler_state_t *);
 static struct block *gen_portatom(compiler_state_t *, int, bpf_int32);
@@ -658,6 +664,9 @@ int
 pcap_compile(pcap_t *p, struct bpf_program *program,
             const char *buf, int optimize, bpf_u_int32 mask)
 {
+#ifdef _WIN32
+       static int done = 0;
+#endif
        compiler_state_t cstate;
        const char * volatile xbuf = buf;
        yyscan_t scanner = NULL;
@@ -665,14 +674,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        u_int len;
        int  rc;
 
-#ifdef _WIN32
-       static int done = 0;
-
-       if (!done)
-               pcap_wsockinit();
-       done = 1;
-#endif
-
        /*
         * If this pcap_t hasn't been activated, it doesn't have a
         * link-layer type, so we can't use it.
@@ -680,12 +681,41 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        if (!p->activated) {
                pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "not-yet-activated pcap_t passed to pcap_compile");
-               rc = -1;
-               goto quit;
+               return (-1);
        }
+
+#ifdef _WIN32
+       if (!done)
+               pcap_wsockinit();
+       done = 1;
+#endif
+
+#ifdef HAVE_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.ic.root = NULL;
        cstate.ic.cur_mark = 0;
        cstate.bpf_pcap = p;
@@ -1107,7 +1137,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 * SLIP doesn't have a link level type.  The 16 byte
                 * header is hacked into our SLIP driver.
                 */
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 16;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
@@ -1115,7 +1145,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
 
        case DLT_SLIP_BSDOS:
                /* XXX this may be the same as the DLT_PPP_BSDOS case */
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                /* XXX end */
                cstate->off_linkpl.constant_part = 24;
                cstate->off_nl = 0;
@@ -1301,7 +1331,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        case DLT_RAW:
        case DLT_IPV4:
        case DLT_IPV6:
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 0;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
@@ -1320,7 +1350,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 * but really it just indicates whether there is a "short" or
                 * "long" DDP packet following.
                 */
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 0;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
@@ -1348,7 +1378,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 * XXX - we should set this to handle SNAP-encapsulated
                 * frames (NLPID of 0x80).
                 */
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 0;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;      /* no 802.2 LLC */
@@ -1360,7 +1390,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                  * so lets start with offset 4 for now and increments later on (FIXME);
                  */
        case DLT_MFR:
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 0;
                cstate->off_nl = 4;
                cstate->off_nl_nosnap = 0;      /* XXX - for now -> no 802.2 LLC */
@@ -1441,7 +1471,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
 
        case DLT_JUNIPER_ES:
                cstate->off_linktype.constant_part = 6;
-               cstate->off_linkpl.constant_part = -1;  /* not really a network layer but raw IP addresses */
+               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 */
                break;
@@ -1454,36 +1484,36 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                break;
 
        case DLT_BACNET_MS_TP:
-               cstate->off_linktype.constant_part = -1;
-               cstate->off_linkpl.constant_part = -1;
+               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;
                break;
 
        case DLT_JUNIPER_SERVICES:
                cstate->off_linktype.constant_part = 12;
-               cstate->off_linkpl.constant_part = -1;  /* L3 proto location dep. on cookie type */
+               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 */
                break;
 
        case DLT_JUNIPER_VP:
                cstate->off_linktype.constant_part = 18;
-               cstate->off_linkpl.constant_part = -1;
+               cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
                cstate->off_nl = -1;
                cstate->off_nl_nosnap = -1;
                break;
 
        case DLT_JUNIPER_ST:
                cstate->off_linktype.constant_part = 18;
-               cstate->off_linkpl.constant_part = -1;
+               cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
                cstate->off_nl = -1;
                cstate->off_nl_nosnap = -1;
                break;
 
        case DLT_JUNIPER_ISM:
                cstate->off_linktype.constant_part = 8;
-               cstate->off_linkpl.constant_part = -1;
+               cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
                cstate->off_nl = -1;
                cstate->off_nl_nosnap = -1;
                break;
@@ -1493,7 +1523,7 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
        case DLT_JUNIPER_FIBRECHANNEL:
        case DLT_JUNIPER_ATM_CEMIC:
                cstate->off_linktype.constant_part = 8;
-               cstate->off_linkpl.constant_part = -1;
+               cstate->off_linkpl.constant_part = OFFSET_NOT_SET;
                cstate->off_nl = -1;
                cstate->off_nl_nosnap = -1;
                break;
@@ -1505,8 +1535,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_opc = 4;
                cstate->off_dpc = 4;
                cstate->off_sls = 7;
-               cstate->off_linktype.constant_part = -1;
-               cstate->off_linkpl.constant_part = -1;
+               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;
                break;
@@ -1518,8 +1548,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_opc = 8;
                cstate->off_dpc = 8;
                cstate->off_sls = 11;
-               cstate->off_linktype.constant_part = -1;
-               cstate->off_linkpl.constant_part = -1;
+               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;
                break;
@@ -1531,14 +1561,14 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                cstate->off_opc = 24;
                cstate->off_dpc = 24;
                cstate->off_sls = 27;
-               cstate->off_linktype.constant_part = -1;
-               cstate->off_linkpl.constant_part = -1;
+               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;
                break;
 
        case DLT_PFSYNC:
-               cstate->off_linktype.constant_part = -1;
+               cstate->off_linktype.constant_part = OFFSET_NOT_SET;
                cstate->off_linkpl.constant_part = 4;
                cstate->off_nl = 0;
                cstate->off_nl_nosnap = 0;
@@ -1548,8 +1578,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                /*
                 * Currently, only raw "link[N:M]" filtering is supported.
                 */
-               cstate->off_linktype.constant_part = -1;        /* variable, min 15, max 71 steps of 7 */
-               cstate->off_linkpl.constant_part = -1;
+               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 */
                break;
@@ -1584,8 +1614,8 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
                 */
                if (cstate->linktype >= DLT_MATCHING_MIN &&
                    cstate->linktype <= DLT_MATCHING_MAX) {
-                       cstate->off_linktype.constant_part = -1;
-                       cstate->off_linkpl.constant_part = -1;
+                       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;
                } else {
@@ -1989,6 +2019,41 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
        }
 }
 
+static struct block *
+gen_loopback_linktype(compiler_state_t *cstate, int proto)
+{
+       /*
+        * For DLT_NULL, the link-layer header is a 32-bit word
+        * containing an AF_ value in *host* byte order, and for
+        * DLT_ENC, the link-layer header begins with a 32-bit
+        * word containing an AF_ value in host byte order.
+        *
+        * In addition, if we're reading a saved capture file,
+        * the host byte order in the capture may not be the
+        * same as the host byte order on this machine.
+        *
+        * For DLT_LOOP, the link-layer header is a 32-bit
+        * word containing an AF_ value in *network* byte order.
+        */
+       if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
+               /*
+                * The AF_ value is in host byte order, but the BPF
+                * interpreter will convert it to network byte order.
+                *
+                * If this is a save file, and it's from a machine
+                * with the opposite byte order to ours, we byte-swap
+                * the AF_ value.
+                *
+                * Then we run it through "htonl()", and generate
+                * code to compare against the result.
+                */
+               if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
+                       proto = SWAPLONG(proto);
+               proto = htonl(proto);
+       }
+       return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
+}
+
 /*
  * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
  * or IPv6 then we have an error.
@@ -2925,6 +2990,14 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
        /*NOTREACHED*/
 }
 
+/*
+ * The three different values we should check for when checking for an
+ * IPv6 packet with DLT_NULL.
+ */
+#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 */
+
 /*
  * Generate code to match a particular packet type by matching the
  * link-layer type field or fields in the 802.2 LLC header.
@@ -3145,39 +3218,71 @@ gen_linktype(compiler_state_t *cstate, int proto)
        case DLT_NULL:
        case DLT_LOOP:
        case DLT_ENC:
-               /*
-                * For DLT_NULL, the link-layer header is a 32-bit
-                * word containing an AF_ value in *host* byte order,
-                * and for DLT_ENC, the link-layer header begins
-                * with a 32-bit work containing an AF_ value in
-                * host byte order.
-                *
-                * In addition, if we're reading a saved capture file,
-                * the host byte order in the capture may not be the
-                * same as the host byte order on this machine.
-                *
-                * For DLT_LOOP, the link-layer header is a 32-bit
-                * word containing an AF_ value in *network* byte order.
-                *
-                * XXX - AF_ values may, unfortunately, be platform-
-                * dependent; for example, FreeBSD's AF_INET6 is 24
-                * whilst NetBSD's and OpenBSD's is 26.
-                *
-                * This means that, when reading a capture file, just
-                * checking for our AF_INET6 value won't work if the
-                * capture file came from another OS.
-                */
                switch (proto) {
 
                case ETHERTYPE_IP:
-                       proto = AF_INET;
-                       break;
+                       return (gen_loopback_linktype(cstate, AF_INET));
 
-#ifdef INET6
                case ETHERTYPE_IPV6:
-                       proto = AF_INET6;
-                       break;
-#endif
+                       /*
+                        * AF_ values may, unfortunately, be platform-
+                        * dependent; AF_INET isn't, because everybody
+                        * used 4.2BSD's value, but AF_INET6 is, because
+                        * 4.2BSD didn't have a value for it (given that
+                        * IPv6 didn't exist back in the early 1980's),
+                        * and they all picked their own values.
+                        *
+                        * This means that, if we're reading from a
+                        * savefile, we need to check for all the
+                        * possible values.
+                        *
+                        * If we're doing a live capture, we only need
+                        * to check for this platform's value; however,
+                        * Npcap uses 24, which isn't Windows's AF_INET6
+                        * value.  (Given the multiple different values,
+                        * programs that read pcap files shouldn't be
+                        * checking for their platform's AF_INET6 value
+                        * anyway, they should check for all of the
+                        * possible values. and they might as well do
+                        * that even for live captures.)
+                        */
+                       if (cstate->bpf_pcap->rfile != NULL) {
+                               /*
+                                * Savefile - check for all three
+                                * possible IPv6 values.
+                                */
+                               b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD);
+                               b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD);
+                               gen_or(b0, b1);
+                               b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN);
+                               gen_or(b0, b1);
+                               return (b1);
+                       } else {
+                               /*
+                                * Live capture, so we only need to
+                                * check for the value used on this
+                                * platform.
+                                */
+#ifdef _WIN32
+                               /*
+                                * Npcap doesn't use Windows's AF_INET6,
+                                * as that collides with AF_IPX on
+                                * some BSDs (both have the value 23).
+                                * Instead, it uses 24.
+                                */
+                               return (gen_loopback_linktype(cstate, 24));
+#else /* _WIN32 */
+#ifdef AF_INET6
+                               return (gen_loopback_linktype(cstate, AF_INET6));
+#else /* AF_INET6 */
+                               /*
+                                * I guess this platform doesn't support
+                                * IPv6, so we just reject all packets.
+                                */
+                               return gen_false(cstate);
+#endif /* AF_INET6 */
+#endif /* _WIN32 */
+                       }
 
                default:
                        /*
@@ -3188,25 +3293,6 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return gen_false(cstate);
                }
 
-               if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
-                       /*
-                        * The AF_ value is in host byte order, but
-                        * the BPF interpreter will convert it to
-                        * network byte order.
-                        *
-                        * If this is a save file, and it's from a
-                        * machine with the opposite byte order to
-                        * ours, we byte-swap the AF_ value.
-                        *
-                        * Then we run it through "htonl()", and
-                        * generate code to compare against the result.
-                        */
-                       if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
-                               proto = SWAPLONG(proto);
-                       proto = htonl(proto);
-               }
-               return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
-
 #ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                /*
@@ -3428,9 +3514,9 @@ gen_linktype(compiler_state_t *cstate, int proto)
                 * Does this link-layer header type have a field
                 * indicating the type of the next protocol?  If
                 * so, off_linktype.constant_part will be the offset of that
-                * field in the packet; if not, it will be -1.
+                * field in the packet; if not, it will be OFFSET_NOT_SET.
                 */
-               if (cstate->off_linktype.constant_part != (u_int)-1) {
+               if (cstate->off_linktype.constant_part != OFFSET_NOT_SET) {
                        /*
                         * Yes; assume it's an Ethernet type.  (If
                         * it's not, it needs to be handled specially
@@ -4841,11 +4927,8 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr,
 
 #ifndef INET6
 static struct block *
-gen_gateway(eaddr, alist, proto, dir)
-       const u_char *eaddr;
-       bpf_u_int32 **alist;
-       int proto;
-       int dir;
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist,
+    int proto, int dir)
 {
        struct block *b0, *b1, *tmp;
 
@@ -6248,7 +6331,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                        if (alist == NULL || *alist == NULL)
                                bpf_error(cstate, "unknown host '%s'", name);
                        tproto = proto;
-                       if (cstate->off_linktype.constant_part == (u_int)-1 &&
+                       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);
@@ -6267,7 +6350,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                        cstate->ai = res;
                        b = tmp = NULL;
                        tproto = tproto6 = proto;
-                       if (cstate->off_linktype.constant_part == -1 &&
+                       if (cstate->off_linktype.constant_part == OFFSET_NOT_SET &&
                            tproto == Q_DEFAULT) {
                                tproto = Q_IP;
                                tproto6 = Q_IPV6;
@@ -6409,7 +6492,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                alist = pcap_nametoaddr(name);
                if (alist == NULL || *alist == NULL)
                        bpf_error(cstate, "unknown host '%s'", name);
-               b = gen_gateway(eaddr, alist, proto, dir);
+               b = gen_gateway(cstate, eaddr, alist, proto, dir);
                free(eaddr);
                return b;
 #else