1 /*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #include "internal/internal.h"
11 #include "internal/stack.h"
12 #include <linux/filter.h>
13 #include <stddef.h> /* offsetof */
14
15 #ifndef SKF_AD_NLATTR
16 #define SKF_AD_NLATTR 12
17 #endif
18
19 /* this requires a Linux kernel >= 2.6.29 */
20 #ifndef SKF_AD_NLATTR_NEST
21 #define SKF_AD_NLATTR_NEST 16
22 #endif
23
24 #define NFCT_FILTER_REJECT 0U
25 #define NFCT_FILTER_ACCEPT ~0U
26
27 #if 0
28 static char *code2str(uint16_t code)
29 {
30 switch(code) {
31 case BPF_LD|BPF_IMM:
32 return "BPF_LD|BPF_IMM";
33 break;
34 case BPF_LDX|BPF_IMM:
35 return "BPF_LDX|BPF_IMM";
36 break;
37 case BPF_LD|BPF_B|BPF_ABS:
38 return "BPF_LD|BPF_B|BPF_ABS";
39 break;
40 case BPF_JMP|BPF_JEQ|BPF_K:
41 return "BPF_JMP|BPF_JEQ|BPF_K";
42 break;
43 case BPF_ALU|BPF_AND|BPF_K:
44 return "BPF_ALU|BPF_AND|BPF_K";
45 break;
46 case BPF_JMP|BPF_JA:
47 return "BPF_JMP|BPF_JA";
48 break;
49 case BPF_RET|BPF_K:
50 return "BPF_RET|BPF_K";
51 break;
52 case BPF_ALU|BPF_ADD|BPF_K:
53 return "BPF_ALU|BPF_ADD|BPF_K";
54 break;
55 case BPF_MISC|BPF_TAX:
56 return "BPF_MISC|BPF_TAX";
57 break;
58 case BPF_MISC|BPF_TXA:
59 return "BPF_MISC|BPF_TXA";
60 break;
61 case BPF_LD|BPF_B|BPF_IND:
62 return "BPF_LD|BPF_B|BPF_IND";
63 break;
64 case BPF_LD|BPF_H|BPF_IND:
65 return "BPF_LD|BPF_H|BPF_IND";
66 break;
67 case BPF_LD|BPF_W|BPF_IND:
68 return "BPF_LD|BPF_W|BPF_IND";
69 break;
70 }
71 return NULL;
72 }
73
74 static void show_filter(struct sock_filter *this, int from, int to, char *str)
75 {
76 int i;
77
78 printf("%s\n", str);
79
80 for(i=from; i<to; i++) {
81 char *code_str = code2str(this[i].code & 0xFFFF);
82
83 if (!code_str) {
84 printf("(%.4x) code=%.4x\t\t\tjt=%.2x jf=%.2x k=%.8x\n",
85 i,
86 this[i].code & 0xFFFF,
87 this[i].jt & 0xFF,
88 this[i].jf & 0xFF,
89 this[i].k & 0xFFFFFFFF);
90 } else {
91 printf("(%.4x) code=%30s\tjt=%.2x jf=%.2x k=%.8x\n",
92 i,
93 code_str,
94 this[i].jt & 0xFF,
95 this[i].jf & 0xFF,
96 this[i].k & 0xFFFFFFFF);
97 }
98 }
99 }
100 #else
101 static inline void
show_filter(struct sock_filter * this,int from,int to,char * str)102 show_filter(struct sock_filter *this, int from, int to, char *str) {}
103 #endif
104
105 #define NEW_POS(x) (sizeof(x)/sizeof(struct sock_filter))
106
107 static int
nfct_bsf_load_payload_offset(struct sock_filter * this,int pos)108 nfct_bsf_load_payload_offset(struct sock_filter *this, int pos)
109 {
110 struct sock_filter __code = {
111 .code = BPF_LD|BPF_IMM,
112 .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg),
113 };
114 memcpy(&this[pos], &__code, sizeof(__code));
115 return NEW_POS(__code);
116 }
117
118 static int
nfct_bsf_find_attr(struct sock_filter * this,int attr,int pos)119 nfct_bsf_find_attr(struct sock_filter *this, int attr, int pos)
120 {
121 struct sock_filter __code[] = {
122 [0] = {
123 /* X = attribute type */
124 .code = BPF_LDX|BPF_IMM,
125 .k = attr,
126 },
127 [1] = {
128 /* A = netlink attribute offset */
129 .code = BPF_LD|BPF_B|BPF_ABS,
130 .k = SKF_AD_OFF + SKF_AD_NLATTR,
131 }
132 };
133 memcpy(&this[pos], __code, sizeof(__code));
134 return NEW_POS(__code);
135 }
136
137 /* like the previous, but limit the search to the bound of the nest */
138 static int
nfct_bsf_find_attr_nest(struct sock_filter * this,int attr,int pos)139 nfct_bsf_find_attr_nest(struct sock_filter *this, int attr, int pos)
140 {
141 struct sock_filter __code[] = {
142 [0] = {
143 /* X = attribute type */
144 .code = BPF_LDX|BPF_IMM,
145 .k = attr,
146 },
147 [1] = {
148 /* A = netlink attribute offset */
149 .code = BPF_LD|BPF_B|BPF_ABS,
150 .k = SKF_AD_OFF + SKF_AD_NLATTR_NEST,
151 }
152 };
153 memcpy(&this[pos], __code, sizeof(__code));
154 return NEW_POS(__code);
155 }
156
157 struct jump {
158 int line;
159 uint8_t jt;
160 uint8_t jf;
161 };
162
163 static int
nfct_bsf_cmp_k_stack(struct sock_filter * this,int k,int jump_true,int pos,struct stack * s)164 nfct_bsf_cmp_k_stack(struct sock_filter *this, int k,
165 int jump_true, int pos, struct stack *s)
166 {
167 struct sock_filter __code = {
168 .code = BPF_JMP|BPF_JEQ|BPF_K,
169 .k = k,
170 };
171 struct jump jmp = {
172 .line = pos,
173 .jt = jump_true - 1,
174 .jf = 0,
175 };
176 stack_push(s, &jmp);
177 memcpy(&this[pos], &__code, sizeof(__code));
178 return NEW_POS(__code);
179 }
180
181 /* like previous, but use jf instead of jt. We can merge both functions */
182 static int
nfct_bsf_cmp_k_stack_jf(struct sock_filter * this,int k,int jump_false,int pos,struct stack * s)183 nfct_bsf_cmp_k_stack_jf(struct sock_filter *this, int k,
184 int jump_false, int pos, struct stack *s)
185 {
186 struct sock_filter __code = {
187 .code = BPF_JMP|BPF_JEQ|BPF_K,
188 .k = k,
189 };
190 struct jump jmp = {
191 .line = pos,
192 .jt = 0,
193 .jf = jump_false - 1,
194 };
195 stack_push(s, &jmp);
196 memcpy(&this[pos], &__code, sizeof(__code));
197 return NEW_POS(__code);
198 }
199
200 static int
nfct_bsf_alu_and(struct sock_filter * this,int k,int pos)201 nfct_bsf_alu_and(struct sock_filter *this, int k, int pos)
202 {
203 struct sock_filter __code = {
204 .code = BPF_ALU|BPF_AND|BPF_K,
205 .k = k,
206 };
207 memcpy(&this[pos], &__code, sizeof(__code));
208 return NEW_POS(__code);
209 }
210
211 static int
nfct_bsf_add_attr_data_offset(struct sock_filter * this,int pos)212 nfct_bsf_add_attr_data_offset(struct sock_filter *this, int pos)
213 {
214 struct sock_filter __code = {
215 /* A += sizeof(struct nfattr) */
216 .code = BPF_ALU|BPF_ADD|BPF_K,
217 .k = sizeof(struct nfattr),
218 };
219 memcpy(&this[pos], &__code, sizeof(__code));
220 return NEW_POS(__code);
221 }
222
223 static int
nfct_bsf_x_equal_a(struct sock_filter * this,int pos)224 nfct_bsf_x_equal_a(struct sock_filter *this, int pos)
225 {
226 struct sock_filter __code = {
227 .code = BPF_MISC|BPF_TAX,
228 };
229 memcpy(&this[pos], &__code, sizeof(__code));
230 return NEW_POS(__code);
231 }
232
233 static int
nfct_bsf_a_equal_x(struct sock_filter * this,int pos)234 nfct_bsf_a_equal_x(struct sock_filter *this, int pos)
235 {
236 struct sock_filter __code = {
237 .code = BPF_MISC|BPF_TXA,
238 };
239 memcpy(&this[pos], &__code, sizeof(__code));
240 return NEW_POS(__code);
241 }
242
243 static int
nfct_bsf_load_attr(struct sock_filter * this,int word_size,int pos)244 nfct_bsf_load_attr(struct sock_filter *this, int word_size, int pos)
245 {
246 struct sock_filter __code = {
247 /* A = skb->data[X + k:word_size] */
248 .code = BPF_LD|word_size|BPF_IND,
249 .k = sizeof(struct nfattr),
250
251 };
252 memcpy(&this[pos], &__code, sizeof(__code));
253 return NEW_POS(__code);
254 }
255
256 static int
nfct_bsf_load_attr_offset(struct sock_filter * this,int word_size,int offset,int pos)257 nfct_bsf_load_attr_offset(struct sock_filter *this, int word_size,
258 int offset, int pos)
259 {
260 struct sock_filter __code = {
261 /* A = skb->data[X + k:word_size] */
262 .code = BPF_LD|word_size|BPF_IND,
263 .k = sizeof(struct nfattr) + offset,
264 };
265 memcpy(&this[pos], &__code, sizeof(__code));
266 return NEW_POS(__code);
267 }
268
269 static int
nfct_bsf_ret_verdict(struct sock_filter * this,int verdict,int pos)270 nfct_bsf_ret_verdict(struct sock_filter *this, int verdict, int pos)
271 {
272 struct sock_filter __code = {
273 .code = BPF_RET|BPF_K,
274 .k = verdict,
275 };
276 memcpy(&this[pos], &__code, sizeof(__code));
277 return NEW_POS(__code);
278 }
279
280 static int
nfct_bsf_jump_to(struct sock_filter * this,int line,int pos)281 nfct_bsf_jump_to(struct sock_filter *this, int line, int pos)
282 {
283 struct sock_filter __code = {
284 .code = BPF_JMP|BPF_JA,
285 .k = line,
286 };
287 memcpy(&this[pos], &__code, sizeof(__code));
288 return NEW_POS(__code);
289 };
290
291 /* this helps to skip messages coming from the ctnetlink expectation subsys. */
292 static int
bsf_cmp_subsys(struct sock_filter * this,int pos,uint8_t subsys)293 bsf_cmp_subsys(struct sock_filter *this, int pos, uint8_t subsys)
294 {
295 struct sock_filter __code[] = {
296 [0] = {
297 /* X = offset to nlh->nlmsg_type */
298 .code = BPF_LDX|BPF_IMM,
299 .k = offsetof(struct nlmsghdr, nlmsg_type),
300 },
301 [1] = {
302 /* A = skb->data[X+k:B] (subsys_id) */
303 .code = BPF_LD|BPF_B|BPF_IND,
304 .k = sizeof(uint8_t),
305 },
306 [2] = {
307 /* A == subsys ? jump +1 : accept */
308 .code = BPF_JMP|BPF_JEQ|BPF_K,
309 .k = subsys,
310 .jt = 1,
311 .jf = 0,
312 },
313 };
314 memcpy(&this[pos], &__code, sizeof(__code));
315 return NEW_POS(__code);
316 }
317
318 static int
add_state_filter_cta(struct sock_filter * this,unsigned int cta_protoinfo_proto,unsigned int cta_protoinfo_state,uint16_t state_flags,unsigned int logic)319 add_state_filter_cta(struct sock_filter *this,
320 unsigned int cta_protoinfo_proto,
321 unsigned int cta_protoinfo_state,
322 uint16_t state_flags,
323 unsigned int logic)
324 {
325 unsigned int i, j;
326 unsigned int label_continue, jt;
327 struct stack *s;
328 struct jump jmp;
329
330 /* XXX: 32 maximum states + 3 jumps in the three-level iteration */
331 s = stack_create(sizeof(struct jump), 3 + 32);
332 if (s == NULL) {
333 errno = ENOMEM;
334 return -1;
335 }
336
337 jt = 1;
338 if (logic == NFCT_FILTER_LOGIC_POSITIVE)
339 label_continue = 1;
340 else
341 label_continue = 2;
342
343 j = 0;
344 j += nfct_bsf_load_payload_offset(this, j);
345 j += nfct_bsf_find_attr(this, CTA_PROTOINFO, j);
346 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
347 j += nfct_bsf_add_attr_data_offset(this, j);
348 j += nfct_bsf_find_attr(this, cta_protoinfo_proto, j);
349 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
350 j += nfct_bsf_add_attr_data_offset(this, j);
351 j += nfct_bsf_find_attr(this, cta_protoinfo_state, j);
352 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
353 j += nfct_bsf_x_equal_a(this, j);
354 j += nfct_bsf_load_attr(this, BPF_B, j);
355
356 for (i = 0; i < sizeof(state_flags) * 8; i++) {
357 if (state_flags & (1 << i)) {
358 j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
359 }
360 }
361
362 while (stack_pop(s, &jmp) != -1)
363 this[jmp.line].jt += jmp.jt + j;
364
365 if (logic == NFCT_FILTER_LOGIC_NEGATIVE)
366 j += nfct_bsf_jump_to(this, 1, j);
367
368 j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
369
370 stack_destroy(s);
371
372 return j;
373 }
374
375 static int
add_state_filter(struct sock_filter * this,int proto,uint16_t flags,unsigned int logic)376 add_state_filter(struct sock_filter *this,
377 int proto,
378 uint16_t flags,
379 unsigned int logic)
380 {
381 static const struct {
382 unsigned int cta_protoinfo;
383 unsigned int cta_state;
384 } cta[IPPROTO_MAX] = {
385 [IPPROTO_TCP] = {
386 .cta_protoinfo = CTA_PROTOINFO_TCP,
387 .cta_state = CTA_PROTOINFO_TCP_STATE,
388 },
389 [IPPROTO_SCTP] = {
390 .cta_protoinfo = CTA_PROTOINFO_SCTP,
391 .cta_state = CTA_PROTOINFO_SCTP_STATE,
392 },
393 [IPPROTO_DCCP] = {
394 .cta_protoinfo = CTA_PROTOINFO_DCCP,
395 .cta_state = CTA_PROTOINFO_DCCP_STATE,
396 },
397 };
398
399 if (cta[proto].cta_protoinfo == 0 && cta[proto].cta_state == 0) {
400 errno = ENOTSUP;
401 return -1;
402 }
403
404 return add_state_filter_cta(this,
405 cta[proto].cta_protoinfo,
406 cta[proto].cta_state,
407 flags,
408 logic);
409 }
410
411 static int
bsf_add_state_filter(const struct nfct_filter * filter,struct sock_filter * this)412 bsf_add_state_filter(const struct nfct_filter *filter, struct sock_filter *this)
413 {
414 unsigned int i, j;
415
416 for (i = 0, j = 0; i < IPPROTO_MAX; i++) {
417 if (filter->l4proto_state[i].map &&
418 filter->l4proto_state[i].len > 0) {
419 j += add_state_filter(
420 this,
421 i,
422 filter->l4proto_state[i].map,
423 filter->logic[NFCT_FILTER_L4PROTO_STATE]);
424 }
425 }
426
427 return j;
428 }
429
430 static int
bsf_add_proto_filter(const struct nfct_filter * f,struct sock_filter * this)431 bsf_add_proto_filter(const struct nfct_filter *f, struct sock_filter *this)
432 {
433 unsigned int i, j;
434 unsigned int label_continue, jt;
435 struct stack *s;
436 struct jump jmp;
437
438 /* nothing to filter, skip */
439 if (f->l4proto_len == 0)
440 return 0;
441
442 /* XXX: 255 maximum proto + 3 jumps in the three-level iteration */
443 s = stack_create(sizeof(struct jump), 3 + 255);
444 if (s == NULL) {
445 errno = ENOMEM;
446 return -1;
447 }
448
449 jt = 1;
450 if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_POSITIVE)
451 label_continue = 1;
452 else
453 label_continue = 2;
454
455 j = 0;
456 j += nfct_bsf_load_payload_offset(this, j);
457 j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
458 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
459 j += nfct_bsf_add_attr_data_offset(this, j);
460 j += nfct_bsf_find_attr(this, CTA_TUPLE_PROTO, j);
461 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
462 j += nfct_bsf_add_attr_data_offset(this, j);
463 j += nfct_bsf_find_attr(this, CTA_PROTO_NUM, j);
464 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
465 j += nfct_bsf_x_equal_a(this, j);
466 j += nfct_bsf_load_attr(this, BPF_B, j);
467
468 for (i = 0; i < IPPROTO_MAX; i++) {
469 if (test_bit(i, f->l4proto_map)) {
470 j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
471 }
472 }
473
474 while (stack_pop(s, &jmp) != -1)
475 this[jmp.line].jt += jmp.jt + j;
476
477 if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_NEGATIVE)
478 j += nfct_bsf_jump_to(this, 1, j);
479
480 j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
481
482 stack_destroy(s);
483
484 return j;
485 }
486
487 static int
bsf_add_addr_ipv4_filter(const struct nfct_filter * f,struct sock_filter * this,unsigned int type)488 bsf_add_addr_ipv4_filter(const struct nfct_filter *f,
489 struct sock_filter *this,
490 unsigned int type)
491 {
492 unsigned int i, j, dir, attr;
493 unsigned int label_continue, jt;
494 struct stack *s;
495 struct jump jmp;
496
497 switch(type) {
498 case CTA_IP_V4_SRC:
499 dir = __FILTER_ADDR_SRC;
500 attr = NFCT_FILTER_SRC_IPV4;
501 break;
502 case CTA_IP_V4_DST:
503 dir = __FILTER_ADDR_DST;
504 attr = NFCT_FILTER_DST_IPV4;
505 break;
506 default:
507 return 0;
508 }
509
510 /* nothing to filter, skip */
511 if (f->l3proto_elems[dir] == 0)
512 return 0;
513
514 /* XXX: 127 maximum IPs + 3 jumps in the three-level iteration */
515 s = stack_create(sizeof(struct jump), 3 + 127);
516 if (s == NULL) {
517 errno = ENOMEM;
518 return -1;
519 }
520
521 jt = 1;
522 if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE)
523 label_continue = 1;
524 else
525 label_continue = 2;
526
527 j = 0;
528 j += nfct_bsf_load_payload_offset(this, j);
529 j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
530 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
531 j += nfct_bsf_add_attr_data_offset(this, j);
532 j += nfct_bsf_find_attr(this, CTA_TUPLE_IP, j);
533 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
534 j += nfct_bsf_add_attr_data_offset(this, j);
535 j += nfct_bsf_find_attr(this, type, j);
536 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
537 j += nfct_bsf_x_equal_a(this, j);
538
539 for (i = 0; i < f->l3proto_elems[dir]; i++) {
540 int ip = f->l3proto[dir][i].addr & f->l3proto[dir][i].mask;
541
542 j += nfct_bsf_load_attr(this, BPF_W, j);
543 j += nfct_bsf_alu_and(this, f->l3proto[dir][i].mask, j);
544 j += nfct_bsf_cmp_k_stack(this, ip, jt - j, j, s);
545 }
546
547 while (stack_pop(s, &jmp) != -1)
548 this[jmp.line].jt += jmp.jt + j;
549
550 if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE)
551 j += nfct_bsf_jump_to(this, 1, j);
552
553 j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
554
555 stack_destroy(s);
556
557 return j;
558 }
559
560 static int
bsf_add_saddr_ipv4_filter(const struct nfct_filter * f,struct sock_filter * this)561 bsf_add_saddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
562 {
563 return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_SRC);
564 }
565
566 static int
bsf_add_daddr_ipv4_filter(const struct nfct_filter * f,struct sock_filter * this)567 bsf_add_daddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
568 {
569 return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_DST);
570 }
571
572 static int
bsf_add_addr_ipv6_filter(const struct nfct_filter * f,struct sock_filter * this,unsigned int type)573 bsf_add_addr_ipv6_filter(const struct nfct_filter *f,
574 struct sock_filter *this,
575 unsigned int type)
576 {
577 unsigned int i, j, dir, attr;
578 unsigned int label_continue, jf;
579 struct stack *s;
580 struct jump jmp;
581
582 switch(type) {
583 case CTA_IP_V6_SRC:
584 dir = __FILTER_ADDR_SRC;
585 attr = NFCT_FILTER_SRC_IPV6;
586 break;
587 case CTA_IP_V6_DST:
588 dir = __FILTER_ADDR_DST;
589 attr = NFCT_FILTER_DST_IPV6;
590 break;
591 default:
592 return 0;
593 }
594
595 /* nothing to filter, skip */
596 if (f->l3proto_elems_ipv6[dir] == 0)
597 return 0;
598
599 /* XXX: 80 jumps (4*20) + 3 jumps in the three-level iteration */
600 s = stack_create(sizeof(struct jump), 3 + 80);
601 if (s == NULL) {
602 errno = ENOMEM;
603 return -1;
604 }
605
606 jf = 1;
607 if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE) {
608 label_continue = 1;
609 } else {
610 label_continue = 2;
611 }
612
613 j = 0;
614 j += nfct_bsf_load_payload_offset(this, j);
615 j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
616 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
617 /* no need to access attribute payload, we are using nest-based finder
618 * j += nfct_bsf_add_attr_data_offset(this, j); */
619 j += nfct_bsf_find_attr_nest(this, CTA_TUPLE_IP, j);
620 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
621 j += nfct_bsf_find_attr_nest(this, type, j);
622 j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
623 j += nfct_bsf_x_equal_a(this, j);
624
625 for (i = 0; i < f->l3proto_elems_ipv6[dir]; i++) {
626 int k, offset;
627
628 for (k = 0, offset = 0; k < 4; k++, offset += 4) {
629 int ip = f->l3proto_ipv6[dir][i].addr[k] &
630 f->l3proto_ipv6[dir][i].mask[k];
631
632 j += nfct_bsf_load_attr_offset(this, BPF_W, offset, j);
633 j += nfct_bsf_alu_and(this,
634 f->l3proto_ipv6[dir][i].mask[k],
635 j);
636 if (k < 3) {
637 j += nfct_bsf_cmp_k_stack_jf(this, ip,
638 jf - j - 1,
639 j, s);
640 } else {
641 /* last word: jump if true */
642 j += nfct_bsf_cmp_k_stack(this, ip, jf - j,
643 j, s);
644 }
645 }
646 }
647
648 while (stack_pop(s, &jmp) != -1) {
649 if (jmp.jt) {
650 this[jmp.line].jt += jmp.jt + j;
651 }
652 if (jmp.jf) {
653 this[jmp.line].jf += jmp.jf + j;
654 }
655 }
656
657 if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE)
658 j += nfct_bsf_jump_to(this, 1, j);
659
660 j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
661
662 stack_destroy(s);
663
664 return j;
665 }
666
667 static int
bsf_add_saddr_ipv6_filter(const struct nfct_filter * f,struct sock_filter * this)668 bsf_add_saddr_ipv6_filter(const struct nfct_filter *f, struct sock_filter *this)
669 {
670 return bsf_add_addr_ipv6_filter(f, this, CTA_IP_V6_SRC);
671 }
672
673 static int
bsf_add_daddr_ipv6_filter(const struct nfct_filter * f,struct sock_filter * this)674 bsf_add_daddr_ipv6_filter(const struct nfct_filter *f, struct sock_filter *this)
675 {
676 return bsf_add_addr_ipv6_filter(f, this, CTA_IP_V6_DST);
677 }
678
679 static int
bsf_add_mark_filter(const struct nfct_filter * f,struct sock_filter * this)680 bsf_add_mark_filter(const struct nfct_filter *f, struct sock_filter *this)
681 {
682 unsigned int i, j;
683 unsigned int jt;
684 struct stack *s;
685 struct jump jmp;
686 struct sock_filter __code = {
687 /* if (A == 0) skip next two */
688 .code = BPF_JMP|BPF_JEQ|BPF_K,
689 .k = 0,
690 .jt = 2,
691 .jf = 0,
692 };
693
694 /* nothing to filter, skip */
695 if (f->mark_elems == 0)
696 return 0;
697
698 /* XXX: see bsf_add_addr_ipv4_filter() */
699 s = stack_create(sizeof(struct jump), 3 + 127);
700 if (s == NULL) {
701 errno = ENOMEM;
702 return -1;
703 }
704
705 jt = 1;
706 j = 0;
707 j += nfct_bsf_load_payload_offset(this, j); /* A = nla header offset */
708 j += nfct_bsf_find_attr(this, CTA_MARK, j); /* A = CTA_MARK offset, started from A */
709 memcpy(&this[j], &__code, sizeof(__code)); /* if A == 0 skip next two op */
710 j += NEW_POS(__code);
711 j += nfct_bsf_x_equal_a(this, j); /* X = A <CTA_MARK offset> */
712 j += nfct_bsf_load_attr(this, BPF_W, j); /* A = skb->data[X:X + BPF_W] */
713 j += nfct_bsf_x_equal_a(this, j); /* X = A <CTA_MARK value> */
714
715 for (i = 0; i < f->mark_elems; i++) {
716 int mark = f->mark[i].val & f->mark[i].mask;
717
718 j += nfct_bsf_alu_and(this, f->mark[i].mask, j);
719 j += nfct_bsf_cmp_k_stack(this, mark, jt - j, j, s);
720 j += nfct_bsf_a_equal_x(this, j);
721 }
722
723 while (stack_pop(s, &jmp) != -1)
724 this[jmp.line].jt += jmp.jt + j;
725
726 if (f->logic[NFCT_FILTER_MARK] == NFCT_FILTER_LOGIC_NEGATIVE)
727 j += nfct_bsf_jump_to(this, 1, j);
728
729 j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
730
731 stack_destroy(s);
732
733 return j;
734 }
735
736 /* this buffer must be big enough to store all the autogenerated lines */
737 #define BSF_BUFFER_SIZE 2048
738
__setup_netlink_socket_filter(int fd,struct nfct_filter * f)739 int __setup_netlink_socket_filter(int fd, struct nfct_filter *f)
740 {
741 struct sock_filter bsf[BSF_BUFFER_SIZE];
742 struct sock_fprog sf;
743 unsigned int j = 0, from = 0;
744
745 memset(bsf, 0, sizeof(bsf));
746
747 j += bsf_cmp_subsys(&bsf[j], j, NFNL_SUBSYS_CTNETLINK);
748 j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j);
749 show_filter(bsf, from, j, "--- check subsys ---");
750 from = j;
751 j += bsf_add_proto_filter(f, &bsf[j]);
752 show_filter(bsf, from, j, "---- check proto ----");
753 from = j;
754 j += bsf_add_saddr_ipv4_filter(f, &bsf[j]);
755 show_filter(bsf, from, j, "---- check src IPv4 ----");
756 from = j;
757 j += bsf_add_daddr_ipv4_filter(f, &bsf[j]);
758 show_filter(bsf, from, j, "---- check dst IPv4 ----");
759 from = j;
760 j += bsf_add_saddr_ipv6_filter(f, &bsf[j]);
761 show_filter(bsf, from, j, "---- check src IPv6 ----");
762 from = j;
763 j += bsf_add_daddr_ipv6_filter(f, &bsf[j]);
764 show_filter(bsf, from, j, "---- check dst IPv6 ----");
765 from = j;
766 j += bsf_add_state_filter(f, &bsf[j]);
767 show_filter(bsf, from, j, "---- check state ----");
768 from = j;
769 j += bsf_add_mark_filter(f, &bsf[j]);
770 show_filter(bsf, from, j, "---- check mark ----");
771 from = j;
772
773 /* nothing to filter, skip */
774 if (j == 0)
775 return 0;
776
777 j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j);
778 show_filter(bsf, from, j, "---- final verdict ----");
779 from = j;
780
781 sf.len = (sizeof(struct sock_filter) * j) / sizeof(bsf[0]);
782 sf.filter = bsf;
783
784 return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &sf, sizeof(sf));
785 }
786