Home | History | Annotate | Download | only in conntrack
      1 /*
      2  * (C) 2005-2011 by Pablo Neira Ayuso <pablo (at) 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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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