2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
21 #include "bpf_parser.tab.h"
25 #define MAX_INSTRUCTIONS 4096
27 int compile_filter
(char *file
, int verbose
);
29 static int curr_instr
= 0;
31 static struct sock_filter out
[MAX_INSTRUCTIONS
];
33 static char *labels
[MAX_INSTRUCTIONS
];
35 static char *labels_jt
[MAX_INSTRUCTIONS
];
36 static char *labels_jf
[MAX_INSTRUCTIONS
];
37 static char *labels_k
[MAX_INSTRUCTIONS
];
39 #define YYERROR_VERBOSE 0
41 #define YYENABLE_NLS 1
42 #define YYLTYPE_IS_TRIVIAL 1
46 extern
int yylex(void);
47 extern
void yyerror(const char *);
51 static inline
void set_curr_instr
(uint16_t code
, uint8_t jt
, uint8_t jf
, uint32_t k
)
53 if
(curr_instr
>= MAX_INSTRUCTIONS
)
54 panic
("Exceeded maximal number of instructions!\n");
55 out
[curr_instr
].code
= code
;
56 out
[curr_instr
].jt
= jt
;
57 out
[curr_instr
].jf
= jf
;
58 out
[curr_instr
].k
= k
;
62 static inline
void set_curr_label
(char *label
)
64 if
(curr_instr
>= MAX_INSTRUCTIONS
)
65 panic
("Exceeded maximal number of instructions!\n");
66 labels
[curr_instr
] = label
;
73 static inline
void set_jmp_label
(char *label
, int which
)
75 if
(curr_instr
>= MAX_INSTRUCTIONS
)
76 panic
("Exceeded maximal number of instructions!\n");
77 assert
(which
== JTL || which
== JFL || which
== JKL
);
79 labels_jt
[curr_instr
] = label
;
80 else if
(which
== JFL
)
81 labels_jf
[curr_instr
] = label
;
83 labels_k
[curr_instr
] = label
;
86 static int find_intr_offset_or_panic
(char *label_to_search
)
88 int i
, max
= curr_instr
, ret
= -ENOENT
;
90 assert
(label_to_search
);
91 for
(i
= 0; i
< max
; ++i
) {
92 if
(labels
[i
] != NULL
) {
93 /* Both are \0-terminated! */
94 if
(!strcmp
(label_to_search
, labels
[i
])) {
101 panic
("No such label!\n");
113 %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
114 %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_LSH OP_RSH OP_RET
115 %token OP_TAX OP_TXA OP_LDXB K_PKT_LEN K_PROTO K_TYPE K_IFIDX K_NLATTR
116 %token K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE K_RXHASH K_CPU K_COMMENT
118 %token
':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#'
120 %token number_hex number_dec label comment
122 %type
<number
> number_hex number_dec number
168 : number_dec
{ $$
= $1; }
169 | number_hex
{ $$
= $1; }
177 : label
':' { set_curr_label
($1); }
181 : OP_LDB
'[' 'x' '+' number
']' {
182 set_curr_instr
(BPF_LD | BPF_B | BPF_IND
, 0, 0, $5); }
183 | OP_LDB
'[' number
']' {
184 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0, $3); }
185 | OP_LDB
'#' K_PROTO
{
186 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
187 SKF_AD_OFF
+ SKF_AD_PROTOCOL
); }
188 | OP_LDB
'#' K_TYPE
{
189 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
190 SKF_AD_OFF
+ SKF_AD_PKTTYPE
); }
191 | OP_LDB
'#' K_IFIDX
{
192 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
193 SKF_AD_OFF
+ SKF_AD_IFINDEX
); }
194 | OP_LDB
'#' K_NLATTR
{
195 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
196 SKF_AD_OFF
+ SKF_AD_NLATTR
); }
197 | OP_LDB
'#' K_NLATTR_NEST
{
198 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
199 SKF_AD_OFF
+ SKF_AD_NLATTR_NEST
); }
200 | OP_LDB
'#' K_MARK
{
201 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
202 SKF_AD_OFF
+ SKF_AD_MARK
); }
203 | OP_LDB
'#' K_QUEUE
{
204 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
205 SKF_AD_OFF
+ SKF_AD_QUEUE
); }
206 | OP_LDB
'#' K_HATYPE
{
207 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
208 SKF_AD_OFF
+ SKF_AD_HATYPE
); }
209 | OP_LDB
'#' K_RXHASH
{
210 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
211 SKF_AD_OFF
+ SKF_AD_RXHASH
); }
213 set_curr_instr
(BPF_LD | BPF_B | BPF_ABS
, 0, 0,
214 SKF_AD_OFF
+ SKF_AD_CPU
); }
218 : OP_LDH
'[' 'x' '+' number
']' {
219 set_curr_instr
(BPF_LD | BPF_H | BPF_IND
, 0, 0, $5); }
220 | OP_LDH
'[' number
']' {
221 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0, $3); }
222 | OP_LDH
'#' K_PROTO
{
223 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
224 SKF_AD_OFF
+ SKF_AD_PROTOCOL
); }
225 | OP_LDH
'#' K_TYPE
{
226 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
227 SKF_AD_OFF
+ SKF_AD_PKTTYPE
); }
228 | OP_LDH
'#' K_IFIDX
{
229 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
230 SKF_AD_OFF
+ SKF_AD_IFINDEX
); }
231 | OP_LDH
'#' K_NLATTR
{
232 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
233 SKF_AD_OFF
+ SKF_AD_NLATTR
); }
234 | OP_LDH
'#' K_NLATTR_NEST
{
235 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
236 SKF_AD_OFF
+ SKF_AD_NLATTR_NEST
); }
237 | OP_LDH
'#' K_MARK
{
238 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
239 SKF_AD_OFF
+ SKF_AD_MARK
); }
240 | OP_LDH
'#' K_QUEUE
{
241 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
242 SKF_AD_OFF
+ SKF_AD_QUEUE
); }
243 | OP_LDH
'#' K_HATYPE
{
244 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
245 SKF_AD_OFF
+ SKF_AD_HATYPE
); }
246 | OP_LDH
'#' K_RXHASH
{
247 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
248 SKF_AD_OFF
+ SKF_AD_RXHASH
); }
250 set_curr_instr
(BPF_LD | BPF_H | BPF_ABS
, 0, 0,
251 SKF_AD_OFF
+ SKF_AD_CPU
); }
256 set_curr_instr
(BPF_LD | BPF_IMM
, 0, 0, $3); }
257 | OP_LD
'#' K_PKT_LEN
{
258 set_curr_instr
(BPF_LD | BPF_W | BPF_LEN
, 0, 0, 0); }
259 | OP_LD
'#' K_PROTO
{
260 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
261 SKF_AD_OFF
+ SKF_AD_PROTOCOL
); }
263 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
264 SKF_AD_OFF
+ SKF_AD_PKTTYPE
); }
265 | OP_LD
'#' K_IFIDX
{
266 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
267 SKF_AD_OFF
+ SKF_AD_IFINDEX
); }
268 | OP_LD
'#' K_NLATTR
{
269 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
270 SKF_AD_OFF
+ SKF_AD_NLATTR
); }
271 | OP_LD
'#' K_NLATTR_NEST
{
272 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
273 SKF_AD_OFF
+ SKF_AD_NLATTR_NEST
); }
275 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
276 SKF_AD_OFF
+ SKF_AD_MARK
); }
277 | OP_LD
'#' K_QUEUE
{
278 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
279 SKF_AD_OFF
+ SKF_AD_QUEUE
); }
280 | OP_LD
'#' K_HATYPE
{
281 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
282 SKF_AD_OFF
+ SKF_AD_HATYPE
); }
283 | OP_LD
'#' K_RXHASH
{
284 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
285 SKF_AD_OFF
+ SKF_AD_RXHASH
); }
287 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0,
288 SKF_AD_OFF
+ SKF_AD_CPU
); }
289 | OP_LD
'M' '[' number
']' {
290 set_curr_instr
(BPF_LD | BPF_MEM
, 0, 0, $4); }
291 | OP_LD
'[' 'x' '+' number
']' {
292 set_curr_instr
(BPF_LD | BPF_W | BPF_IND
, 0, 0, $5); }
293 | OP_LD
'[' number
']' {
294 set_curr_instr
(BPF_LD | BPF_W | BPF_ABS
, 0, 0, $3); }
298 : OP_LDX
'#' number
{
299 set_curr_instr
(BPF_LDX | BPF_IMM
, 0, 0, $3); }
300 | OP_LDX
'M' '[' number
']' {
301 set_curr_instr
(BPF_LDX | BPF_MEM
, 0, 0, $4); }
302 | OP_LDXB number
'*' '(' '[' number
']' '&' number
')' {
303 if
($2 != 4 ||
$9 != 0xf) {
304 panic
("ldxb offset not supported!\n");
306 set_curr_instr
(BPF_LDX | BPF_MSH | BPF_B
, 0, 0, $6); } }
307 | OP_LDX number
'*' '(' '[' number
']' '&' number
')' {
308 if
($2 != 4 ||
$9 != 0xf) {
309 panic
("ldxb offset not supported!\n");
311 set_curr_instr
(BPF_LDX | BPF_MSH | BPF_B
, 0, 0, $6); } }
315 : OP_ST
'M' '[' number
']' {
316 set_curr_instr
(BPF_ST
, 0, 0, $4); }
320 : OP_STX
'M' '[' number
']' {
321 set_curr_instr
(BPF_STX
, 0, 0, $4); }
326 set_jmp_label
($2, JKL
);
327 set_curr_instr
(BPF_JMP | BPF_JA
, 0, 0, 0); }
331 : OP_JEQ
'#' number
',' label
',' label
{
332 set_jmp_label
($5, JTL
);
333 set_jmp_label
($7, JFL
);
334 set_curr_instr
(BPF_JMP | BPF_JEQ | BPF_K
, 0, 0, $3); }
335 | OP_JEQ
'x' ',' label
',' label
{
336 set_jmp_label
($4, JTL
);
337 set_jmp_label
($6, JFL
);
338 set_curr_instr
(BPF_JMP | BPF_JEQ | BPF_X
, 0, 0, 0); }
342 : OP_JGT
'#' number
',' label
',' label
{
343 set_jmp_label
($5, JTL
);
344 set_jmp_label
($7, JFL
);
345 set_curr_instr
(BPF_JMP | BPF_JGT | BPF_K
, 0, 0, $3); }
346 | OP_JGT
'x' ',' label
',' label
{
347 set_jmp_label
($4, JTL
);
348 set_jmp_label
($6, JFL
);
349 set_curr_instr
(BPF_JMP | BPF_JGT | BPF_X
, 0, 0, 0); }
353 : OP_JGE
'#' number
',' label
',' label
{
354 set_jmp_label
($5, JTL
);
355 set_jmp_label
($7, JFL
);
356 set_curr_instr
(BPF_JMP | BPF_JGE | BPF_K
, 0, 0, $3); }
357 | OP_JGE
'x' ',' label
',' label
{
358 set_jmp_label
($4, JTL
);
359 set_jmp_label
($6, JFL
);
360 set_curr_instr
(BPF_JMP | BPF_JGE | BPF_X
, 0, 0, 0); }
364 : OP_JSET
'#' number
',' label
',' label
{
365 set_jmp_label
($5, JTL
);
366 set_jmp_label
($7, JFL
);
367 set_curr_instr
(BPF_JMP | BPF_JSET | BPF_K
, 0, 0, $3); }
368 | OP_JSET
'x' ',' label
',' label
{
369 set_jmp_label
($4, JTL
);
370 set_jmp_label
($6, JFL
);
371 set_curr_instr
(BPF_JMP | BPF_JSET | BPF_X
, 0, 0, 0); }
375 : OP_ADD
'#' number
{
376 set_curr_instr
(BPF_ALU | BPF_ADD | BPF_K
, 0, 0, $3); }
378 set_curr_instr
(BPF_ALU | BPF_ADD | BPF_X
, 0, 0, 0); }
382 : OP_SUB
'#' number
{
383 set_curr_instr
(BPF_ALU | BPF_SUB | BPF_K
, 0, 0, $3); }
385 set_curr_instr
(BPF_ALU | BPF_SUB | BPF_X
, 0, 0, 0); }
389 : OP_MUL
'#' number
{
390 set_curr_instr
(BPF_ALU | BPF_MUL | BPF_K
, 0, 0, $3); }
392 set_curr_instr
(BPF_ALU | BPF_MUL | BPF_X
, 0, 0, 0); }
396 : OP_DIV
'#' number
{
397 set_curr_instr
(BPF_ALU | BPF_DIV | BPF_K
, 0, 0, $3); }
399 set_curr_instr
(BPF_ALU | BPF_DIV | BPF_X
, 0, 0, 0); }
403 : OP_AND
'#' number
{
404 set_curr_instr
(BPF_ALU | BPF_AND | BPF_K
, 0, 0, $3); }
406 set_curr_instr
(BPF_ALU | BPF_AND | BPF_X
, 0, 0, 0); }
411 set_curr_instr
(BPF_ALU | BPF_OR | BPF_K
, 0, 0, $3); }
413 set_curr_instr
(BPF_ALU | BPF_OR | BPF_X
, 0, 0, 0); }
417 : OP_LSH
'#' number
{
418 set_curr_instr
(BPF_ALU | BPF_LSH | BPF_K
, 0, 0, $3); }
420 set_curr_instr
(BPF_ALU | BPF_LSH | BPF_X
, 0, 0, 0); }
424 : OP_RSH
'#' number
{
425 set_curr_instr
(BPF_ALU | BPF_RSH | BPF_K
, 0, 0, $3); }
427 set_curr_instr
(BPF_ALU | BPF_RSH | BPF_X
, 0, 0, 0); }
432 set_curr_instr
(BPF_RET | BPF_A
, 0, 0, 0); }
433 | OP_RET
'#' number
{
434 set_curr_instr
(BPF_RET | BPF_K
, 0, 0, $3); }
439 set_curr_instr
(BPF_MISC | BPF_TAX
, 0, 0, 0); }
444 set_curr_instr
(BPF_MISC | BPF_TXA
, 0, 0, 0); }
449 static void stage_1_inline
(void)
454 static void stage_2_label_reduce
(void)
456 int i
, max
= curr_instr
, off
;
458 /* 1. reduce k jumps */
459 for
(i
= 0; i
< max
; ++i
) {
460 if
(labels_k
[i
] != NULL
) {
461 off
= find_intr_offset_or_panic
(labels_k
[i
]);
462 out
[i
].k
= (uint32_t) (off
- i
- 1);
466 /* 1. reduce jt jumps */
467 for
(i
= 0; i
< max
; ++i
) {
468 if
(labels_jt
[i
] != NULL
) {
469 off
= find_intr_offset_or_panic
(labels_jt
[i
]);
470 out
[i
].jt
= (uint8_t) (off
- i
-1);
474 /* 1. reduce jf jumps */
475 for
(i
= 0; i
< max
; ++i
) {
476 if
(labels_jf
[i
] != NULL
) {
477 off
= find_intr_offset_or_panic
(labels_jf
[i
]);
478 out
[i
].jf
= (uint8_t) (off
- i
- 1);
483 int compile_filter
(char *file
, int verbose
)
486 struct sock_fprog res
;
488 yyin
= fopen
(file
, "r");
490 panic
("Cannot open file!\n");
491 memset
(out
, 0, sizeof
(out
));
492 memset
(labels
, 0, sizeof
(labels
));
493 memset
(labels_jf
, 0, sizeof
(labels_jf
));
494 memset
(labels_jt
, 0, sizeof
(labels_jt
));
495 memset
(labels_k
, 0, sizeof
(labels_k
));
498 stage_2_label_reduce
();
501 res.len
= curr_instr
;
504 printf
("Generated program:\n");
508 printf
("Validating: ");
511 if
(bpf_validate
(&res
) == 0) {
513 whine
("semantic error! BPF validation failed!\n");
515 panic
("Semantic error! BPF validation failed! "
516 "Try -V for debugging output!\n");
518 printf
("is runnable!\n");
521 for
(i
= 0; i
< res.len
; ++i
) {
522 printf
("{ 0x%x, %u, %u, 0x%08x },\n",
523 res.filter
[i
].code
, res.filter
[i
].jt
,
524 res.filter
[i
].jf
, res.filter
[i
].k
);
525 if
(labels
[i
] != NULL
)
527 if
(labels_jt
[i
] != NULL
)
529 if
(labels_jf
[i
] != NULL
)
531 if
(labels_k
[i
] != NULL
)
537 void yyerror(const char *err
)
539 panic
("Syntax error at line %d: %s! %s!\n",
540 yylineno
, yytext
, err
);