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