]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: add libxt_bpf extension
authorWillem de Bruijn <willemb@google.com>
Wed, 23 Jan 2013 16:00:58 +0000 (16:00 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 1 Apr 2013 22:08:21 +0000 (00:08 +0200)
Add user-space code to support the new BPF iptables extension.

Pablo has mangled the original patch to:

* include a copy of include/linux/netfilter/xt_bpf.h in the tree.
* I have also remove the --bytecode-file option. The original
  proposal was to accept BPF code in a file in human readable
  format. Now, with the nfbpf_compile utility, it's very easy
  to generate the filter using tcpdump-like syntax.
* I have remove the trailing comma in the backtick format, the
  parser works just fine for me here.
* Fix error message if --bytecode is missing.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
extensions/libxt_bpf.c [new file with mode: 0644]
extensions/libxt_bpf.man [new file with mode: 0644]
include/linux/netfilter/xt_bpf.h [new file with mode: 0644]

diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
new file mode 100644 (file)
index 0000000..dca97d7
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Xtables BPF extension
+ *
+ * Written by Willem de Bruijn (willemb@google.com)
+ * Copyright Google, Inc. 2013
+ * Licensed under the GNU General Public License version 2 (GPLv2)
+*/
+
+#include <linux/netfilter/xt_bpf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <xtables.h>
+
+#define BCODE_FILE_MAX_LEN_B   1024
+
+enum {
+       O_BCODE_STDIN = 0,
+};
+
+static void bpf_help(void)
+{
+       printf(
+"bpf match options:\n"
+"--bytecode <program>  : a bpf program as generated by\n"
+"  `nfbpf_compiler RAW <filter>`\n");
+}
+
+static const struct xt_option_entry bpf_opts[] = {
+       {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
+       XTOPT_TABLEEND,
+};
+
+static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
+                            const char separator)
+{
+       struct xt_bpf_info *bi = (void *) cb->data;
+       const char *token;
+       char sp;
+       int i;
+
+       /* parse head: length. */
+       if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 ||
+                  sp != separator)
+               xtables_error(PARAMETER_PROBLEM,
+                             "bpf: error parsing program length");
+       if (!bi->bpf_program_num_elem)
+               xtables_error(PARAMETER_PROBLEM,
+                             "bpf: illegal zero length program");
+       if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR)
+               xtables_error(PARAMETER_PROBLEM,
+                             "bpf: number of instructions exceeds maximum");
+
+       /* parse instructions. */
+       i = 0;
+       token = bpf_program;
+       while ((token = strchr(token, separator)) && (++token)[0]) {
+               if (i >= bi->bpf_program_num_elem)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "bpf: real program length exceeds"
+                                     " the encoded length parameter");
+               if (sscanf(token, "%hu %hhu %hhu %u,",
+                          &bi->bpf_program[i].code,
+                          &bi->bpf_program[i].jt,
+                          &bi->bpf_program[i].jf,
+                          &bi->bpf_program[i].k) != 4)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "bpf: error at instr %d", i);
+               i++;
+       }
+
+       if (i != bi->bpf_program_num_elem)
+               xtables_error(PARAMETER_PROBLEM,
+                             "bpf: parsed program length is less than the"
+                             " encoded length parameter");
+}
+
+static void bpf_parse(struct xt_option_call *cb)
+{
+       xtables_option_parse(cb);
+       switch (cb->entry->id) {
+       case O_BCODE_STDIN:
+               bpf_parse_string(cb, cb->arg, ',');
+               break;
+       default:
+               xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
+       }
+}
+
+static void bpf_print_code(const void *ip, const struct xt_entry_match *match)
+{
+       const struct xt_bpf_info *info = (void *) match->data;
+       int i;
+
+       for (i = 0; i < info->bpf_program_num_elem-1; i++)
+               printf("%hu %hhu %hhu %u,", info->bpf_program[i].code,
+                                           info->bpf_program[i].jt,
+                                           info->bpf_program[i].jf,
+                                           info->bpf_program[i].k);
+
+       printf("%hu %hhu %hhu %u", info->bpf_program[i].code,
+                                   info->bpf_program[i].jt,
+                                   info->bpf_program[i].jf,
+                                   info->bpf_program[i].k);
+}
+
+static void bpf_save(const void *ip, const struct xt_entry_match *match)
+{
+       const struct xt_bpf_info *info = (void *) match->data;
+
+       printf(" --bytecode \"%hu,", info->bpf_program_num_elem);
+       bpf_print_code(ip, match);
+       printf("\"");
+}
+
+static void bpf_fcheck(struct xt_fcheck_call *cb)
+{
+       if (!(cb->xflags & (1 << O_BCODE_STDIN)))
+               xtables_error(PARAMETER_PROBLEM,
+                             "bpf: missing --bytecode parameter");
+}
+
+static void bpf_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+       printf("match bpf ");
+       return bpf_print_code(ip, match);
+}
+
+static struct xtables_match bpf_match = {
+       .family         = NFPROTO_UNSPEC,
+       .name           = "bpf",
+       .version        = XTABLES_VERSION,
+       .size           = XT_ALIGN(sizeof(struct xt_bpf_info)),
+       .userspacesize  = XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
+       .help           = bpf_help,
+       .print          = bpf_print,
+       .save           = bpf_save,
+       .x6_parse       = bpf_parse,
+       .x6_fcheck      = bpf_fcheck,
+       .x6_options     = bpf_opts,
+};
+
+void _init(void)
+{
+       xtables_register_match(&bpf_match);
+}
diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man
new file mode 100644 (file)
index 0000000..4120a23
--- /dev/null
@@ -0,0 +1,34 @@
+Match using Linux Socket Filter. Expects a BPF program in decimal format. This
+is the format generated by the \fBnfbpf_compile\fP utility.
+.TP
+\fB\-\-bytecode\fP \fIcode\fP
+Pass the code in backtick format as argument.
+.PP
+The code format is similar to the output of the tcpdump -ddd command: one line
+that stores the number of instructions, followed by one line for each
+instruction. Instruction lines follow the pattern 'u16 u8 u8 u32' in decimal
+notation. Fields encode the operation, jump offset if true, jump offset if
+false and generic multiuse field 'K'. Comments are not supported.
+.PP
+For example, to read only packets matching 'ip proto 6', insert the following,
+without the comments or trailing whitespace:
+.IP
+4               # number of instructions
+.br
+48 0 0 9        # load byte  ip->proto
+.br
+21 0 1 6        # jump equal IPPROTO_TCP
+.br
+6 0 0 1         # return     pass (non-zero)
+.br
+6 0 0 0         # return     fail (zero)
+.PP
+You can pass this filter to the bpf match with the following command:
+.IP
+iptables \-A OUTPUT \-m bpf \-\-bytecode '4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0' \-j ACCEPT
+.PP
+Or instead, you can invoke the nfbpf_compile utility.
+.IP
+iptables \-A OUTPUT \-m bpf \-\-bytecode "`nfbpf_compile RAW 'ip proto 6'`" \-j ACCEPT
+.PP
+You may want to learn more about BPF from FreeBSD's bpf(4) manpage.
diff --git a/include/linux/netfilter/xt_bpf.h b/include/linux/netfilter/xt_bpf.h
new file mode 100644 (file)
index 0000000..5dda450
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _XT_BPF_H
+#define _XT_BPF_H
+
+#include <linux/filter.h>
+#include <linux/types.h>
+
+#define XT_BPF_MAX_NUM_INSTR   64
+
+struct xt_bpf_info {
+       __u16 bpf_program_num_elem;
+       struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR];
+
+       /* only used in the kernel */
+       struct sk_filter *filter __attribute__((aligned(8)));
+};
+
+#endif /*_XT_BPF_H */