netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH next] extensions: add libxt_bpf extension
@ 2012-12-09 19:54 Willem de Bruijn
  2013-01-10  0:12 ` [PATCH] " Willem de Bruijn
  0 siblings, 1 reply; 6+ messages in thread
From: Willem de Bruijn @ 2012-12-09 19:54 UTC (permalink / raw)
  To: netfilter-devel, pablo; +Cc: Willem de Bruijn

Support filtering using Linux Socket Filters
---
 extensions/libxt_bpf.c |  225 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 225 insertions(+), 0 deletions(-)
 create mode 100644 extensions/libxt_bpf.c

diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
new file mode 100644
index 0000000..4c02402
--- /dev/null
+++ b/extensions/libxt_bpf.c
@@ -0,0 +1,225 @@
+/*
+ * Xtables BPF extension
+ *
+ * Written by Willem de Bruijn (willemb@google.com)
+ * Copyright Google, Inc. 2012
+ * 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,
+       O_BCODE_FILE};
+
+static void bpf_help(void)
+{
+	printf(
+"bpf match options:\n"
+"--bytecode-file <file>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> > file\n"
+"--bytecode <program>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> | tr '\\n' ','`\n");
+}
+
+static const struct xt_option_entry bpf_opts[] = {
+	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
+	{.name = "bytecode-file", .id = O_BCODE_FILE, .type = XTTYPE_STRING},
+	XTOPT_TABLEEND,
+};
+
+/* Q: make a generic libxtables call? */
+static void bpf_resize_match_struct(struct xt_option_call *cb, int head_len,
+				    int elem_len, int num_elem)
+{
+	const int match_len = sizeof(struct xt_entry_match);
+	struct xt_entry_match *new_match;
+	unsigned long new_match_size;
+
+	new_match_size = match_len + head_len + (elem_len * num_elem);
+	new_match = malloc(new_match_size);
+	if (!new_match) {
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: allocation failed");
+		return;
+	}
+
+	memcpy(new_match, *cb->match, match_len + head_len);
+	new_match->u.match_size = new_match_size;
+
+	free(*cb->match);
+	*cb->match = new_match;
+	cb->data = ((void *) new_match) + match_len;
+}
+
+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");
+
+	/* adjust match struct to be able to store all instructions. */
+	bpf_resize_match_struct(cb,
+				sizeof(struct xt_bpf_info),
+				sizeof(struct sock_filter),
+				bi->bpf_program_num_elem);
+	bi = cb->data;
+
+	/* 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: program length: parameter");
+			return;
+		}
+		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);
+			return;
+		}
+		i++;
+	}
+
+	if (i != bi->bpf_program_num_elem) {
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: program length: parsing");
+		return;
+	}
+}
+
+static void bpf_parse_file(struct xt_option_call *cb, const char *filepath)
+{
+	struct stat stats;
+	char *contents;
+	int fd, len = 0, ret;
+
+	if (access(filepath, F_OK))
+		xtables_error(PARAMETER_PROBLEM, "bpf: no such file");
+	if (access(filepath, R_OK))
+		xtables_error(PARAMETER_PROBLEM, "bpf: no read permissions");
+
+	fd = open(filepath, O_RDONLY);
+	if (fd == -1)
+		xtables_error(PARAMETER_PROBLEM, "bpf: error opening file");
+	if (fstat(fd, &stats))
+		xtables_error(PARAMETER_PROBLEM, "bpf: error reading metadata");
+	if (stats.st_size >= BCODE_FILE_MAX_LEN_B)
+		xtables_error(PARAMETER_PROBLEM, "bpf: file too large");
+
+	contents = malloc(stats.st_size + 1);
+	if (!contents)
+		xtables_error(PARAMETER_PROBLEM, "bpf: allocation failed");
+	contents[stats.st_size] = 0;
+
+	while (len < stats.st_size) {
+		ret = read(fd, contents + len, stats.st_size - len);
+		if (ret == -1) {
+			if (errno == EAGAIN)
+				continue;
+			xtables_error(PARAMETER_PROBLEM, "bpf: read failed");
+		}
+		if (!ret)
+			xtables_error(PARAMETER_PROBLEM, "bpf: unexpected EOF");
+		len += ret;
+	}
+
+	bpf_parse_string(cb, contents, '\n');
+
+	free(contents);
+	close(fd);
+}
+
+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;
+	case O_BCODE_FILE:
+		bpf_parse_file(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; 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);
+}
+
+static void bpf_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_bpf_info *info = (void *) match->data;
+
+	printf("bpf --bytecode %hu,", info->bpf_program_num_elem);
+	bpf_print_code(ip, match);
+}
+
+static void bpf_fcheck(struct xt_fcheck_call *cb)
+{
+	if (((!!(cb->xflags & (1 << O_BCODE_STDIN))) ^
+	     (!!(cb->xflags & (1 << O_BCODE_FILE)))) == 0)
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: pass bytecode or bytecode-file, not both");
+}
+
+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)),
+	.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);
+}
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH] extensions: add libxt_bpf extension
  2012-12-09 19:54 [PATCH next] extensions: add libxt_bpf extension Willem de Bruijn
@ 2013-01-10  0:12 ` Willem de Bruijn
  2013-01-21 12:19   ` Pablo Neira Ayuso
  2013-01-24  2:00   ` [PATCH next] " Willem de Bruijn
  0 siblings, 2 replies; 6+ messages in thread
From: Willem de Bruijn @ 2013-01-10  0:12 UTC (permalink / raw)
  To: netfilter-devel, pablo; +Cc: Willem de Bruijn

Changes:
- v2
  - update to match latest kernel module (fixed size match struct)
  - add manual page
  - fix save/restore
  - fix matching whole program on delete

Support filtering using Linux Socket Filters
---
 extensions/libxt_bpf.c   |  199 ++++++++++++++++++++++++++++++++++++++++++++++
 extensions/libxt_bpf.man |   17 ++++
 2 files changed, 216 insertions(+), 0 deletions(-)
 create mode 100644 extensions/libxt_bpf.c
 create mode 100644 extensions/libxt_bpf.man

diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
new file mode 100644
index 0000000..8ad540f
--- /dev/null
+++ b/extensions/libxt_bpf.c
@@ -0,0 +1,199 @@
+/*
+ * 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,
+       O_BCODE_FILE};
+
+static void bpf_help(void)
+{
+	printf(
+"bpf match options:\n"
+"--bytecode-file <file>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> > file\n"
+"--bytecode <program>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> | tr '\\n' ','`\n");
+}
+
+static const struct xt_option_entry bpf_opts[] = {
+	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
+	{.name = "bytecode-file", .id = O_BCODE_FILE, .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: program length: parameter");
+			return;
+		}
+		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);
+			return;
+		}
+		i++;
+	}
+
+	if (i != bi->bpf_program_num_elem) {
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: program length: parsing");
+		return;
+	}
+}
+
+static void bpf_parse_file(struct xt_option_call *cb, const char *filepath)
+{
+	struct stat stats;
+	char *contents;
+	int fd, len = 0, ret;
+
+	if (access(filepath, F_OK))
+		xtables_error(PARAMETER_PROBLEM, "bpf: no such file");
+	if (access(filepath, R_OK))
+		xtables_error(PARAMETER_PROBLEM, "bpf: no read permissions");
+
+	fd = open(filepath, O_RDONLY);
+	if (fd == -1)
+		xtables_error(PARAMETER_PROBLEM, "bpf: error opening file");
+	if (fstat(fd, &stats))
+		xtables_error(PARAMETER_PROBLEM, "bpf: error reading metadata");
+	if (stats.st_size >= BCODE_FILE_MAX_LEN_B)
+		xtables_error(PARAMETER_PROBLEM, "bpf: file too large");
+
+	contents = malloc(stats.st_size + 1);
+	if (!contents)
+		xtables_error(PARAMETER_PROBLEM, "bpf: allocation failed");
+	contents[stats.st_size] = 0;
+
+	while (len < stats.st_size) {
+		ret = read(fd, contents + len, stats.st_size - len);
+		if (ret == -1) {
+			if (errno == EAGAIN)
+				continue;
+			xtables_error(PARAMETER_PROBLEM, "bpf: read failed");
+		}
+		if (!ret)
+			xtables_error(PARAMETER_PROBLEM, "bpf: unexpected EOF");
+		len += ret;
+	}
+
+	bpf_parse_string(cb, contents, '\n');
+
+	free(contents);
+	close(fd);
+}
+
+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;
+	case O_BCODE_FILE:
+		bpf_parse_file(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; 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);
+}
+
+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))) ^
+	     (!!(cb->xflags & (1 << O_BCODE_FILE)))) == 0)
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: pass bytecode or bytecode-file, not both");
+}
+
+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(sizeof(struct xt_bpf_info) - sizeof(void *)),
+	.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 0000000..359684c
--- /dev/null
+++ b/extensions/libxt_bpf.man
@@ -0,0 +1,17 @@
+.TP
+Match using Linux Socket Filter. Expects a BPF program in decimal format for a device without link layer. This is the format generated by \fBtcpdump \-ddd \-i $DEV\fP, if $DEV is of type DLT_RAW.
+.TP
+\fB\-\-bytecode\-file\fP \fIfilename\fP
+Pass the program stored in a file.
+For example:
+.IP
+iptables \-A OUTPUT \-m bpf \-\-bytecode-file program.bpf \-j ACCEPT
+.TP
+\fB\-\-bytecode\fP \fIcode\fP
+Pass the program on the command line. In this case all end-lines
+must have been converted to commas (for instance using `tr '\\n' ','`).
+For example:
+.IP
+iptables \-A OUTPUT \-m bpf \-\-bytecode
+         '6,40 0 0 14, 21 0 3 2048,48 0 0 25,21 0 1 20,6 0 0 96,6 0 0 0'
+         \-j ACCEPT
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] extensions: add libxt_bpf extension
  2013-01-10  0:12 ` [PATCH] " Willem de Bruijn
@ 2013-01-21 12:19   ` Pablo Neira Ayuso
  2013-01-24  2:04     ` Willem de Bruijn
  2013-01-24  2:00   ` [PATCH next] " Willem de Bruijn
  1 sibling, 1 reply; 6+ messages in thread
From: Pablo Neira Ayuso @ 2013-01-21 12:19 UTC (permalink / raw)
  To: Willem de Bruijn; +Cc: netfilter-devel

On Wed, Jan 09, 2013 at 07:12:07PM -0500, Willem de Bruijn wrote:
> Changes:
> - v2
>   - update to match latest kernel module (fixed size match struct)
>   - add manual page
>   - fix save/restore
>   - fix matching whole program on delete
> 
> Support filtering using Linux Socket Filters
> ---
>  extensions/libxt_bpf.c   |  199 ++++++++++++++++++++++++++++++++++++++++++++++
>  extensions/libxt_bpf.man |   17 ++++
>  2 files changed, 216 insertions(+), 0 deletions(-)
>  create mode 100644 extensions/libxt_bpf.c
>  create mode 100644 extensions/libxt_bpf.man
> 
> diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
> new file mode 100644
> index 0000000..8ad540f
> --- /dev/null
> +++ b/extensions/libxt_bpf.c
> @@ -0,0 +1,199 @@
> +/*
> + * 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

This has to be updated now that this sticks to 64 instructions per
filter.

> +
> +enum { O_BCODE_STDIN = 0,
> +       O_BCODE_FILE};

Better:

enum {
        O_...
        O_...
};

> +
> +static void bpf_help(void)
> +{
> +	printf(
> +"bpf match options:\n"
> +"--bytecode-file <file>	: a bpf program as generated by\n"
> +"  `tcpdump -i any -ddd <expr> > file\n"
> +"--bytecode <program>	: a bpf program as generated by\n"
> +"  `tcpdump -i any -ddd <expr> | tr '\\n' ','`\n");
> +}
> +
> +static const struct xt_option_entry bpf_opts[] = {
> +	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
> +	{.name = "bytecode-file", .id = O_BCODE_FILE, .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: program length: parameter");

better error reporting?

> +			return;

That return is superfluous. xtables_error calls exit.

> +		}
> +		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);
> +			return;

Same thing.

> +		}
> +		i++;
> +	}
> +
> +	if (i != bi->bpf_program_num_elem) {
> +		xtables_error(PARAMETER_PROBLEM,
> +			      "bpf: program length: parsing");

Better error reporting?

> +		return;

Same thing.

> +	}
> +}
> +
> +static void bpf_parse_file(struct xt_option_call *cb, const char *filepath)
> +{
> +	struct stat stats;
> +	char *contents;
> +	int fd, len = 0, ret;
> +
> +	if (access(filepath, F_OK))
> +		xtables_error(PARAMETER_PROBLEM, "bpf: no such file");
> +	if (access(filepath, R_OK))
> +		xtables_error(PARAMETER_PROBLEM, "bpf: no read permissions");

Remove these above so...

> +
> +	fd = open(filepath, O_RDONLY);
> +	if (fd == -1)
> +		xtables_error(PARAMETER_PROBLEM, "bpf: error opening file");

you can use strerror here.

> +	if (fstat(fd, &stats))
> +		xtables_error(PARAMETER_PROBLEM, "bpf: error reading metadata");
> +	if (stats.st_size >= BCODE_FILE_MAX_LEN_B)
> +		xtables_error(PARAMETER_PROBLEM, "bpf: file too large");
> +
> +	contents = malloc(stats.st_size + 1);

Better a buffer allocated in the stack now that we have 64
instructions per filter?

Or use fread to get each line and put it into the filter? so reading
the filter and parsing it happens all at once.

> +	if (!contents)
> +		xtables_error(PARAMETER_PROBLEM, "bpf: allocation failed");
> +	contents[stats.st_size] = 0;
> +
> +	while (len < stats.st_size) {
> +		ret = read(fd, contents + len, stats.st_size - len);
> +		if (ret == -1) {
> +			if (errno == EAGAIN)
> +				continue;
> +			xtables_error(PARAMETER_PROBLEM, "bpf: read failed");
> +		}
> +		if (!ret)
> +			xtables_error(PARAMETER_PROBLEM, "bpf: unexpected EOF");
> +		len += ret;
> +	}
> +
> +	bpf_parse_string(cb, contents, '\n');
> +
> +	free(contents);
> +	close(fd);
> +}
> +
> +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;
> +	case O_BCODE_FILE:
> +		bpf_parse_file(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; 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);
> +}
> +
> +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))) ^
> +	     (!!(cb->xflags & (1 << O_BCODE_FILE)))) == 0)
> +		xtables_error(PARAMETER_PROBLEM,
> +			      "bpf: pass bytecode or bytecode-file, not both");
> +}
> +
> +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(sizeof(struct xt_bpf_info) - sizeof(void *)),

Use offsetof instead, please.

> +	.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 0000000..359684c
> --- /dev/null
> +++ b/extensions/libxt_bpf.man
> @@ -0,0 +1,17 @@
> +.TP
> +Match using Linux Socket Filter. Expects a BPF program in decimal format for a device without link layer. This is the format generated by \fBtcpdump \-ddd \-i $DEV\fP, if $DEV is of type DLT_RAW.
> +.TP
> +\fB\-\-bytecode\-file\fP \fIfilename\fP
> +Pass the program stored in a file.
> +For example:
> +.IP
> +iptables \-A OUTPUT \-m bpf \-\-bytecode-file program.bpf \-j ACCEPT

It's a good idea to describe the format of the file here.

> +.TP
> +\fB\-\-bytecode\fP \fIcode\fP
> +Pass the program on the command line. In this case all end-lines
> +must have been converted to commas (for instance using `tr '\\n' ','`).
> +For example:
> +.IP
> +iptables \-A OUTPUT \-m bpf \-\-bytecode
> +         '6,40 0 0 14, 21 0 3 2048,48 0 0 25,21 0 1 20,6 0 0 96,6 0 0 0'

Please, a filter that actually works ;-)

> +         \-j ACCEPT
> -- 
> 1.7.7.3
> 
> --
> 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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH next] extensions: add libxt_bpf extension
  2013-01-10  0:12 ` [PATCH] " Willem de Bruijn
  2013-01-21 12:19   ` Pablo Neira Ayuso
@ 2013-01-24  2:00   ` Willem de Bruijn
  2013-04-01 22:16     ` Pablo Neira Ayuso
  1 sibling, 1 reply; 6+ messages in thread
From: Willem de Bruijn @ 2013-01-24  2:00 UTC (permalink / raw)
  To: netfilter-devel, pablo; +Cc: Willem de Bruijn

Changes:
- v3
  - more informative error messages and man page
- v2
  - update to match latest kernel module (fixed size match struct)
  - add manual page
  - fix save/restore
  - fix matching whole program on delete

Support filtering using Linux Socket Filters
---
 extensions/libxt_bpf.c   | 193 +++++++++++++++++++++++++++++++++++++++++++++++
 extensions/libxt_bpf.man |  35 +++++++++
 2 files changed, 228 insertions(+)
 create mode 100644 extensions/libxt_bpf.c
 create mode 100644 extensions/libxt_bpf.man

diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
new file mode 100644
index 0000000..15dc870
--- /dev/null
+++ b/extensions/libxt_bpf.c
@@ -0,0 +1,193 @@
+/*
+ * 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,
+	O_BCODE_FILE
+};
+
+static void bpf_help(void)
+{
+	printf(
+"bpf match options:\n"
+"--bytecode-file <file>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> > file\n"
+"--bytecode <program>	: a bpf program as generated by\n"
+"  `tcpdump -i any -ddd <expr> | tr '\\n' ','`\n");
+}
+
+static const struct xt_option_entry bpf_opts[] = {
+	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
+	{.name = "bytecode-file", .id = O_BCODE_FILE, .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_file(struct xt_option_call *cb, const char *filepath)
+{
+	struct stat stats;
+	char *contents;
+	int fd, len = 0, ret;
+
+	fd = open(filepath, O_RDONLY);
+	if (fd == -1)
+		xtables_error(PARAMETER_PROBLEM, "bpf: error opening file: %s",
+			      strerror(errno));
+	if (fstat(fd, &stats))
+		xtables_error(PARAMETER_PROBLEM, "bpf: error reading metadata");
+	if (stats.st_size >= BCODE_FILE_MAX_LEN_B)
+		xtables_error(PARAMETER_PROBLEM, "bpf: file too large");
+
+	contents = malloc(stats.st_size + 1);
+	if (!contents)
+		xtables_error(PARAMETER_PROBLEM, "bpf: allocation failed");
+	contents[stats.st_size] = 0;
+
+	while (len < stats.st_size) {
+		ret = read(fd, contents + len, stats.st_size - len);
+		if (ret == -1) {
+			if (errno == EAGAIN)
+				continue;
+			xtables_error(PARAMETER_PROBLEM, "bpf: read failed");
+		}
+		if (!ret)
+			xtables_error(PARAMETER_PROBLEM, "bpf: unexpected EOF");
+		len += ret;
+	}
+
+	bpf_parse_string(cb, contents, '\n');
+
+	free(contents);
+	close(fd);
+}
+
+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;
+	case O_BCODE_FILE:
+		bpf_parse_file(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; 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);
+}
+
+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))) ^
+	     (!!(cb->xflags & (1 << O_BCODE_FILE)))) == 0)
+		xtables_error(PARAMETER_PROBLEM,
+			      "bpf: pass bytecode or bytecode-file, not both");
+}
+
+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 0000000..468c023
--- /dev/null
+++ b/extensions/libxt_bpf.man
@@ -0,0 +1,35 @@
+.TP
+Match using Linux Socket Filter. Expects a BPF program in decimal format for a device without link layer. This is the format generated by \fBtcpdump \-ddd \-i $DEV\fP, if $DEV is of type DLT_RAW.
+.TP
+\fB\-\-bytecode\-file\fP \fIfilename\fP
+Pass the program stored in a file.
+For example:
+.IP
+iptables \-A OUTPUT \-m bpf \-\-bytecode-file program.bpf \-j ACCEPT
+.IP
+The file format matches the output of the tcpdump 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.
+.IP
+For example, to read only packets matching 'ip proto 6', insert the
+following, without the comments or trailing whitespace:
+.br
+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)
+.TP
+\fB\-\-bytecode\fP \fIcode\fP
+Pass the program on the command line. In this case all end-lines
+must have been converted to commas (for instance using `tr '\\n' ','`).
+For example, the same program passed on the command line becomes:
+.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
-- 
1.8.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] extensions: add libxt_bpf extension
  2013-01-21 12:19   ` Pablo Neira Ayuso
@ 2013-01-24  2:04     ` Willem de Bruijn
  0 siblings, 0 replies; 6+ messages in thread
From: Willem de Bruijn @ 2013-01-24  2:04 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

On Mon, Jan 21, 2013 at 7:19 AM, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Wed, Jan 09, 2013 at 07:12:07PM -0500, Willem de Bruijn wrote:
>> Changes:
>> - v2
>>   - update to match latest kernel module (fixed size match struct)
>>   - add manual page
>>   - fix save/restore
>>   - fix matching whole program on delete
>>
>> Support filtering using Linux Socket Filters
>> ---
>>  extensions/libxt_bpf.c   |  199 ++++++++++++++++++++++++++++++++++++++++++++++
>>  extensions/libxt_bpf.man |   17 ++++
>>  2 files changed, 216 insertions(+), 0 deletions(-)
>>  create mode 100644 extensions/libxt_bpf.c
>>  create mode 100644 extensions/libxt_bpf.man
>>
>> diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
>> new file mode 100644
>> index 0000000..8ad540f
>> --- /dev/null
>> +++ b/extensions/libxt_bpf.c
>> @@ -0,0 +1,199 @@
>> +/*
>> + * 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
>
> This has to be updated now that this sticks to 64 instructions per
> filter.

Oh.. rereading my comments after sending the revised patch I see that
I missed this. Will fix up in the next revision. If my little
arithmetic below is correct, it should be either 1603, or a little bit
larger (this is mainly a safety against enormous files).

>> +
>> +enum { O_BCODE_STDIN = 0,
>> +       O_BCODE_FILE};
>
> Better:
>
> enum {
>         O_...
>         O_...
> };

Done

>> +
>> +static void bpf_help(void)
>> +{
>> +     printf(
>> +"bpf match options:\n"
>> +"--bytecode-file <file>      : a bpf program as generated by\n"
>> +"  `tcpdump -i any -ddd <expr> > file\n"
>> +"--bytecode <program>        : a bpf program as generated by\n"
>> +"  `tcpdump -i any -ddd <expr> | tr '\\n' ','`\n");
>> +}
>> +
>> +static const struct xt_option_entry bpf_opts[] = {
>> +     {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
>> +     {.name = "bytecode-file", .id = O_BCODE_FILE, .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: program length: parameter");
>
> better error reporting?

Done

>> +                     return;

Done

> That return is superfluous. xtables_error calls exit.
>
>> +             }
>> +             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);
>> +                     return;
>
> Same thing.

Done

>> +             }
>> +             i++;
>> +     }
>> +
>> +     if (i != bi->bpf_program_num_elem) {
>> +             xtables_error(PARAMETER_PROBLEM,
>> +                           "bpf: program length: parsing");
>
> Better error reporting?

Done

>> +             return;
>
> Same thing.

Done

>> +     }
>> +}
>> +
>> +static void bpf_parse_file(struct xt_option_call *cb, const char *filepath)
>> +{
>> +     struct stat stats;
>> +     char *contents;
>> +     int fd, len = 0, ret;
>> +
>> +     if (access(filepath, F_OK))
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: no such file");
>> +     if (access(filepath, R_OK))
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: no read permissions");
>
> Remove these above so...

Done

>
>> +
>> +     fd = open(filepath, O_RDONLY);
>> +     if (fd == -1)
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: error opening file");
>
> you can use strerror here.

Done

>
>> +     if (fstat(fd, &stats))
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: error reading metadata");
>> +     if (stats.st_size >= BCODE_FILE_MAX_LEN_B)
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: file too large");
>> +
>> +     contents = malloc(stats.st_size + 1);
>
> Better a buffer allocated in the stack now that we have 64
> instructions per filter?

The decimal notation still allows variable size, causing us to have to
allocate an upper estimate. This is 3 characters for the first line +
64 * (5 + 1 + 3 + 1 + 3 + 1 + 10 + 1) == 1603 B if I didn't mess up
somewhere.

> Or use fread to get each line and put it into the filter? so reading
> the filter and parsing it happens all at once.

That would involve duplicating some of the parsing logic from
bpf_parse_string, and the same error reports (program length mismatch,
instruction errors, etcetera). I think that parsing in only one
location is preferable (but I'm happy to change the code if you
prefer).

>> +     if (!contents)
>> +             xtables_error(PARAMETER_PROBLEM, "bpf: allocation failed");
>> +     contents[stats.st_size] = 0;
>> +
>> +     while (len < stats.st_size) {
>> +             ret = read(fd, contents + len, stats.st_size - len);
>> +             if (ret == -1) {
>> +                     if (errno == EAGAIN)
>> +                             continue;
>> +                     xtables_error(PARAMETER_PROBLEM, "bpf: read failed");
>> +             }
>> +             if (!ret)
>> +                     xtables_error(PARAMETER_PROBLEM, "bpf: unexpected EOF");
>> +             len += ret;
>> +     }
>> +
>> +     bpf_parse_string(cb, contents, '\n');
>> +
>> +     free(contents);
>> +     close(fd);
>> +}
>> +
>> +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;
>> +     case O_BCODE_FILE:
>> +             bpf_parse_file(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; 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);
>> +}
>> +
>> +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))) ^
>> +          (!!(cb->xflags & (1 << O_BCODE_FILE)))) == 0)
>> +             xtables_error(PARAMETER_PROBLEM,
>> +                           "bpf: pass bytecode or bytecode-file, not both");
>> +}
>> +
>> +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(sizeof(struct xt_bpf_info) - sizeof(void *)),
>
> Use offsetof instead, please.

Done.

>> +     .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 0000000..359684c
>> --- /dev/null
>> +++ b/extensions/libxt_bpf.man
>> @@ -0,0 +1,17 @@
>> +.TP
>> +Match using Linux Socket Filter. Expects a BPF program in decimal format for a device without link layer. This is the format generated by \fBtcpdump \-ddd \-i $DEV\fP, if $DEV is of type DLT_RAW.
>> +.TP
>> +\fB\-\-bytecode\-file\fP \fIfilename\fP
>> +Pass the program stored in a file.
>> +For example:
>> +.IP
>> +iptables \-A OUTPUT \-m bpf \-\-bytecode-file program.bpf \-j ACCEPT
>
> It's a good idea to describe the format of the file here.

Done. Maybe a bit too verbose now. Let me know, if so.

>> +.TP
>> +\fB\-\-bytecode\fP \fIcode\fP
>> +Pass the program on the command line. In this case all end-lines
>> +must have been converted to commas (for instance using `tr '\\n' ','`).
>> +For example:
>> +.IP
>> +iptables \-A OUTPUT \-m bpf \-\-bytecode
>> +         '6,40 0 0 14, 21 0 3 2048,48 0 0 25,21 0 1 20,6 0 0 96,6 0 0 0'
>
> Please, a filter that actually works ;-)

Oops! Done (and tested).

>> +         \-j ACCEPT
>> --
>> 1.7.7.3
>>
>> --
>> 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

Thanks!

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH next] extensions: add libxt_bpf extension
  2013-01-24  2:00   ` [PATCH next] " Willem de Bruijn
@ 2013-04-01 22:16     ` Pablo Neira Ayuso
  0 siblings, 0 replies; 6+ messages in thread
From: Pablo Neira Ayuso @ 2013-04-01 22:16 UTC (permalink / raw)
  To: Willem de Bruijn; +Cc: netfilter-devel

On Wed, Jan 23, 2013 at 09:00:58PM -0500, Willem de Bruijn wrote:
> Changes:
> - v3
>   - more informative error messages and man page
> - v2
>   - update to match latest kernel module (fixed size match struct)
>   - add manual page
>   - fix save/restore
>   - fix matching whole program on delete
> 
> Support filtering using Linux Socket Filters

Applied with changes:

* include a copy of include/linux/netfilter/xt_bpf.h in the tree.

* Removed 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. We can recover the file parameter
  later on if you find it useful.

* Removed the trailing comma in the backtick format, the parser works
  just fine for me here.

* Fix error message if --bytecode is missing.

Thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-04-01 22:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-09 19:54 [PATCH next] extensions: add libxt_bpf extension Willem de Bruijn
2013-01-10  0:12 ` [PATCH] " Willem de Bruijn
2013-01-21 12:19   ` Pablo Neira Ayuso
2013-01-24  2:04     ` Willem de Bruijn
2013-01-24  2:00   ` [PATCH next] " Willem de Bruijn
2013-04-01 22:16     ` Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).