]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
BPF: Use pcap_setwritefilter() and pcap_lockfilter()
authorRoy Marples <roy@marples.name>
Sun, 17 May 2026 15:38:22 +0000 (16:38 +0100)
committerRoy Marples <roy@marples.name>
Sun, 17 May 2026 15:38:22 +0000 (16:38 +0100)
If available.
Upstream PR: https://github.com/the-tcpdump-group/libpcap/pull/1683

BUILDING.md
configure
src/bpf-bsd.c
src/bpf-linux.c
src/bpf-pcap.c
src/bpf.c
src/bpf.h

index 1b3fc700552f80d61dbad52f0a0a539c81a5c2eb..ee0ceb62a924f0b38544ceca2e86d24f481e166c 100644 (file)
@@ -143,6 +143,9 @@ Enable libpcap support with --with-libpcap.
 This should only be done on systems that lack the needed kernel hooks
 as libpcap does not support a write filter and is vulnerable
 if the application is exploited.
+An upstream PR has been submitted to add `pcap_setwritefilter()` and
+`pcap_lockfilter()` to libpcap:
+    https://github.com/the-tcpdump-group/libpcap/pull/1683
 
 ## Init systems
 We try and detect how dhcpcd should interact with system services at runtime.
index a1776e720b05af40e06e5d5dae6f5ab61105b0c7..fb5b5fff4b41360da22c458847c600e39f1bf772 100755 (executable)
--- a/configure
+++ b/configure
@@ -1524,8 +1524,6 @@ if [ "$LIBPCAP" = yes ]; then
                LIBPCAP_CFLAGS=$($PKG_CONFIG --cflags libpcap 2>/dev/null)
                LIBPCAP_LIBS=$($PKG_CONFIG --libs libpcap 2>/dev/null)
                echo "yes"
-               echo "CFLAGS+=  $LIBPCAP_CFLAGS" >>$CONFIG_MK
-               echo "LDADD+=           $LIBPCAP_LIBS" >>$CONFIG_MK
        else
                cat <<EOF >_libpcap.c
 #include <pcap.h>
@@ -1536,7 +1534,8 @@ int main(void) {
 EOF
                if $XCC _libpcap.c -o libpcap -lpcap 2>&3; then
                        echo "yes"
-                       echo "LDADD+=           -lpcap" >>$CONFIG_MK
+                       LIBPCAP_CFLAGS=
+                       LIBPCAP_LIBS="-lpcap"
                        abort=false
                else
                        echo "no"
@@ -1545,7 +1544,42 @@ EOF
                rm -f _libpcap.c libpcap
                $abort && exit 1
        fi
+       LIBPCAP_LIBS="-L/tmp/foo/usr/local/lib -lpcap"
+       echo "CFLAGS+=  $LIBPCAP_CFLAGS" >>$CONFIG_MK
+       echo "LDADD+=           $LIBPCAP_LIBS" >>$CONFIG_MK
        echo "#define   USE_LIBPCAP" >>$CONFIG_H
+
+       printf "Testing for pcap_setwritefilter() ... "
+       cat <<EOF >_libpcap_write.c
+#include <pcap.h>
+
+int main(void) {
+       return pcap_setwritefilter(NULL, NULL);
+}
+EOF
+       if $XCC $LIBPCAP_CFLAGS _libpcap_write.c -o libpcap_write $LIBPCAP_LIBS 2>&3; then
+               echo "yes"
+               echo "#define HAVE_PCAP_SETWRITEFILTER" >>$CONFIG_H
+       else
+               echo "no"
+       fi
+       rm -f _libpcap_write.c libpcap_write
+
+       printf "Testing for pcap_lockfilter() ... "
+       cat <<EOF >_libpcap_lock.c
+#include <pcap.h>
+
+int main(void) {
+       return pcap_lockfilter(NULL);
+}
+EOF
+       if $XCC $LIBPCAP_CFLAGS _libpcap_lock.c -o libpcap_lock $LIBPCAP_LIBS 2>&3; then
+               echo "yes"
+               echo "#define HAVE_PCAP_LOCKFILTER" >>$CONFIG_H
+       else
+               echo "no"
+       fi
+       rm -f _libpcap_lock.c libpcap_lock
 fi
 
 # Workaround for DragonFlyBSD import
index 5200c12a070eab30ab8cc984bdb5316f88696ac3..52503020731bc788671b604ed1c45172b9b56f76 100644 (file)
@@ -228,7 +228,7 @@ bpf_setwfilter(const struct bpf *bpf, void *filter, unsigned int filter_len)
 }
 
 int
-bpf_lock(const struct bpf *bpf)
+bpf_lockfilter(const struct bpf *bpf)
 {
 #ifdef BIOCLOCK
        return ioctl(bpf->bpf_fd, BIOCLOCK);
index aa0be5b4934ece72749818f3ef75fbdee91fbf63..2dc34111d095a6723ca8a62f4b4c018be9409b97 100644 (file)
@@ -192,7 +192,7 @@ bpf_setwfilter(__unused const struct bpf *bpf, __unused void *filter, __unused u
 }
 
 int
-bpf_lock(const struct bpf *bpf)
+bpf_lockfilter(const struct bpf *bpf)
 {
 #ifdef SO_LOCK_FILTER
        int fd = bpf->bpf_fd, on = 1;
index 931037a5e971a956cba891c6e6e945642aa921c6..7f0f08aac482e43c48fc5dd6072eef098d844a91 100644 (file)
 #define PCAP_CHECK(call, name)                                         \
        do {                                                           \
                int status = (call);                                   \
-               if (status < 0)                                        \
+               if (status < 0) {                                      \
                        logerrx("%s: %s failed: %s", __func__, name,   \
                            pcap_statustostr(status));                 \
-               else if (status > 0)                                   \
+                       goto eexit;                                    \
+               } else if (status > 0)                                 \
                        logwarnx("%s: %s warning: %s", __func__, name, \
                            pcap_statustostr(status));                 \
        } while (0)
@@ -52,7 +53,7 @@ const char *bpf_name = "Berkeley Packet Filter (libpcap)";
 struct bpf *
 bpf_open(const struct interface *ifp,
     int (*filter)(const struct bpf *, const struct in_addr *),
-    __unused const struct in_addr *ia)
+    const struct in_addr *ia)
 {
        int err;
        struct bpf *bpf;
@@ -80,7 +81,8 @@ bpf_open(const struct interface *ifp,
                goto eexit;
        }
 
-       PCAP_CHECK(pcap_set_snaplen(handle, (int)bpf->bpf_size), "pcap_set_snaplen");
+       PCAP_CHECK(pcap_set_snaplen(handle, (int)bpf->bpf_size),
+           "pcap_set_snaplen");
        PCAP_CHECK(pcap_set_promisc(handle, 0), "pcap_set_promisc");
        PCAP_CHECK(pcap_set_immediate_mode(handle, 1),
            "pcap_set_immediate_mode");
@@ -180,20 +182,33 @@ bpf_setfilter(const struct bpf *bpf, void *filter, unsigned int filter_len)
 }
 
 int
-bpf_setwfilter(__unused const struct bpf *bpf, __unused void *filter,
-    __unused unsigned int filter_len)
+bpf_setwfilter(const struct bpf *bpf, void *filter, unsigned int filter_len)
 {
+#ifdef HAVE_PCAP_SETWRITEFILTER
+       struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
+
+       return pcap_setwritefilter(bpf->bpf_handle, &pf);
+#else
 #warning A compromised libpcap socket can be used as a raw socket
 
+       UNUSED(bpf);
+       UNUSED(filter);
+       UNUSED(filter_len);
        errno = ENOSYS;
        return -1;
+#endif
 }
 
 int
-bpf_lock(__unused const struct bpf *bpf)
+bpf_lockfilter(const struct bpf *bpf)
 {
+#ifdef HAVE_PCAP_LOCKFILTER
+       return pcap_lockfilter(bpf->bpf_handle);
+#else
+       UNUSED(bpf);
        errno = ENOSYS;
        return -1;
+#endif
 }
 
 void
index 20032c9d4daef627d3e2a3dd6ac99bc428c9a0f8..19a0286a57556937834ddd41b35843a851ea7f12 100644 (file)
--- a/src/bpf.c
+++ b/src/bpf.c
@@ -375,7 +375,7 @@ bpf_filter_arp(const struct bpf *bpf, const struct in_addr *ia)
                return -1;
        if (bpf_arp_rw(bpf, ia, false) == -1 && errno != ENOSYS)
                return -1;
-       if (bpf_lock(bpf) == -1 && errno != ENOSYS)
+       if (bpf_lockfilter(bpf) == -1 && errno != ENOSYS)
                return -1;
        return 0;
 }
@@ -506,7 +506,7 @@ bpf_filter_bootp(const struct bpf *bpf, __unused const struct in_addr *ia)
                return -1;
        if (bpf_bootp_rw(bpf, false) == -1 && errno != ENOSYS)
                return -1;
-       if (bpf_lock(bpf) == -1 && errno != ENOSYS)
+       if (bpf_lockfilter(bpf) == -1 && errno != ENOSYS)
                return -1;
        return 0;
 }
index 97248ab91ad042de9611de5453993c9d99fb929d..3f309494b01a173c914685eda4bc2ca819582d4f 100644 (file)
--- a/src/bpf.h
+++ b/src/bpf.h
@@ -77,7 +77,7 @@ struct bpf *bpf_open(const struct interface *,
 void bpf_close(struct bpf *);
 int bpf_setfilter(const struct bpf *, void *, unsigned int);
 int bpf_setwfilter(const struct bpf *, void *, unsigned int);
-int bpf_lock(const struct bpf *);
+int bpf_lockfilter(const struct bpf *);
 ssize_t bpf_send(const struct bpf *, uint16_t, const void *, size_t);
 ssize_t bpf_writev(const struct bpf *, struct iovec *, int);
 ssize_t bpf_read(struct bpf *, void *, size_t);