Narrow the BPF read filter rules so only packets sent to the
authorkrw <krw@openbsd.org>
Tue, 19 Jul 2016 17:23:20 +0000 (17:23 +0000)
committerkrw <krw@openbsd.org>
Tue, 19 Jul 2016 17:23:20 +0000 (17:23 +0000)
interface's LLADDR pass. Rely on dhclient's existing ability to
detect and react to LLADDR changes.

This limits the number of packets that get dropped as a result of
dhclient setting BIOCSFILDROP on the bpf descriptor.

Problem with bridges and multiple dhclients noted by stsp@.

ok mpi@ stsp@ deraadt@ henning@

sbin/dhclient/bpf.c
sbin/dhclient/dhclient.c

index 8185bd9..379af94 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bpf.c,v 1.40 2016/05/08 08:20:50 natano Exp $ */
+/*     $OpenBSD: bpf.c,v 1.41 2016/07/19 17:23:20 krw Exp $    */
 
 /* BPF socket interface code, originally contributed by Archie Cobbs. */
 
@@ -114,8 +114,27 @@ if_register_send(void)
  *
  * XXX: Changes to the filter program may require changes to the
  * constant offsets used in if_register_receive to patch the BPF program!
+ *
+ * Adapted from script shown by
+ *
+ * tcpdump -d 'ether dst 00:00:00:00:00:00 ip proto \udp dst port 67'
+ *
+ * NOTE: tcpdump shows absolute jumps and relative jumps are required here!
  */
 struct bpf_insn dhcp_bpf_filter[] = {
+       /*
+        * Make sure this is directed to our MAC.
+        *     a) compare last 4 octets
+        *     b) compare first 2 octets
+        *
+        * NOTE: MAC value must be patched in!
+        */
+
+       BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 2),
+       BPF_JUMP(BPF_JMP + BPF_JEQ +  BPF_K, 0x00000000, 0, 12), /* patch */
+       BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 0),
+       BPF_JUMP(BPF_JMP + BPF_JEQ +  BPF_K, 0x0000, 0, 10), /* patch */
+
        /* Make sure this is an IP packet. */
        BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
        BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
@@ -190,6 +209,8 @@ if_register_receive(void)
        struct bpf_version v;
        struct bpf_program p;
        int flag = 1, sz;
+       uint32_t bits;
+       uint16_t bits16;
 
        /* Open a BPF device and hang it on this interface. */
        ifi->bfdesc = if_register_bpf();
@@ -235,7 +256,13 @@ if_register_receive(void)
         * XXX: changes to filter program may require changes to the
         * insn number(s) used below!
         */
-       dhcp_bpf_filter[8].k = LOCAL_PORT;
+       memcpy(&bits, ((uint8_t *)&ifi->hw_address) + 2, sizeof(bits));
+       dhcp_bpf_filter[1].k = ntohl(bits);
+
+       memcpy(&bits16, ((uint8_t *)&ifi->hw_address), sizeof(bits16));
+       dhcp_bpf_filter[3].k = ntohs(bits16);
+
+       dhcp_bpf_filter[12].k = LOCAL_PORT;
 
        if (ioctl(ifi->bfdesc, BIOCSETF, &p) < 0)
                error("Can't install packet filter program: %s",
index f4d98ac..7f89b1d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: dhclient.c,v 1.373 2016/04/28 17:34:49 krw Exp $      */
+/*     $OpenBSD: dhclient.c,v 1.374 2016/07/19 17:23:20 krw Exp $      */
 
 /*
  * Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -603,6 +603,7 @@ main(int argc, char *argv[])
                error("setsockopt(ROUTE_TABLEFILTER): %s", strerror(errno));
 
        /* Register the interface. */
+       get_hw_address();
        if_register_receive();
        if_register_send();