]> The Tcpdump Group git mirrors - libpcap/commitdiff
filtertest: Add "-l" flag to use Linux BPF extensions.
authorDenis Ovsienko <[email protected]>
Fri, 24 Jan 2025 22:21:51 +0000 (22:21 +0000)
committerDenis Ovsienko <[email protected]>
Sat, 25 Jan 2025 11:56:04 +0000 (11:56 +0000)
filtertest prints what pcap_compile() produces for a pcap_t from
pcap_open_dead(), which is not suitable for Linux BPF extensions, so in
theory the output should never include any absolute addresses formatted
as names in square brackets ([ifindex], [vlanp], etc.).  In practice it
sometimes does, which means such tests do not cover the intended part of
the problem space (bytecode without the extensions).  Another problem
is, bytecode with the extensions is a sound part of the problem space
too, so ideally the filter tests should completely and separately cover
each part.

To begin untangling this, add a Linux-specfic flag to filtertest to make
it clear whether the bytecode is meant to use the extensions.  It has
the correct effect on the "vlan" keyword already and there are VLAN
tests without the extensions already, so add VLAN tests for bytecode
with the extensions and get both versions tested at basic level.

CHANGES
testprogs/TESTrun
testprogs/filtertest.c

diff --git a/CHANGES b/CHANGES
index 75fcd17ef6e6bd346a49df7c1c9a3231a90333cf..32fa61f0e819f3e382ce4ff8230298480fa1366f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -89,6 +89,7 @@ DayOfTheWeek, Month DD, YYYY / The Tcpdump Group
       CI: Implement "make check".
       Fix autotools and CMake issues with snprintf test and sanitizers.
         Fixes issue #1396.
+      filtertest: Add "-l" flag to use Linux BPF extensions.
     Hurd:
       Support network capture devices too.
       Fix a few device activation bugs.
index f7032c8abd739969154310004dfc4354a417bafa..ec9f36e1557a0bf975756193940b4512642837cf 100755 (executable)
@@ -112,6 +112,8 @@ sub is_not_linux {
 #   "unopt" separately)
 # * skip (optional, string): if defined and is not equal to an empty string,
 #   causes the test to skip using the string as the reason
+# * linuxext (optional, int): if defined and is equal to 1, use Linux BPF
+#   extensions.
 #
 # At least one of "opt" and "unopt" must be defined in each accept test block.
 
@@ -1921,6 +1923,70 @@ my %accept_blocks = (
                        (008) ret      #0
                        EOF
        }, # vlan_netanalyzer_unary
+       vlan_eth_linuxext_nullary => {
+               skip => is_not_linux(),
+               DLT => 'EN10MB',
+               linuxext => 1,
+               expr => 'vlan',
+               opt => <<~'EOF',
+                       (000) ldb      [vlanp]
+                       (001) jeq      #0x1             jt 6    jf 2
+                       (002) ldh      [12]
+                       (003) jeq      #0x8100          jt 6    jf 4
+                       (004) jeq      #0x88a8          jt 6    jf 5
+                       (005) jeq      #0x9100          jt 6    jf 7
+                       (006) ret      #262144
+                       (007) ret      #0
+                       EOF
+       }, # vlan_eth_linuxext_nullary
+       vlan_eth_linuxext_unary => {
+               skip => is_not_linux(),
+               DLT => 'EN10MB',
+               linuxext => 1,
+               expr => 'vlan 10',
+               opt => <<~'EOF',
+                       (000) ldb      [vlanp]
+                       (001) jeq      #0x1             jt 6    jf 2
+                       (002) ldh      [12]
+                       (003) jeq      #0x8100          jt 6    jf 4
+                       (004) jeq      #0x88a8          jt 6    jf 5
+                       (005) jeq      #0x9100          jt 6    jf 14
+                       (006) ldb      [vlanp]
+                       (007) jeq      #0x1             jt 8    jf 10
+                       (008) ldh      [vlan_tci]
+                       (009) ja       11
+                       (010) ldh      [14]
+                       (011) and      #0xfff
+                       (012) jeq      #0xa             jt 13   jf 14
+                       (013) ret      #262144
+                       (014) ret      #0
+                       EOF
+       }, # vlan_eth_linuxext_unary
+       vlan_and_vlan_eth_linuxext => {
+               skip => is_not_linux(),
+               DLT => 'EN10MB',
+               linuxext => 1,
+               expr => 'vlan and vlan',
+               opt => <<~'EOF',
+                       (000) ld       #0x0
+                       (001) st       M[1]
+                       (002) ldb      [vlanp]
+                       (003) jeq      #0x1             jt 10   jf 4
+                       (004) ld       #0x4
+                       (005) st       M[1]
+                       (006) ldh      [12]
+                       (007) jeq      #0x8100          jt 10   jf 8
+                       (008) jeq      #0x88a8          jt 10   jf 9
+                       (009) jeq      #0x9100          jt 10   jf 16
+                       (010) ldx      M[1]
+                       (011) ldh      [x + 12]
+                       (012) jeq      #0x8100          jt 15   jf 13
+                       (013) jeq      #0x88a8          jt 15   jf 14
+                       (014) jeq      #0x9100          jt 15   jf 16
+                       (015) ret      #262144
+                       (016) ret      #0
+                       EOF
+       }, # vlan_and_vlan_eth_linuxext
 
        mpls_eth_nullary => {
                DLT => 'EN10MB',
@@ -5859,6 +5925,7 @@ sub run_accept_test {
        push @args, $filtertest;
        push @args, ('-s', $test{snaplen}) if defined $test{snaplen};
        push @args, '-O' unless $test{optimize};
+       push @args, '-l' if $test{linuxext};
        # Write the filter expression to a file because the version of
        # system() that takes a list does not support redirecting stdout,
        # and the version of system() that takes a string does not escape
@@ -6003,6 +6070,7 @@ foreach my $testname (sort keys %accept_blocks) {
                                func => \&run_accept_test,
                                snaplen => defined $test->{snaplen} ? $test->{snaplen} : undef,
                                optimize => int ($optunopt eq 'opt'),
+                               linuxext => defined $test->{linuxext} && $test->{linuxext} == 1,
                                expected => $test->{$optunopt},
                        };
                        $main->{$_} = $test->{$_} foreach ('DLT', 'expr');
@@ -6013,7 +6081,7 @@ foreach my $testname (sort keys %accept_blocks) {
                                                label => valid_alias_label ($label, $i),
                                                expr => $test->{aliases}[$i],
                                        };
-                                       $alias->{$_} = $main->{$_} foreach ('DLT', 'func', 'optimize', 'expected', 'snaplen');
+                                       $alias->{$_} = $main->{$_} foreach ('DLT', 'func', 'optimize', 'expected', 'snaplen', 'linuxext');
                                        push @ready_to_run, $alias;
                                }
                        }
index 49a3b98ee03e80258547d2559010106c7c79f7f8..fd177b7d8da4c95c3d634cd761af73079f62e37b 100644 (file)
@@ -69,6 +69,20 @@ PCAP_API void pcap_set_optimizer_debug(int);
 PCAP_API void pcap_set_print_dot_graph(int);
 #endif
 
+#ifdef __linux__
+#include <linux/filter.h>
+#if defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT)
+/*
+ * pcap-int.h is a private header and should not be included by programs that
+ * use libpcap.  This test program uses a special hack because it is the
+ * simplest way to test internal code paths that otherwise would require
+ * elevated privileges.  Do not do this in normal code.
+ */
+#include <pcap-int.h>
+#define LINUX_BPF_EXT
+#endif // defined(SO_BPF_EXTENSIONS) && defined(SKF_AD_VLAN_TAG_PRESENT)
+#endif // __linux__
+
 static char *program_name;
 
 /* Forwards */
@@ -212,6 +226,9 @@ main(int argc, char **argv)
 #endif
        char *infile;
        int Oflag;
+#ifdef LINUX_BPF_EXT
+       int lflag = 0;
+#endif
        int snaplen;
        char *p;
        int dlt;
@@ -241,7 +258,7 @@ main(int argc, char **argv)
                program_name = argv[0];
 
        opterr = 0;
-       while ((op = getopt(argc, argv, "dF:gm:Os:")) != -1) {
+       while ((op = getopt(argc, argv, "dF:gm:Os:l")) != -1) {
                switch (op) {
 
                case 'd':
@@ -301,6 +318,15 @@ main(int argc, char **argv)
                        break;
                }
 
+               case 'l':
+#ifdef LINUX_BPF_EXT
+                       // Enable Linux BPF extensions.
+                       lflag = 1;
+                       break;
+#else
+                       error("libpcap and filtertest built without Linux BPF extensions");
+#endif
+
                default:
                        usage();
                        /* NOTREACHED */
@@ -333,6 +359,12 @@ main(int argc, char **argv)
        if (pd == NULL)
                error("Can't open fake pcap_t");
 
+#ifdef LINUX_BPF_EXT
+       if (lflag) {
+               pd->bpf_codegen_flags |= BPF_SPECIAL_VLAN_HANDLING;
+       }
+#endif
+
        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
                error("%s", pcap_geterr(pd));
 
@@ -369,11 +401,15 @@ usage(void)
        (void)fprintf(stderr, "%s, with %s\n", program_name,
            pcap_lib_version());
        (void)fprintf(stderr,
+           "Usage: %s [-d"
 #ifdef BDEBUG
-           "Usage: %s [-dgO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
-#else
-           "Usage: %s [-dO] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
+           "g"
+#endif
+           "O"
+#ifdef LINUX_BPF_EXT
+           "l"
 #endif
+           "] [ -F file ] [ -m netmask] [ -s snaplen ] dlt [ expression ]\n",
            program_name);
        exit(1);
 }