1 /*
2  * Xtables BPF extension
3  *
4  * Written by Willem de Bruijn (willemb@google.com)
5  * Copyright Google, Inc. 2013
6  * Licensed under the GNU General Public License version 2 (GPLv2)
7 */
8 
9 #include <linux/netfilter/xt_bpf.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <xtables.h>
19 
20 #define BCODE_FILE_MAX_LEN_B	1024
21 
22 enum {
23 	O_BCODE_STDIN = 0,
24 };
25 
bpf_help(void)26 static void bpf_help(void)
27 {
28 	printf(
29 "bpf match options:\n"
30 "--bytecode <program>	: a bpf program as generated by\n"
31 "  `nfbpf_compiler RAW <filter>`\n");
32 }
33 
34 static const struct xt_option_entry bpf_opts[] = {
35 	{.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
36 	XTOPT_TABLEEND,
37 };
38 
bpf_parse_string(struct xt_option_call * cb,const char * bpf_program,const char separator)39 static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
40 			     const char separator)
41 {
42 	struct xt_bpf_info *bi = (void *) cb->data;
43 	const char *token;
44 	char sp;
45 	int i;
46 
47 	/* parse head: length. */
48 	if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 ||
49 		   sp != separator)
50 		xtables_error(PARAMETER_PROBLEM,
51 			      "bpf: error parsing program length");
52 	if (!bi->bpf_program_num_elem)
53 		xtables_error(PARAMETER_PROBLEM,
54 			      "bpf: illegal zero length program");
55 	if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR)
56 		xtables_error(PARAMETER_PROBLEM,
57 			      "bpf: number of instructions exceeds maximum");
58 
59 	/* parse instructions. */
60 	i = 0;
61 	token = bpf_program;
62 	while ((token = strchr(token, separator)) && (++token)[0]) {
63 		if (i >= bi->bpf_program_num_elem)
64 			xtables_error(PARAMETER_PROBLEM,
65 				      "bpf: real program length exceeds"
66 				      " the encoded length parameter");
67 		if (sscanf(token, "%hu %hhu %hhu %u,",
68 			   &bi->bpf_program[i].code,
69 			   &bi->bpf_program[i].jt,
70 			   &bi->bpf_program[i].jf,
71 			   &bi->bpf_program[i].k) != 4)
72 			xtables_error(PARAMETER_PROBLEM,
73 				      "bpf: error at instr %d", i);
74 		i++;
75 	}
76 
77 	if (i != bi->bpf_program_num_elem)
78 		xtables_error(PARAMETER_PROBLEM,
79 			      "bpf: parsed program length is less than the"
80 			      " encoded length parameter");
81 }
82 
bpf_parse(struct xt_option_call * cb)83 static void bpf_parse(struct xt_option_call *cb)
84 {
85 	xtables_option_parse(cb);
86 	switch (cb->entry->id) {
87 	case O_BCODE_STDIN:
88 		bpf_parse_string(cb, cb->arg, ',');
89 		break;
90 	default:
91 		xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
92 	}
93 }
94 
bpf_print_code(const void * ip,const struct xt_entry_match * match)95 static void bpf_print_code(const void *ip, const struct xt_entry_match *match)
96 {
97 	const struct xt_bpf_info *info = (void *) match->data;
98 	int i;
99 
100 	for (i = 0; i < info->bpf_program_num_elem-1; i++)
101 		printf("%hu %hhu %hhu %u,", info->bpf_program[i].code,
102 					    info->bpf_program[i].jt,
103 					    info->bpf_program[i].jf,
104 					    info->bpf_program[i].k);
105 
106 	printf("%hu %hhu %hhu %u", info->bpf_program[i].code,
107 				    info->bpf_program[i].jt,
108 				    info->bpf_program[i].jf,
109 				    info->bpf_program[i].k);
110 }
111 
bpf_save(const void * ip,const struct xt_entry_match * match)112 static void bpf_save(const void *ip, const struct xt_entry_match *match)
113 {
114 	const struct xt_bpf_info *info = (void *) match->data;
115 
116 	printf(" --bytecode \"%hu,", info->bpf_program_num_elem);
117 	bpf_print_code(ip, match);
118 	printf("\"");
119 }
120 
bpf_fcheck(struct xt_fcheck_call * cb)121 static void bpf_fcheck(struct xt_fcheck_call *cb)
122 {
123 	if (!(cb->xflags & (1 << O_BCODE_STDIN)))
124 		xtables_error(PARAMETER_PROBLEM,
125 			      "bpf: missing --bytecode parameter");
126 }
127 
bpf_print(const void * ip,const struct xt_entry_match * match,int numeric)128 static void bpf_print(const void *ip, const struct xt_entry_match *match,
129 		      int numeric)
130 {
131 	printf("match bpf ");
132 	return bpf_print_code(ip, match);
133 }
134 
135 static struct xtables_match bpf_match = {
136 	.family		= NFPROTO_UNSPEC,
137 	.name		= "bpf",
138 	.version	= XTABLES_VERSION,
139 	.size		= XT_ALIGN(sizeof(struct xt_bpf_info)),
140 	.userspacesize	= XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
141 	.help		= bpf_help,
142 	.print		= bpf_print,
143 	.save		= bpf_save,
144 	.x6_parse	= bpf_parse,
145 	.x6_fcheck	= bpf_fcheck,
146 	.x6_options	= bpf_opts,
147 };
148 
_init(void)149 void _init(void)
150 {
151 	xtables_register_match(&bpf_match);
152 }
153