Patchwork [next] utils: bpf_compile

login
register
mail settings
Submitter Willem de Bruijn
Date March 12, 2013, 3:44 p.m.
Message ID <1363103052-5529-1-git-send-email-willemb@google.com>
Download mbox | patch
Permalink /patch/227056/
State Accepted
Headers show

Comments

Willem de Bruijn - March 12, 2013, 3:44 p.m.
V2
- update build process to
  - succeed without bpf_compiler when --enable-bpf-compiler is not set
  - succeed with bpf_compiler when this flag is set and libpcap is found
  - fail when this flag is set but libpcap is absent
- release memory allocated by pcap on exit

A BPF compiler to convert tcpudmp expressions to the decimal format accepted
by the libxt_bpf.

Generate a file and pass that to iptables:

  bpf_compile RAW 'udp dst port 9000' > test.bpf
  iptables -A OUTPUT -m bpf --bytecode-file test.bpf -j LOG

Or pass the output directly to iptables using backticks:

  iptables -A INPUT -m bpf --bytecode \
      "`./bpf_compile RAW 'udp dst port 9000' | tr '\n' ','`" -j LOG

This utility depends on libpcap. The library is only compiled if the option
--enable-pcap is explicitly passed to ./configure and libpcap is found.

Tested (for review: to be removed before merging):

- compilation always succeeds.
  - utils/bpf_compile is only built when enable_pcap is true and libpcap is found
  - utils/nfnl_osf is (still) only built when nfnetlink library is found

- execution
  - tested the above two expressions and verified dmesg output

- logging
  - iptables -L INPUT
"
LOG        all  --  anywhere             anywhere            match bpf 48 0 0
0,84 0 0 240,21 0 4 96,48 0 0 6,21 0 13 17,40 0 0 42,21 10 11 9000,48 0 0 0,84
0 0 240,21 0 8 64,48 0 0 9,21 0 6 17,40 0 0 6,69 4 0 8191,177 0 0 0,72 0 0
  2,21 0 1 9000,6 0 0 65535,6 0 0 0, LOG level warning
"

  - iptables-save
"
-A INPUT -m bpf --bytecode "19,48 0 0 0,84 0 0 240,21 0 4 96,48 0 0 6,21 0
13 17,40 0 0 42,21 10 11 9000,48 0 0 0,84 0 0 240,21 0 8 64,48 0 0 9,21 0
6 17,40 0 0 6,69 4 0 8191,177 0 0 0,72 0 0 2,21 0 1 9000,6 0 0 65535,6
0 0 0," -j LOG
"

Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 Makefile.am         |  2 --
 configure.ac        |  4 ++++
 utils/Makefile.am   | 14 ++++++++++++--
 utils/bpf_compile.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 72 insertions(+), 4 deletions(-)
 create mode 100644 utils/bpf_compile.c
Pablo Neira - April 1, 2013, 10:20 p.m.
On Tue, Mar 12, 2013 at 11:44:12AM -0400, Willem de Bruijn wrote:
> V2
> - update build process to
>   - succeed without bpf_compiler when --enable-bpf-compiler is not set
>   - succeed with bpf_compiler when this flag is set and libpcap is found
>   - fail when this flag is set but libpcap is absent
> - release memory allocated by pcap on exit

Applied with changes:

* renamed utility to add the `nf' prefix.

* the output of the utility is now exactly what iptables -m bpf --bytecode
  needs, just to make it easier to everyone.

Still missing a hard fail if --enable-bpf-compiler is set and libpcap
is not available in the system, I'd appreciate if you send me a follow
up patch to address this. You may want to have a look at how ulogd2
does this in its configure fail as reference.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Willem de Bruijn - April 3, 2013, 3:32 p.m.
On Mon, Apr 1, 2013 at 6:20 PM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Tue, Mar 12, 2013 at 11:44:12AM -0400, Willem de Bruijn wrote:
>> V2
>> - update build process to
>>   - succeed without bpf_compiler when --enable-bpf-compiler is not set
>>   - succeed with bpf_compiler when this flag is set and libpcap is found
>>   - fail when this flag is set but libpcap is absent
>> - release memory allocated by pcap on exit
>
> Applied with changes:

Thanks, Pablo.

> * renamed utility to add the `nf' prefix.
>
> * the output of the utility is now exactly what iptables -m bpf --bytecode
>   needs, just to make it easier to everyone.
>
> Still missing a hard fail if --enable-bpf-compiler is set and libpcap
> is not available in the system,

Compilation and linking will both fail hard:

if gcc -DHAVE_CONFIG_H -I. -I. -I..  -D_LARGEFILE_SOURCE=1
-D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT
-DXTABLES_LIBDIR=\"/usr/local/lib/xtables\" -DXTABLES_INTERNAL
-I../include -I../include   -Wall -Waggregate-return
-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow
-Wstrict-prototypes -Winline -pipe -g -O2 -MT nfbpf_compile.o -MD -MP
-MF ".deps/nfbpf_compile.Tpo" -c -o nfbpf_compile.o nfbpf_compile.c; \
then mv -f ".deps/nfbpf_compile.Tpo" ".deps/nfbpf_compile.Po"; else rm
-f ".deps/nfbpf_compile.Tpo"; exit 1; fi
nfbpf_compile.c:12:18: fatal error: pcap.h: No such file or directory
compilation terminated.
make: *** [nfbpf_compile.o] Error 1

Do you want the configure script itself to fail before that step?

> I'd appreciate if you send me a follow
> up patch to address this. You may want to have a look at how ulogd2
> does this in its configure fail as reference.

That skips compilation if HAVE_PCAP is false, but it does not fail
hard during configure, either. At least, that's what I gather from
reading and running

https://git.netfilter.org/ulogd2/tree/configure.ac#n23
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pablo Neira - April 4, 2013, 9:34 a.m.
On Wed, Apr 03, 2013 at 11:32:13AM -0400, Willem de Bruijn wrote:
[...]
> > Still missing a hard fail if --enable-bpf-compiler is set and libpcap
> > is not available in the system,
> 
> Compilation and linking will both fail hard:
> 
> if gcc -DHAVE_CONFIG_H -I. -I. -I..  -D_LARGEFILE_SOURCE=1
> -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT
> -DXTABLES_LIBDIR=\"/usr/local/lib/xtables\" -DXTABLES_INTERNAL
> -I../include -I../include   -Wall -Waggregate-return
> -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wshadow
> -Wstrict-prototypes -Winline -pipe -g -O2 -MT nfbpf_compile.o -MD -MP
> -MF ".deps/nfbpf_compile.Tpo" -c -o nfbpf_compile.o nfbpf_compile.c; \
> then mv -f ".deps/nfbpf_compile.Tpo" ".deps/nfbpf_compile.Po"; else rm
> -f ".deps/nfbpf_compile.Tpo"; exit 1; fi
> nfbpf_compile.c:12:18: fatal error: pcap.h: No such file or directory
> compilation terminated.
> make: *** [nfbpf_compile.o] Error 1
> 
> Do you want the configure script itself to fail before that step?

Yes. It should hard fail if --enable-bpf-compiler is set and libpcap
is not available.

> > I'd appreciate if you send me a follow
> > up patch to address this. You may want to have a look at how ulogd2
> > does this in its configure fail as reference.
> 
> That skips compilation if HAVE_PCAP is false, but it does not fail
> hard during configure, either. At least, that's what I gather from
> reading and running
> 
> https://git.netfilter.org/ulogd2/tree/configure.ac#n23

Just pointed to that chunk of code so you can use it as base, you'll
have to adapt it to achieve the behaviour we want, of course.

Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/Makefile.am b/Makefile.am
index 6400ba4..c38d360 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,9 +10,7 @@  endif
 if ENABLE_LIBIPQ
 SUBDIRS         += libipq
 endif
-if HAVE_LIBNFNETLINK
 SUBDIRS         += utils
-endif
 # Depends on libxtables:
 SUBDIRS         += extensions
 # Depends on extensions/libext.a:
diff --git a/configure.ac b/configure.ac
index 27e0b10..e5cfb12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,6 +50,9 @@  AC_ARG_ENABLE([devel],
 	[enable_devel="$enableval"], [enable_devel="yes"])
 AC_ARG_ENABLE([libipq],
 	AS_HELP_STRING([--enable-libipq], [Build and install libipq]))
+AC_ARG_ENABLE([bpf-compiler],
+	AS_HELP_STRING([--enable-bpf-compiler], [Build bpf compiler]),
+	[enable_bpfc="yes"])
 AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
 	[Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
 	[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
@@ -88,6 +91,7 @@  AM_CONDITIONAL([ENABLE_IPV6], [test "$enable_ipv6" = "yes"])
 AM_CONDITIONAL([ENABLE_LARGEFILE], [test "$enable_largefile" = "yes"])
 AM_CONDITIONAL([ENABLE_DEVEL], [test "$enable_devel" = "yes"])
 AM_CONDITIONAL([ENABLE_LIBIPQ], [test "$enable_libipq" = "yes"])
+AM_CONDITIONAL([ENABLE_BPFC], [test "$enable_bpfc" = "yes"])
 
 PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0],
 	[nfnetlink=1], [nfnetlink=0])
diff --git a/utils/Makefile.am b/utils/Makefile.am
index f1bbfc5..8b510d6 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -4,7 +4,17 @@  AM_CFLAGS = ${regular_CFLAGS}
 AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \
               -I${top_srcdir}/include ${libnfnetlink_CFLAGS}
 
-sbin_PROGRAMS = nfnl_osf
-pkgdata_DATA = pf.os
+sbin_PROGRAMS =
+pkgdata_DATA =
+
+if HAVE_LIBNFNETLINK
+sbin_PROGRAMS += nfnl_osf
+pkgdata_DATA += pf.os
 
 nfnl_osf_LDADD = -lnfnetlink
+endif
+
+if ENABLE_BPFC
+sbin_PROGRAMS += bpf_compile
+bpf_compile_LDADD = -lpcap
+endif
diff --git a/utils/bpf_compile.c b/utils/bpf_compile.c
new file mode 100644
index 0000000..81b59a4
--- /dev/null
+++ b/utils/bpf_compile.c
@@ -0,0 +1,56 @@ 
+/*
+ * BPF program compilation tool
+ *
+ * Generates decimal output, similar to `tcpdump -ddd ...`.
+ * Unlike tcpdump, will generate for any given link layer type.
+ *
+ * There is no makefile:
+ * compile with `gcc -Wall -o bpf2decimal bpf2decimal.c -lpcap` or similar.
+ *
+ * Written by Willem de Bruijn (willemb@google.com)
+ * Copyright Google, Inc. 2013
+ * Licensed under the GNU General Public License version 2 (GPLv2)
+*/
+
+#include <pcap.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	struct bpf_program program;
+	struct bpf_insn *ins;
+	int i, dlt = DLT_RAW;
+
+	if (argc < 2 || argc > 3) {
+		fprintf(stderr, "Usage:    %s [link] '<program>'\n\n"
+				"          link is a pcap linklayer type:\n"
+				"          one of EN10MB, RAW, SLIP, ...\n\n"
+				"Examples: %s RAW 'tcp and greater 100'\n"
+				"          %s EN10MB 'ip proto 47'\n'",
+				argv[0], argv[0], argv[0]);
+		return 1;
+	}
+
+	if (argc == 3) {
+		dlt = pcap_datalink_name_to_val(argv[1]);
+		if (dlt == -1) {
+			fprintf(stderr, "Unknown datalinktype: %s\n", argv[1]);
+			return 1;
+		}
+	}
+
+	if (pcap_compile_nopcap(65535, dlt, &program, argv[argc - 1], 1,
+				PCAP_NETMASK_UNKNOWN)) {
+		fprintf(stderr, "Compilation error\n");
+		return 1;
+	}
+
+	printf("%d\n", program.bf_len);
+	ins = program.bf_insns;
+	for (i = 0; i < program.bf_len; ++ins, ++i)
+		printf("%u %u %u %u\n", ins->code, ins->jt, ins->jf, ins->k);
+
+	pcap_freecode(&program);
+	return 0;
+}
+