summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libxt_bpf.c152
-rw-r--r--extensions/libxt_bpf.man34
-rw-r--r--include/linux/netfilter/xt_bpf.h17
3 files changed, 203 insertions, 0 deletions
diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
new file mode 100644
index 00000000..dca97d70
--- /dev/null
+++ b/extensions/libxt_bpf.c
@@ -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
index 00000000..4120a23d
--- /dev/null
+++ b/extensions/libxt_bpf.man
@@ -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
index 00000000..5dda450e
--- /dev/null
+++ b/include/linux/netfilter/xt_bpf.h
@@ -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 */