• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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