summaryrefslogtreecommitdiffstats
path: root/extensions/libxt_bpf.c
blob: dca97d707123a41aaae9368dc84954f2615d1487 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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);
}