libiptc.c revision c0aa38e22e8a09fcb1898ad0e042eaf6314d2d42
1/* Library which manipulates firewall rules. Version $Revision$ */ 2 3/* Architecture of firewall rules is as follows: 4 * 5 * Chains go INPUT, FORWARD, OUTPUT then user chains. 6 * Each user chain starts with an ERROR node. 7 * Every chain ends with an unconditional jump: a RETURN for user chains, 8 * and a POLICY for built-ins. 9 */ 10 11/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See 12 * COPYING for details). 13 * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org> 14 * 15 * 2003-Jun-20: Harald Welte <laforge@netfilter.org>: 16 * - Reimplementation of chain cache to use offsets instead of entries 17 * 2003-Jun-23: Harald Welte <laforge@netfilter.org>: 18 * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/) 19 * don't rebuild the chain cache after every operation, instead fix it 20 * up after a ruleset change. 21 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>: 22 * - further performance work: total reimplementation of libiptc. 23 * - libiptc now has a real internal (linked-list) represntation of the 24 * ruleset and a parser/compiler from/to this internal representation 25 * - again sponsored by Astaro AG (http://www.astaro.com/) 26 * 27 * 2008-Jan+Jul: Jesper Dangaard Brouer <hawk@comx.dk> 28 * - performance work: speedup chain list "name" searching. 29 * - performance work: speedup initial ruleset parsing. 30 * - sponsored by ComX Networks A/S (http://www.comx.dk/) 31 */ 32#include <unistd.h> 33#include <fcntl.h> 34#include <sys/types.h> 35#include <sys/socket.h> 36#include <stdbool.h> 37#include <xtables.h> 38#include <libiptc/xtcshared.h> 39 40#include "linux_list.h" 41 42//#define IPTC_DEBUG2 1 43 44#ifdef IPTC_DEBUG2 45#include <fcntl.h> 46#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args) 47#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args) 48#else 49#define DEBUGP(x, args...) 50#define DEBUGP_C(x, args...) 51#endif 52 53#ifdef DEBUG 54#define debug(x, args...) fprintf(stderr, x, ## args) 55#else 56#define debug(x, args...) 57#endif 58 59static void *iptc_fn = NULL; 60 61static const char *hooknames[] = { 62 [HOOK_PRE_ROUTING] = "PREROUTING", 63 [HOOK_LOCAL_IN] = "INPUT", 64 [HOOK_FORWARD] = "FORWARD", 65 [HOOK_LOCAL_OUT] = "OUTPUT", 66 [HOOK_POST_ROUTING] = "POSTROUTING", 67}; 68 69/* Convenience structures */ 70struct chain_head; 71struct rule_head; 72 73struct counter_map 74{ 75 enum { 76 COUNTER_MAP_NOMAP, 77 COUNTER_MAP_NORMAL_MAP, 78 COUNTER_MAP_ZEROED, 79 COUNTER_MAP_SET 80 } maptype; 81 unsigned int mappos; 82}; 83 84enum iptcc_rule_type { 85 IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */ 86 IPTCC_R_MODULE, /* extension module (SNAT, ...) */ 87 IPTCC_R_FALLTHROUGH, /* fallthrough rule */ 88 IPTCC_R_JUMP, /* jump to other chain */ 89}; 90 91struct rule_head 92{ 93 struct list_head list; 94 struct chain_head *chain; 95 struct counter_map counter_map; 96 97 unsigned int index; /* index (needed for counter_map) */ 98 unsigned int offset; /* offset in rule blob */ 99 100 enum iptcc_rule_type type; 101 struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */ 102 103 unsigned int size; /* size of entry data */ 104 STRUCT_ENTRY entry[0]; 105}; 106 107struct chain_head 108{ 109 struct list_head list; 110 char name[TABLE_MAXNAMELEN]; 111 unsigned int hooknum; /* hook number+1 if builtin */ 112 unsigned int references; /* how many jumps reference us */ 113 int verdict; /* verdict if builtin */ 114 115 STRUCT_COUNTERS counters; /* per-chain counters */ 116 struct counter_map counter_map; 117 118 unsigned int num_rules; /* number of rules in list */ 119 struct list_head rules; /* list of rules */ 120 121 unsigned int index; /* index (needed for jump resolval) */ 122 unsigned int head_offset; /* offset in rule blob */ 123 unsigned int foot_index; /* index (needed for counter_map) */ 124 unsigned int foot_offset; /* offset in rule blob */ 125}; 126 127struct xtc_handle { 128 int sockfd; 129 int changed; /* Have changes been made? */ 130 131 struct list_head chains; 132 133 struct chain_head *chain_iterator_cur; 134 struct rule_head *rule_iterator_cur; 135 136 unsigned int num_chains; /* number of user defined chains */ 137 138 struct chain_head **chain_index; /* array for fast chain list access*/ 139 unsigned int chain_index_sz;/* size of chain index array */ 140 141 int sorted_offsets; /* if chains are received sorted from kernel, 142 * then the offsets are also sorted. Says if its 143 * possible to bsearch offsets using chain_index. 144 */ 145 146 STRUCT_GETINFO info; 147 STRUCT_GET_ENTRIES *entries; 148}; 149 150enum bsearch_type { 151 BSEARCH_NAME, /* Binary search after chain name */ 152 BSEARCH_OFFSET, /* Binary search based on offset */ 153}; 154 155/* allocate a new chain head for the cache */ 156static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum) 157{ 158 struct chain_head *c = malloc(sizeof(*c)); 159 if (!c) 160 return NULL; 161 memset(c, 0, sizeof(*c)); 162 163 strncpy(c->name, name, TABLE_MAXNAMELEN); 164 c->hooknum = hooknum; 165 INIT_LIST_HEAD(&c->rules); 166 167 return c; 168} 169 170/* allocate and initialize a new rule for the cache */ 171static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size) 172{ 173 struct rule_head *r = malloc(sizeof(*r)+size); 174 if (!r) 175 return NULL; 176 memset(r, 0, sizeof(*r)); 177 178 r->chain = c; 179 r->size = size; 180 181 return r; 182} 183 184/* notify us that the ruleset has been modified by the user */ 185static inline void 186set_changed(struct xtc_handle *h) 187{ 188 h->changed = 1; 189} 190 191#ifdef IPTC_DEBUG 192static void do_check(struct xtc_handle *h, unsigned int line); 193#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) 194#else 195#define CHECK(h) 196#endif 197 198 199/********************************************************************** 200 * iptc blob utility functions (iptcb_*) 201 **********************************************************************/ 202 203static inline int 204iptcb_get_number(const STRUCT_ENTRY *i, 205 const STRUCT_ENTRY *seek, 206 unsigned int *pos) 207{ 208 if (i == seek) 209 return 1; 210 (*pos)++; 211 return 0; 212} 213 214static inline int 215iptcb_get_entry_n(STRUCT_ENTRY *i, 216 unsigned int number, 217 unsigned int *pos, 218 STRUCT_ENTRY **pe) 219{ 220 if (*pos == number) { 221 *pe = i; 222 return 1; 223 } 224 (*pos)++; 225 return 0; 226} 227 228static inline STRUCT_ENTRY * 229iptcb_get_entry(struct xtc_handle *h, unsigned int offset) 230{ 231 return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset); 232} 233 234static unsigned int 235iptcb_entry2index(struct xtc_handle *const h, const STRUCT_ENTRY *seek) 236{ 237 unsigned int pos = 0; 238 239 if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size, 240 iptcb_get_number, seek, &pos) == 0) { 241 fprintf(stderr, "ERROR: offset %u not an entry!\n", 242 (unsigned int)((char *)seek - (char *)h->entries->entrytable)); 243 abort(); 244 } 245 return pos; 246} 247 248static inline STRUCT_ENTRY * 249iptcb_offset2entry(struct xtc_handle *h, unsigned int offset) 250{ 251 return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset); 252} 253 254 255static inline unsigned long 256iptcb_entry2offset(struct xtc_handle *const h, const STRUCT_ENTRY *e) 257{ 258 return (void *)e - (void *)h->entries->entrytable; 259} 260 261static inline unsigned int 262iptcb_offset2index(struct xtc_handle *const h, unsigned int offset) 263{ 264 return iptcb_entry2index(h, iptcb_offset2entry(h, offset)); 265} 266 267/* Returns 0 if not hook entry, else hooknumber + 1 */ 268static inline unsigned int 269iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, struct xtc_handle *h) 270{ 271 unsigned int i; 272 273 for (i = 0; i < NUMHOOKS; i++) { 274 if ((h->info.valid_hooks & (1 << i)) 275 && iptcb_get_entry(h, h->info.hook_entry[i]) == e) 276 return i+1; 277 } 278 return 0; 279} 280 281 282/********************************************************************** 283 * Chain index (cache utility) functions 284 ********************************************************************** 285 * The chain index is an array with pointers into the chain list, with 286 * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to 287 * speedup chain list searching, by find a more optimal starting 288 * points when searching the linked list. 289 * 290 * The starting point can be found fast by using a binary search of 291 * the chain index. Thus, reducing the previous search complexity of 292 * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN. 293 * 294 * A nice property of the chain index, is that the "bucket" list 295 * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will 296 * change this). Oppose to hashing, where the "bucket" list length can 297 * vary a lot. 298 */ 299#ifndef CHAIN_INDEX_BUCKET_LEN 300#define CHAIN_INDEX_BUCKET_LEN 40 301#endif 302 303/* Another nice property of the chain index is that inserting/creating 304 * chains in chain list don't change the correctness of the chain 305 * index, it only causes longer lists in the buckets. 306 * 307 * To mitigate the performance penalty of longer bucket lists and the 308 * penalty of rebuilding, the chain index is rebuild only when 309 * CHAIN_INDEX_INSERT_MAX chains has been added. 310 */ 311#ifndef CHAIN_INDEX_INSERT_MAX 312#define CHAIN_INDEX_INSERT_MAX 355 313#endif 314 315static inline unsigned int iptcc_is_builtin(struct chain_head *c); 316 317/* Use binary search in the chain index array, to find a chain_head 318 * pointer closest to the place of the searched name element. 319 * 320 * Notes that, binary search (obviously) requires that the chain list 321 * is sorted by name. 322 * 323 * The not so obvious: The chain index array, is actually both sorted 324 * by name and offset, at the same time!. This is only true because, 325 * chain are stored sorted in the kernel (as we pushed it in sorted). 326 * 327 */ 328static struct list_head * 329__iptcc_bsearch_chain_index(const char *name, unsigned int offset, 330 unsigned int *idx, struct xtc_handle *handle, 331 enum bsearch_type type) 332{ 333 unsigned int pos, end; 334 int res; 335 336 struct list_head *list_pos; 337 list_pos=&handle->chains; 338 339 /* Check for empty array, e.g. no user defined chains */ 340 if (handle->chain_index_sz == 0) { 341 debug("WARNING: handle->chain_index_sz == 0\n"); 342 return list_pos; 343 } 344 345 /* Init */ 346 end = handle->chain_index_sz; 347 pos = end / 2; 348 349 debug("bsearch Find chain:%s (pos:%d end:%d) (offset:%d)\n", 350 name, pos, end, offset); 351 352 /* Loop */ 353 loop: 354 if (!handle->chain_index[pos]) { 355 fprintf(stderr, "ERROR: NULL pointer chain_index[%d]\n", pos); 356 return &handle->chains; /* Be safe, return orig start pos */ 357 } 358 359 debug("bsearch Index[%d] name:%s ", 360 pos, handle->chain_index[pos]->name); 361 362 /* Support for different compare functions */ 363 switch (type) { 364 case BSEARCH_NAME: 365 res = strcmp(name, handle->chain_index[pos]->name); 366 break; 367 case BSEARCH_OFFSET: 368 debug("head_offset:[%d] foot_offset:[%d] ", 369 handle->chain_index[pos]->head_offset, 370 handle->chain_index[pos]->foot_offset); 371 res = offset - handle->chain_index[pos]->head_offset; 372 break; 373 default: 374 fprintf(stderr, "ERROR: %d not a valid bsearch type\n", 375 type); 376 abort(); 377 break; 378 } 379 debug("res:%d ", res); 380 381 382 list_pos = &handle->chain_index[pos]->list; 383 *idx = pos; 384 385 if (res == 0) { /* Found element, by direct hit */ 386 debug("[found] Direct hit pos:%d end:%d\n", pos, end); 387 return list_pos; 388 } else if (res < 0) { /* Too far, jump back */ 389 end = pos; 390 pos = pos / 2; 391 392 /* Exit case: First element of array */ 393 if (end == 0) { 394 debug("[found] Reached first array elem (end%d)\n",end); 395 return list_pos; 396 } 397 debug("jump back to pos:%d (end:%d)\n", pos, end); 398 goto loop; 399 } else { /* res > 0; Not far enough, jump forward */ 400 401 /* Exit case: Last element of array */ 402 if (pos == handle->chain_index_sz-1) { 403 debug("[found] Last array elem (end:%d)\n", end); 404 return list_pos; 405 } 406 407 /* Exit case: Next index less, thus elem in this list section */ 408 switch (type) { 409 case BSEARCH_NAME: 410 res = strcmp(name, handle->chain_index[pos+1]->name); 411 break; 412 case BSEARCH_OFFSET: 413 res = offset - handle->chain_index[pos+1]->head_offset; 414 break; 415 } 416 417 if (res < 0) { 418 debug("[found] closest list (end:%d)\n", end); 419 return list_pos; 420 } 421 422 pos = (pos+end)/2; 423 debug("jump forward to pos:%d (end:%d)\n", pos, end); 424 goto loop; 425 } 426} 427 428/* Wrapper for string chain name based bsearch */ 429static struct list_head * 430iptcc_bsearch_chain_index(const char *name, unsigned int *idx, 431 struct xtc_handle *handle) 432{ 433 return __iptcc_bsearch_chain_index(name, 0, idx, handle, BSEARCH_NAME); 434} 435 436 437/* Wrapper for offset chain based bsearch */ 438static struct list_head * 439iptcc_bsearch_chain_offset(unsigned int offset, unsigned int *idx, 440 struct xtc_handle *handle) 441{ 442 struct list_head *pos; 443 444 /* If chains were not received sorted from kernel, then the 445 * offset bsearch is not possible. 446 */ 447 if (!handle->sorted_offsets) 448 pos = handle->chains.next; 449 else 450 pos = __iptcc_bsearch_chain_index(NULL, offset, idx, handle, 451 BSEARCH_OFFSET); 452 return pos; 453} 454 455 456#ifdef DEBUG 457/* Trivial linear search of chain index. Function used for verifying 458 the output of bsearch function */ 459static struct list_head * 460iptcc_linearly_search_chain_index(const char *name, struct xtc_handle *handle) 461{ 462 unsigned int i=0; 463 int res=0; 464 465 struct list_head *list_pos; 466 list_pos = &handle->chains; 467 468 if (handle->chain_index_sz) 469 list_pos = &handle->chain_index[0]->list; 470 471 /* Linearly walk of chain index array */ 472 473 for (i=0; i < handle->chain_index_sz; i++) { 474 if (handle->chain_index[i]) { 475 res = strcmp(handle->chain_index[i]->name, name); 476 if (res > 0) 477 break; // One step too far 478 list_pos = &handle->chain_index[i]->list; 479 if (res == 0) 480 break; // Direct hit 481 } 482 } 483 484 return list_pos; 485} 486#endif 487 488static int iptcc_chain_index_alloc(struct xtc_handle *h) 489{ 490 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN; 491 unsigned int array_elems; 492 unsigned int array_mem; 493 494 /* Allocate memory for the chain index array */ 495 array_elems = (h->num_chains / list_length) + 496 (h->num_chains % list_length ? 1 : 0); 497 array_mem = sizeof(h->chain_index) * array_elems; 498 499 debug("Alloc Chain index, elems:%d mem:%d bytes\n", 500 array_elems, array_mem); 501 502 h->chain_index = malloc(array_mem); 503 if (h->chain_index == NULL && array_mem > 0) { 504 h->chain_index_sz = 0; 505 return -ENOMEM; 506 } 507 memset(h->chain_index, 0, array_mem); 508 h->chain_index_sz = array_elems; 509 510 return 1; 511} 512 513static void iptcc_chain_index_free(struct xtc_handle *h) 514{ 515 h->chain_index_sz = 0; 516 free(h->chain_index); 517} 518 519 520#ifdef DEBUG 521static void iptcc_chain_index_dump(struct xtc_handle *h) 522{ 523 unsigned int i = 0; 524 525 /* Dump: contents of chain index array */ 526 for (i=0; i < h->chain_index_sz; i++) { 527 if (h->chain_index[i]) { 528 fprintf(stderr, "Chain index[%d].name: %s\n", 529 i, h->chain_index[i]->name); 530 } 531 } 532} 533#endif 534 535/* Build the chain index */ 536static int iptcc_chain_index_build(struct xtc_handle *h) 537{ 538 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN; 539 unsigned int chains = 0; 540 unsigned int cindex = 0; 541 struct chain_head *c; 542 543 /* Build up the chain index array here */ 544 debug("Building chain index\n"); 545 546 debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n", 547 h->num_chains, list_length, h->chain_index_sz); 548 549 if (h->chain_index_sz == 0) 550 return 0; 551 552 list_for_each_entry(c, &h->chains, list) { 553 554 /* Issue: The index array needs to start after the 555 * builtin chains, as they are not sorted */ 556 if (!iptcc_is_builtin(c)) { 557 cindex=chains / list_length; 558 559 /* Safe guard, break out on array limit, this 560 * is useful if chains are added and array is 561 * rebuild, without realloc of memory. */ 562 if (cindex >= h->chain_index_sz) 563 break; 564 565 if ((chains % list_length)== 0) { 566 debug("\nIndex[%d] Chains:", cindex); 567 h->chain_index[cindex] = c; 568 } 569 chains++; 570 } 571 debug("%s, ", c->name); 572 } 573 debug("\n"); 574 575 return 1; 576} 577 578static int iptcc_chain_index_rebuild(struct xtc_handle *h) 579{ 580 debug("REBUILD chain index array\n"); 581 iptcc_chain_index_free(h); 582 if ((iptcc_chain_index_alloc(h)) < 0) 583 return -ENOMEM; 584 iptcc_chain_index_build(h); 585 return 1; 586} 587 588/* Delete chain (pointer) from index array. Removing an element from 589 * the chain list only affects the chain index array, if the chain 590 * index points-to/uses that list pointer. 591 * 592 * There are different strategies, the simple and safe is to rebuild 593 * the chain index every time. The more advanced is to update the 594 * array index to point to the next element, but that requires some 595 * house keeping and boundry checks. The advanced is implemented, as 596 * the simple approach behaves badly when all chains are deleted 597 * because list_for_each processing will always hit the first chain 598 * index, thus causing a rebuild for every chain. 599 */ 600static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handle *h) 601{ 602 struct list_head *index_ptr, *next; 603 struct chain_head *c2; 604 unsigned int idx, idx2; 605 606 index_ptr = iptcc_bsearch_chain_index(c->name, &idx, h); 607 608 debug("Del chain[%s] c->list:%p index_ptr:%p\n", 609 c->name, &c->list, index_ptr); 610 611 /* Save the next pointer */ 612 next = c->list.next; 613 list_del(&c->list); 614 615 if (index_ptr == &c->list) { /* Chain used as index ptr */ 616 617 /* See if its possible to avoid a rebuild, by shifting 618 * to next pointer. Its possible if the next pointer 619 * is located in the same index bucket. 620 */ 621 c2 = list_entry(next, struct chain_head, list); 622 iptcc_bsearch_chain_index(c2->name, &idx2, h); 623 if (idx != idx2) { 624 /* Rebuild needed */ 625 return iptcc_chain_index_rebuild(h); 626 } else { 627 /* Avoiding rebuild */ 628 debug("Update cindex[%d] with next ptr name:[%s]\n", 629 idx, c2->name); 630 h->chain_index[idx]=c2; 631 return 0; 632 } 633 } 634 return 0; 635} 636 637 638/********************************************************************** 639 * iptc cache utility functions (iptcc_*) 640 **********************************************************************/ 641 642/* Is the given chain builtin (1) or user-defined (0) */ 643static inline unsigned int iptcc_is_builtin(struct chain_head *c) 644{ 645 return (c->hooknum ? 1 : 0); 646} 647 648/* Get a specific rule within a chain */ 649static struct rule_head *iptcc_get_rule_num(struct chain_head *c, 650 unsigned int rulenum) 651{ 652 struct rule_head *r; 653 unsigned int num = 0; 654 655 list_for_each_entry(r, &c->rules, list) { 656 num++; 657 if (num == rulenum) 658 return r; 659 } 660 return NULL; 661} 662 663/* Get a specific rule within a chain backwards */ 664static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c, 665 unsigned int rulenum) 666{ 667 struct rule_head *r; 668 unsigned int num = 0; 669 670 list_for_each_entry_reverse(r, &c->rules, list) { 671 num++; 672 if (num == rulenum) 673 return r; 674 } 675 return NULL; 676} 677 678/* Returns chain head if found, otherwise NULL. */ 679static struct chain_head * 680iptcc_find_chain_by_offset(struct xtc_handle *handle, unsigned int offset) 681{ 682 struct list_head *pos; 683 struct list_head *list_start_pos; 684 unsigned int i; 685 686 if (list_empty(&handle->chains)) 687 return NULL; 688 689 /* Find a smart place to start the search */ 690 list_start_pos = iptcc_bsearch_chain_offset(offset, &i, handle); 691 692 /* Note that iptcc_bsearch_chain_offset() skips builtin 693 * chains, but this function is only used for finding jump 694 * targets, and a buildin chain is not a valid jump target */ 695 696 debug("Offset:[%u] starting search at index:[%u]\n", offset, i); 697// list_for_each(pos, &handle->chains) { 698 list_for_each(pos, list_start_pos->prev) { 699 struct chain_head *c = list_entry(pos, struct chain_head, list); 700 debug("."); 701 if (offset >= c->head_offset && offset <= c->foot_offset) { 702 debug("Offset search found chain:[%s]\n", c->name); 703 return c; 704 } 705 } 706 707 return NULL; 708} 709 710/* Returns chain head if found, otherwise NULL. */ 711static struct chain_head * 712iptcc_find_label(const char *name, struct xtc_handle *handle) 713{ 714 struct list_head *pos; 715 struct list_head *list_start_pos; 716 unsigned int i=0; 717 int res; 718 719 if (list_empty(&handle->chains)) 720 return NULL; 721 722 /* First look at builtin chains */ 723 list_for_each(pos, &handle->chains) { 724 struct chain_head *c = list_entry(pos, struct chain_head, list); 725 if (!iptcc_is_builtin(c)) 726 break; 727 if (!strcmp(c->name, name)) 728 return c; 729 } 730 731 /* Find a smart place to start the search via chain index */ 732 //list_start_pos = iptcc_linearly_search_chain_index(name, handle); 733 list_start_pos = iptcc_bsearch_chain_index(name, &i, handle); 734 735 /* Handel if bsearch bails out early */ 736 if (list_start_pos == &handle->chains) { 737 list_start_pos = pos; 738 } 739#ifdef DEBUG 740 else { 741 /* Verify result of bsearch against linearly index search */ 742 struct list_head *test_pos; 743 struct chain_head *test_c, *tmp_c; 744 test_pos = iptcc_linearly_search_chain_index(name, handle); 745 if (list_start_pos != test_pos) { 746 debug("BUG in chain_index search\n"); 747 test_c=list_entry(test_pos, struct chain_head,list); 748 tmp_c =list_entry(list_start_pos,struct chain_head,list); 749 debug("Verify search found:\n"); 750 debug(" Chain:%s\n", test_c->name); 751 debug("BSearch found:\n"); 752 debug(" Chain:%s\n", tmp_c->name); 753 exit(42); 754 } 755 } 756#endif 757 758 /* Initial/special case, no user defined chains */ 759 if (handle->num_chains == 0) 760 return NULL; 761 762 /* Start searching through the chain list */ 763 list_for_each(pos, list_start_pos->prev) { 764 struct chain_head *c = list_entry(pos, struct chain_head, list); 765 res = strcmp(c->name, name); 766 debug("List search name:%s == %s res:%d\n", name, c->name, res); 767 if (res==0) 768 return c; 769 770 /* We can stop earlier as we know list is sorted */ 771 if (res>0 && !iptcc_is_builtin(c)) { /* Walked too far*/ 772 debug(" Not in list, walked too far, sorted list\n"); 773 return NULL; 774 } 775 776 /* Stop on wrap around, if list head is reached */ 777 if (pos == &handle->chains) { 778 debug("Stop, list head reached\n"); 779 return NULL; 780 } 781 } 782 783 debug("List search NOT found name:%s\n", name); 784 return NULL; 785} 786 787/* called when rule is to be removed from cache */ 788static void iptcc_delete_rule(struct rule_head *r) 789{ 790 DEBUGP("deleting rule %p (offset %u)\n", r, r->offset); 791 /* clean up reference count of called chain */ 792 if (r->type == IPTCC_R_JUMP 793 && r->jump) 794 r->jump->references--; 795 796 list_del(&r->list); 797 free(r); 798} 799 800 801/********************************************************************** 802 * RULESET PARSER (blob -> cache) 803 **********************************************************************/ 804 805/* Delete policy rule of previous chain, since cache doesn't contain 806 * chain policy rules. 807 * WARNING: This function has ugly design and relies on a lot of context, only 808 * to be called from specific places within the parser */ 809static int __iptcc_p_del_policy(struct xtc_handle *h, unsigned int num) 810{ 811 const unsigned char *data; 812 813 if (h->chain_iterator_cur) { 814 /* policy rule is last rule */ 815 struct rule_head *pr = (struct rule_head *) 816 h->chain_iterator_cur->rules.prev; 817 818 /* save verdict */ 819 data = GET_TARGET(pr->entry)->data; 820 h->chain_iterator_cur->verdict = *(const int *)data; 821 822 /* save counter and counter_map information */ 823 h->chain_iterator_cur->counter_map.maptype = 824 COUNTER_MAP_ZEROED; 825 h->chain_iterator_cur->counter_map.mappos = num-1; 826 memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters, 827 sizeof(h->chain_iterator_cur->counters)); 828 829 /* foot_offset points to verdict rule */ 830 h->chain_iterator_cur->foot_index = num; 831 h->chain_iterator_cur->foot_offset = pr->offset; 832 833 /* delete rule from cache */ 834 iptcc_delete_rule(pr); 835 h->chain_iterator_cur->num_rules--; 836 837 return 1; 838 } 839 return 0; 840} 841 842/* alphabetically insert a chain into the list */ 843static void iptc_insert_chain(struct xtc_handle *h, struct chain_head *c) 844{ 845 struct chain_head *tmp; 846 struct list_head *list_start_pos; 847 unsigned int i=1; 848 849 /* Find a smart place to start the insert search */ 850 list_start_pos = iptcc_bsearch_chain_index(c->name, &i, h); 851 852 /* Handle the case, where chain.name is smaller than index[0] */ 853 if (i==0 && strcmp(c->name, h->chain_index[0]->name) <= 0) { 854 h->chain_index[0] = c; /* Update chain index head */ 855 list_start_pos = h->chains.next; 856 debug("Update chain_index[0] with %s\n", c->name); 857 } 858 859 /* Handel if bsearch bails out early */ 860 if (list_start_pos == &h->chains) { 861 list_start_pos = h->chains.next; 862 } 863 864 /* sort only user defined chains */ 865 if (!c->hooknum) { 866 list_for_each_entry(tmp, list_start_pos->prev, list) { 867 if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) { 868 list_add(&c->list, tmp->list.prev); 869 return; 870 } 871 872 /* Stop if list head is reached */ 873 if (&tmp->list == &h->chains) { 874 debug("Insert, list head reached add to tail\n"); 875 break; 876 } 877 } 878 } 879 880 /* survived till end of list: add at tail */ 881 list_add_tail(&c->list, &h->chains); 882} 883 884/* Another ugly helper function split out of cache_add_entry to make it less 885 * spaghetti code */ 886static void __iptcc_p_add_chain(struct xtc_handle *h, struct chain_head *c, 887 unsigned int offset, unsigned int *num) 888{ 889 struct list_head *tail = h->chains.prev; 890 struct chain_head *ctail; 891 892 __iptcc_p_del_policy(h, *num); 893 894 c->head_offset = offset; 895 c->index = *num; 896 897 /* Chains from kernel are already sorted, as they are inserted 898 * sorted. But there exists an issue when shifting to 1.4.0 899 * from an older version, as old versions allow last created 900 * chain to be unsorted. 901 */ 902 if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/ 903 list_add_tail(&c->list, &h->chains); 904 else { 905 ctail = list_entry(tail, struct chain_head, list); 906 907 if (strcmp(c->name, ctail->name) > 0 || 908 iptcc_is_builtin(ctail)) 909 list_add_tail(&c->list, &h->chains);/* Already sorted*/ 910 else { 911 iptc_insert_chain(h, c);/* Was not sorted */ 912 913 /* Notice, if chains were not received sorted 914 * from kernel, then an offset bsearch is no 915 * longer valid. 916 */ 917 h->sorted_offsets = 0; 918 919 debug("NOTICE: chain:[%s] was NOT sorted(ctail:%s)\n", 920 c->name, ctail->name); 921 } 922 } 923 924 h->chain_iterator_cur = c; 925} 926 927/* main parser function: add an entry from the blob to the cache */ 928static int cache_add_entry(STRUCT_ENTRY *e, 929 struct xtc_handle *h, 930 STRUCT_ENTRY **prev, 931 unsigned int *num) 932{ 933 unsigned int builtin; 934 unsigned int offset = (char *)e - (char *)h->entries->entrytable; 935 936 DEBUGP("entering..."); 937 938 /* Last entry ("policy rule"). End it.*/ 939 if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) { 940 /* This is the ERROR node at the end of the chain */ 941 DEBUGP_C("%u:%u: end of table:\n", *num, offset); 942 943 __iptcc_p_del_policy(h, *num); 944 945 h->chain_iterator_cur = NULL; 946 goto out_inc; 947 } 948 949 /* We know this is the start of a new chain if it's an ERROR 950 * target, or a hook entry point */ 951 952 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) { 953 struct chain_head *c = 954 iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0); 955 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset, 956 (char *)c->name, c); 957 if (!c) { 958 errno = -ENOMEM; 959 return -1; 960 } 961 h->num_chains++; /* New user defined chain */ 962 963 __iptcc_p_add_chain(h, c, offset, num); 964 965 } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) { 966 struct chain_head *c = 967 iptcc_alloc_chain_head((char *)hooknames[builtin-1], 968 builtin); 969 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n", 970 *num, offset, c, &c->rules); 971 if (!c) { 972 errno = -ENOMEM; 973 return -1; 974 } 975 976 c->hooknum = builtin; 977 978 __iptcc_p_add_chain(h, c, offset, num); 979 980 /* FIXME: this is ugly. */ 981 goto new_rule; 982 } else { 983 /* has to be normal rule */ 984 struct rule_head *r; 985new_rule: 986 987 if (!(r = iptcc_alloc_rule(h->chain_iterator_cur, 988 e->next_offset))) { 989 errno = ENOMEM; 990 return -1; 991 } 992 DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r); 993 994 r->index = *num; 995 r->offset = offset; 996 memcpy(r->entry, e, e->next_offset); 997 r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP; 998 r->counter_map.mappos = r->index; 999 1000 /* handling of jumps, etc. */ 1001 if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) { 1002 STRUCT_STANDARD_TARGET *t; 1003 1004 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 1005 if (t->target.u.target_size 1006 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { 1007 errno = EINVAL; 1008 free(r); 1009 return -1; 1010 } 1011 1012 if (t->verdict < 0) { 1013 DEBUGP_C("standard, verdict=%d\n", t->verdict); 1014 r->type = IPTCC_R_STANDARD; 1015 } else if (t->verdict == r->offset+e->next_offset) { 1016 DEBUGP_C("fallthrough\n"); 1017 r->type = IPTCC_R_FALLTHROUGH; 1018 } else { 1019 DEBUGP_C("jump, target=%u\n", t->verdict); 1020 r->type = IPTCC_R_JUMP; 1021 /* Jump target fixup has to be deferred 1022 * until second pass, since we migh not 1023 * yet have parsed the target */ 1024 } 1025 } else { 1026 DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name); 1027 r->type = IPTCC_R_MODULE; 1028 } 1029 1030 list_add_tail(&r->list, &h->chain_iterator_cur->rules); 1031 h->chain_iterator_cur->num_rules++; 1032 } 1033out_inc: 1034 (*num)++; 1035 return 0; 1036} 1037 1038 1039/* parse an iptables blob into it's pieces */ 1040static int parse_table(struct xtc_handle *h) 1041{ 1042 STRUCT_ENTRY *prev; 1043 unsigned int num = 0; 1044 struct chain_head *c; 1045 1046 /* Assume that chains offsets are sorted, this verified during 1047 parsing of ruleset (in __iptcc_p_add_chain())*/ 1048 h->sorted_offsets = 1; 1049 1050 /* First pass: over ruleset blob */ 1051 ENTRY_ITERATE(h->entries->entrytable, h->entries->size, 1052 cache_add_entry, h, &prev, &num); 1053 1054 /* Build the chain index, used for chain list search speedup */ 1055 if ((iptcc_chain_index_alloc(h)) < 0) 1056 return -ENOMEM; 1057 iptcc_chain_index_build(h); 1058 1059 /* Second pass: fixup parsed data from first pass */ 1060 list_for_each_entry(c, &h->chains, list) { 1061 struct rule_head *r; 1062 list_for_each_entry(r, &c->rules, list) { 1063 struct chain_head *lc; 1064 STRUCT_STANDARD_TARGET *t; 1065 1066 if (r->type != IPTCC_R_JUMP) 1067 continue; 1068 1069 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 1070 lc = iptcc_find_chain_by_offset(h, t->verdict); 1071 if (!lc) 1072 return -1; 1073 r->jump = lc; 1074 lc->references++; 1075 } 1076 } 1077 1078 return 1; 1079} 1080 1081 1082/********************************************************************** 1083 * RULESET COMPILATION (cache -> blob) 1084 **********************************************************************/ 1085 1086/* Convenience structures */ 1087struct iptcb_chain_start{ 1088 STRUCT_ENTRY e; 1089 struct xt_error_target name; 1090}; 1091#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \ 1092 ALIGN(sizeof(struct xt_error_target))) 1093 1094struct iptcb_chain_foot { 1095 STRUCT_ENTRY e; 1096 STRUCT_STANDARD_TARGET target; 1097}; 1098#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \ 1099 ALIGN(sizeof(STRUCT_STANDARD_TARGET))) 1100 1101struct iptcb_chain_error { 1102 STRUCT_ENTRY entry; 1103 struct xt_error_target target; 1104}; 1105#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \ 1106 ALIGN(sizeof(struct xt_error_target))) 1107 1108 1109 1110/* compile rule from cache into blob */ 1111static inline int iptcc_compile_rule (struct xtc_handle *h, STRUCT_REPLACE *repl, struct rule_head *r) 1112{ 1113 /* handle jumps */ 1114 if (r->type == IPTCC_R_JUMP) { 1115 STRUCT_STANDARD_TARGET *t; 1116 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 1117 /* memset for memcmp convenience on delete/replace */ 1118 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); 1119 strcpy(t->target.u.user.name, STANDARD_TARGET); 1120 /* Jumps can only happen to builtin chains, so we 1121 * can safely assume that they always have a header */ 1122 t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE; 1123 } else if (r->type == IPTCC_R_FALLTHROUGH) { 1124 STRUCT_STANDARD_TARGET *t; 1125 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 1126 t->verdict = r->offset + r->size; 1127 } 1128 1129 /* copy entry from cache to blob */ 1130 memcpy((char *)repl->entries+r->offset, r->entry, r->size); 1131 1132 return 1; 1133} 1134 1135/* compile chain from cache into blob */ 1136static int iptcc_compile_chain(struct xtc_handle *h, STRUCT_REPLACE *repl, struct chain_head *c) 1137{ 1138 int ret; 1139 struct rule_head *r; 1140 struct iptcb_chain_start *head; 1141 struct iptcb_chain_foot *foot; 1142 1143 /* only user-defined chains have heaer */ 1144 if (!iptcc_is_builtin(c)) { 1145 /* put chain header in place */ 1146 head = (void *)repl->entries + c->head_offset; 1147 head->e.target_offset = sizeof(STRUCT_ENTRY); 1148 head->e.next_offset = IPTCB_CHAIN_START_SIZE; 1149 strcpy(head->name.target.u.user.name, ERROR_TARGET); 1150 head->name.target.u.target_size = 1151 ALIGN(sizeof(struct xt_error_target)); 1152 strcpy(head->name.errorname, c->name); 1153 } else { 1154 repl->hook_entry[c->hooknum-1] = c->head_offset; 1155 repl->underflow[c->hooknum-1] = c->foot_offset; 1156 } 1157 1158 /* iterate over rules */ 1159 list_for_each_entry(r, &c->rules, list) { 1160 ret = iptcc_compile_rule(h, repl, r); 1161 if (ret < 0) 1162 return ret; 1163 } 1164 1165 /* put chain footer in place */ 1166 foot = (void *)repl->entries + c->foot_offset; 1167 foot->e.target_offset = sizeof(STRUCT_ENTRY); 1168 foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE; 1169 strcpy(foot->target.target.u.user.name, STANDARD_TARGET); 1170 foot->target.target.u.target_size = 1171 ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 1172 /* builtin targets have verdict, others return */ 1173 if (iptcc_is_builtin(c)) 1174 foot->target.verdict = c->verdict; 1175 else 1176 foot->target.verdict = RETURN; 1177 /* set policy-counters */ 1178 memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS)); 1179 1180 return 0; 1181} 1182 1183/* calculate offset and number for every rule in the cache */ 1184static int iptcc_compile_chain_offsets(struct xtc_handle *h, struct chain_head *c, 1185 unsigned int *offset, unsigned int *num) 1186{ 1187 struct rule_head *r; 1188 1189 c->head_offset = *offset; 1190 DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset); 1191 1192 if (!iptcc_is_builtin(c)) { 1193 /* Chain has header */ 1194 *offset += sizeof(STRUCT_ENTRY) 1195 + ALIGN(sizeof(struct xt_error_target)); 1196 (*num)++; 1197 } 1198 1199 list_for_each_entry(r, &c->rules, list) { 1200 DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num); 1201 r->offset = *offset; 1202 r->index = *num; 1203 *offset += r->size; 1204 (*num)++; 1205 } 1206 1207 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num, 1208 *offset, *num); 1209 c->foot_offset = *offset; 1210 c->foot_index = *num; 1211 *offset += sizeof(STRUCT_ENTRY) 1212 + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 1213 (*num)++; 1214 1215 return 1; 1216} 1217 1218/* put the pieces back together again */ 1219static int iptcc_compile_table_prep(struct xtc_handle *h, unsigned int *size) 1220{ 1221 struct chain_head *c; 1222 unsigned int offset = 0, num = 0; 1223 int ret = 0; 1224 1225 /* First pass: calculate offset for every rule */ 1226 list_for_each_entry(c, &h->chains, list) { 1227 ret = iptcc_compile_chain_offsets(h, c, &offset, &num); 1228 if (ret < 0) 1229 return ret; 1230 } 1231 1232 /* Append one error rule at end of chain */ 1233 num++; 1234 offset += sizeof(STRUCT_ENTRY) 1235 + ALIGN(sizeof(struct xt_error_target)); 1236 1237 /* ruleset size is now in offset */ 1238 *size = offset; 1239 return num; 1240} 1241 1242static int iptcc_compile_table(struct xtc_handle *h, STRUCT_REPLACE *repl) 1243{ 1244 struct chain_head *c; 1245 struct iptcb_chain_error *error; 1246 1247 /* Second pass: copy from cache to offsets, fill in jumps */ 1248 list_for_each_entry(c, &h->chains, list) { 1249 int ret = iptcc_compile_chain(h, repl, c); 1250 if (ret < 0) 1251 return ret; 1252 } 1253 1254 /* Append error rule at end of chain */ 1255 error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE; 1256 error->entry.target_offset = sizeof(STRUCT_ENTRY); 1257 error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE; 1258 error->target.target.u.user.target_size = 1259 ALIGN(sizeof(struct xt_error_target)); 1260 strcpy((char *)&error->target.target.u.user.name, ERROR_TARGET); 1261 strcpy((char *)&error->target.errorname, "ERROR"); 1262 1263 return 1; 1264} 1265 1266/********************************************************************** 1267 * EXTERNAL API (operates on cache only) 1268 **********************************************************************/ 1269 1270/* Allocate handle of given size */ 1271static struct xtc_handle * 1272alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) 1273{ 1274 struct xtc_handle *h; 1275 1276 h = malloc(sizeof(*h)); 1277 if (!h) { 1278 errno = ENOMEM; 1279 return NULL; 1280 } 1281 memset(h, 0, sizeof(*h)); 1282 INIT_LIST_HEAD(&h->chains); 1283 strcpy(h->info.name, tablename); 1284 1285 h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size); 1286 if (!h->entries) 1287 goto out_free_handle; 1288 1289 strcpy(h->entries->name, tablename); 1290 h->entries->size = size; 1291 1292 return h; 1293 1294out_free_handle: 1295 free(h); 1296 1297 return NULL; 1298} 1299 1300 1301struct xtc_handle * 1302TC_INIT(const char *tablename) 1303{ 1304 struct xtc_handle *h; 1305 STRUCT_GETINFO info; 1306 unsigned int tmp; 1307 socklen_t s; 1308 int sockfd; 1309 1310 iptc_fn = TC_INIT; 1311 1312 if (strlen(tablename) >= TABLE_MAXNAMELEN) { 1313 errno = EINVAL; 1314 return NULL; 1315 } 1316 1317 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); 1318 if (sockfd < 0) 1319 return NULL; 1320 1321 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { 1322 fprintf(stderr, "Could not set close on exec: %s\n", 1323 strerror(errno)); 1324 abort(); 1325 } 1326 1327retry: 1328 s = sizeof(info); 1329 1330 strcpy(info.name, tablename); 1331 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) { 1332 close(sockfd); 1333 return NULL; 1334 } 1335 1336 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n", 1337 info.valid_hooks, info.num_entries, info.size); 1338 1339 if ((h = alloc_handle(info.name, info.size, info.num_entries)) 1340 == NULL) { 1341 close(sockfd); 1342 return NULL; 1343 } 1344 1345 /* Initialize current state */ 1346 h->sockfd = sockfd; 1347 h->info = info; 1348 1349 h->entries->size = h->info.size; 1350 1351 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; 1352 1353 if (getsockopt(h->sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries, 1354 &tmp) < 0) 1355 goto error; 1356 1357#ifdef IPTC_DEBUG2 1358 { 1359 int fd = open("/tmp/libiptc-so_get_entries.blob", 1360 O_CREAT|O_WRONLY); 1361 if (fd >= 0) { 1362 write(fd, h->entries, tmp); 1363 close(fd); 1364 } 1365 } 1366#endif 1367 1368 if (parse_table(h) < 0) 1369 goto error; 1370 1371 CHECK(h); 1372 return h; 1373error: 1374 TC_FREE(h); 1375 /* A different process changed the ruleset size, retry */ 1376 if (errno == EAGAIN) 1377 goto retry; 1378 return NULL; 1379} 1380 1381void 1382TC_FREE(struct xtc_handle *h) 1383{ 1384 struct chain_head *c, *tmp; 1385 1386 iptc_fn = TC_FREE; 1387 close(h->sockfd); 1388 1389 list_for_each_entry_safe(c, tmp, &h->chains, list) { 1390 struct rule_head *r, *rtmp; 1391 1392 list_for_each_entry_safe(r, rtmp, &c->rules, list) { 1393 free(r); 1394 } 1395 1396 free(c); 1397 } 1398 1399 iptcc_chain_index_free(h); 1400 1401 free(h->entries); 1402 free(h); 1403} 1404 1405static inline int 1406print_match(const STRUCT_ENTRY_MATCH *m) 1407{ 1408 printf("Match name: `%s'\n", m->u.user.name); 1409 return 0; 1410} 1411 1412static int dump_entry(STRUCT_ENTRY *e, struct xtc_handle *const handle); 1413 1414void 1415TC_DUMP_ENTRIES(struct xtc_handle *const handle) 1416{ 1417 iptc_fn = TC_DUMP_ENTRIES; 1418 CHECK(handle); 1419 1420 printf("libiptc v%s. %u bytes.\n", 1421 XTABLES_VERSION, handle->entries->size); 1422 printf("Table `%s'\n", handle->info.name); 1423 printf("Hooks: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n", 1424 handle->info.hook_entry[HOOK_PRE_ROUTING], 1425 handle->info.hook_entry[HOOK_LOCAL_IN], 1426 handle->info.hook_entry[HOOK_FORWARD], 1427 handle->info.hook_entry[HOOK_LOCAL_OUT], 1428 handle->info.hook_entry[HOOK_POST_ROUTING]); 1429 printf("Underflows: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n", 1430 handle->info.underflow[HOOK_PRE_ROUTING], 1431 handle->info.underflow[HOOK_LOCAL_IN], 1432 handle->info.underflow[HOOK_FORWARD], 1433 handle->info.underflow[HOOK_LOCAL_OUT], 1434 handle->info.underflow[HOOK_POST_ROUTING]); 1435 1436 ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size, 1437 dump_entry, handle); 1438} 1439 1440/* Does this chain exist? */ 1441int TC_IS_CHAIN(const char *chain, struct xtc_handle *const handle) 1442{ 1443 iptc_fn = TC_IS_CHAIN; 1444 return iptcc_find_label(chain, handle) != NULL; 1445} 1446 1447static void iptcc_chain_iterator_advance(struct xtc_handle *handle) 1448{ 1449 struct chain_head *c = handle->chain_iterator_cur; 1450 1451 if (c->list.next == &handle->chains) 1452 handle->chain_iterator_cur = NULL; 1453 else 1454 handle->chain_iterator_cur = 1455 list_entry(c->list.next, struct chain_head, list); 1456} 1457 1458/* Iterator functions to run through the chains. */ 1459const char * 1460TC_FIRST_CHAIN(struct xtc_handle *handle) 1461{ 1462 struct chain_head *c = list_entry(handle->chains.next, 1463 struct chain_head, list); 1464 1465 iptc_fn = TC_FIRST_CHAIN; 1466 1467 1468 if (list_empty(&handle->chains)) { 1469 DEBUGP(": no chains\n"); 1470 return NULL; 1471 } 1472 1473 handle->chain_iterator_cur = c; 1474 iptcc_chain_iterator_advance(handle); 1475 1476 DEBUGP(": returning `%s'\n", c->name); 1477 return c->name; 1478} 1479 1480/* Iterator functions to run through the chains. Returns NULL at end. */ 1481const char * 1482TC_NEXT_CHAIN(struct xtc_handle *handle) 1483{ 1484 struct chain_head *c = handle->chain_iterator_cur; 1485 1486 iptc_fn = TC_NEXT_CHAIN; 1487 1488 if (!c) { 1489 DEBUGP(": no more chains\n"); 1490 return NULL; 1491 } 1492 1493 iptcc_chain_iterator_advance(handle); 1494 1495 DEBUGP(": returning `%s'\n", c->name); 1496 return c->name; 1497} 1498 1499/* Get first rule in the given chain: NULL for empty chain. */ 1500const STRUCT_ENTRY * 1501TC_FIRST_RULE(const char *chain, struct xtc_handle *handle) 1502{ 1503 struct chain_head *c; 1504 struct rule_head *r; 1505 1506 iptc_fn = TC_FIRST_RULE; 1507 1508 DEBUGP("first rule(%s): ", chain); 1509 1510 c = iptcc_find_label(chain, handle); 1511 if (!c) { 1512 errno = ENOENT; 1513 return NULL; 1514 } 1515 1516 /* Empty chain: single return/policy rule */ 1517 if (list_empty(&c->rules)) { 1518 DEBUGP_C("no rules, returning NULL\n"); 1519 return NULL; 1520 } 1521 1522 r = list_entry(c->rules.next, struct rule_head, list); 1523 handle->rule_iterator_cur = r; 1524 DEBUGP_C("%p\n", r); 1525 1526 return r->entry; 1527} 1528 1529/* Returns NULL when rules run out. */ 1530const STRUCT_ENTRY * 1531TC_NEXT_RULE(const STRUCT_ENTRY *prev, struct xtc_handle *handle) 1532{ 1533 struct rule_head *r; 1534 1535 iptc_fn = TC_NEXT_RULE; 1536 DEBUGP("rule_iterator_cur=%p...", handle->rule_iterator_cur); 1537 1538 if (handle->rule_iterator_cur == NULL) { 1539 DEBUGP_C("returning NULL\n"); 1540 return NULL; 1541 } 1542 1543 r = list_entry(handle->rule_iterator_cur->list.next, 1544 struct rule_head, list); 1545 1546 iptc_fn = TC_NEXT_RULE; 1547 1548 DEBUGP_C("next=%p, head=%p...", &r->list, 1549 &handle->rule_iterator_cur->chain->rules); 1550 1551 if (&r->list == &handle->rule_iterator_cur->chain->rules) { 1552 handle->rule_iterator_cur = NULL; 1553 DEBUGP_C("finished, returning NULL\n"); 1554 return NULL; 1555 } 1556 1557 handle->rule_iterator_cur = r; 1558 1559 /* NOTE: prev is without any influence ! */ 1560 DEBUGP_C("returning rule %p\n", r); 1561 return r->entry; 1562} 1563 1564/* Returns a pointer to the target name of this position. */ 1565static const char *standard_target_map(int verdict) 1566{ 1567 switch (verdict) { 1568 case RETURN: 1569 return LABEL_RETURN; 1570 break; 1571 case -NF_ACCEPT-1: 1572 return LABEL_ACCEPT; 1573 break; 1574 case -NF_DROP-1: 1575 return LABEL_DROP; 1576 break; 1577 case -NF_QUEUE-1: 1578 return LABEL_QUEUE; 1579 break; 1580 default: 1581 fprintf(stderr, "ERROR: %d not a valid target)\n", 1582 verdict); 1583 abort(); 1584 break; 1585 } 1586 /* not reached */ 1587 return NULL; 1588} 1589 1590/* Returns a pointer to the target name of this position. */ 1591const char *TC_GET_TARGET(const STRUCT_ENTRY *ce, 1592 struct xtc_handle *handle) 1593{ 1594 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; 1595 struct rule_head *r = container_of(e, struct rule_head, entry[0]); 1596 const unsigned char *data; 1597 1598 iptc_fn = TC_GET_TARGET; 1599 1600 switch(r->type) { 1601 int spos; 1602 case IPTCC_R_FALLTHROUGH: 1603 return ""; 1604 break; 1605 case IPTCC_R_JUMP: 1606 DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name); 1607 return r->jump->name; 1608 break; 1609 case IPTCC_R_STANDARD: 1610 data = GET_TARGET(e)->data; 1611 spos = *(const int *)data; 1612 DEBUGP("r=%p, spos=%d'\n", r, spos); 1613 return standard_target_map(spos); 1614 break; 1615 case IPTCC_R_MODULE: 1616 return GET_TARGET(e)->u.user.name; 1617 break; 1618 } 1619 return NULL; 1620} 1621/* Is this a built-in chain? Actually returns hook + 1. */ 1622int 1623TC_BUILTIN(const char *chain, struct xtc_handle *const handle) 1624{ 1625 struct chain_head *c; 1626 1627 iptc_fn = TC_BUILTIN; 1628 1629 c = iptcc_find_label(chain, handle); 1630 if (!c) { 1631 errno = ENOENT; 1632 return 0; 1633 } 1634 1635 return iptcc_is_builtin(c); 1636} 1637 1638/* Get the policy of a given built-in chain */ 1639const char * 1640TC_GET_POLICY(const char *chain, 1641 STRUCT_COUNTERS *counters, 1642 struct xtc_handle *handle) 1643{ 1644 struct chain_head *c; 1645 1646 iptc_fn = TC_GET_POLICY; 1647 1648 DEBUGP("called for chain %s\n", chain); 1649 1650 c = iptcc_find_label(chain, handle); 1651 if (!c) { 1652 errno = ENOENT; 1653 return NULL; 1654 } 1655 1656 if (!iptcc_is_builtin(c)) 1657 return NULL; 1658 1659 *counters = c->counters; 1660 1661 return standard_target_map(c->verdict); 1662} 1663 1664static int 1665iptcc_standard_map(struct rule_head *r, int verdict) 1666{ 1667 STRUCT_ENTRY *e = r->entry; 1668 STRUCT_STANDARD_TARGET *t; 1669 1670 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 1671 1672 if (t->target.u.target_size 1673 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { 1674 errno = EINVAL; 1675 return 0; 1676 } 1677 /* memset for memcmp convenience on delete/replace */ 1678 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); 1679 strcpy(t->target.u.user.name, STANDARD_TARGET); 1680 t->verdict = verdict; 1681 1682 r->type = IPTCC_R_STANDARD; 1683 1684 return 1; 1685} 1686 1687static int 1688iptcc_map_target(struct xtc_handle *const handle, 1689 struct rule_head *r) 1690{ 1691 STRUCT_ENTRY *e = r->entry; 1692 STRUCT_ENTRY_TARGET *t = GET_TARGET(e); 1693 1694 /* Maybe it's empty (=> fall through) */ 1695 if (strcmp(t->u.user.name, "") == 0) { 1696 r->type = IPTCC_R_FALLTHROUGH; 1697 return 1; 1698 } 1699 /* Maybe it's a standard target name... */ 1700 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) 1701 return iptcc_standard_map(r, -NF_ACCEPT - 1); 1702 else if (strcmp(t->u.user.name, LABEL_DROP) == 0) 1703 return iptcc_standard_map(r, -NF_DROP - 1); 1704 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0) 1705 return iptcc_standard_map(r, -NF_QUEUE - 1); 1706 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0) 1707 return iptcc_standard_map(r, RETURN); 1708 else if (TC_BUILTIN(t->u.user.name, handle)) { 1709 /* Can't jump to builtins. */ 1710 errno = EINVAL; 1711 return 0; 1712 } else { 1713 /* Maybe it's an existing chain name. */ 1714 struct chain_head *c; 1715 DEBUGP("trying to find chain `%s': ", t->u.user.name); 1716 1717 c = iptcc_find_label(t->u.user.name, handle); 1718 if (c) { 1719 DEBUGP_C("found!\n"); 1720 r->type = IPTCC_R_JUMP; 1721 r->jump = c; 1722 c->references++; 1723 return 1; 1724 } 1725 DEBUGP_C("not found :(\n"); 1726 } 1727 1728 /* Must be a module? If not, kernel will reject... */ 1729 /* memset to all 0 for your memcmp convenience: don't clear version */ 1730 memset(t->u.user.name + strlen(t->u.user.name), 1731 0, 1732 FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name)); 1733 r->type = IPTCC_R_MODULE; 1734 set_changed(handle); 1735 return 1; 1736} 1737 1738/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ 1739int 1740TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, 1741 const STRUCT_ENTRY *e, 1742 unsigned int rulenum, 1743 struct xtc_handle *handle) 1744{ 1745 struct chain_head *c; 1746 struct rule_head *r; 1747 struct list_head *prev; 1748 1749 iptc_fn = TC_INSERT_ENTRY; 1750 1751 if (!(c = iptcc_find_label(chain, handle))) { 1752 errno = ENOENT; 1753 return 0; 1754 } 1755 1756 /* first rulenum index = 0 1757 first c->num_rules index = 1 */ 1758 if (rulenum > c->num_rules) { 1759 errno = E2BIG; 1760 return 0; 1761 } 1762 1763 /* If we are inserting at the end just take advantage of the 1764 double linked list, insert will happen before the entry 1765 prev points to. */ 1766 if (rulenum == c->num_rules) { 1767 prev = &c->rules; 1768 } else if (rulenum + 1 <= c->num_rules/2) { 1769 r = iptcc_get_rule_num(c, rulenum + 1); 1770 prev = &r->list; 1771 } else { 1772 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1773 prev = &r->list; 1774 } 1775 1776 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1777 errno = ENOMEM; 1778 return 0; 1779 } 1780 1781 memcpy(r->entry, e, e->next_offset); 1782 r->counter_map.maptype = COUNTER_MAP_SET; 1783 1784 if (!iptcc_map_target(handle, r)) { 1785 free(r); 1786 return 0; 1787 } 1788 1789 list_add_tail(&r->list, prev); 1790 c->num_rules++; 1791 1792 set_changed(handle); 1793 1794 return 1; 1795} 1796 1797/* Atomically replace rule `rulenum' in `chain' with `fw'. */ 1798int 1799TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, 1800 const STRUCT_ENTRY *e, 1801 unsigned int rulenum, 1802 struct xtc_handle *handle) 1803{ 1804 struct chain_head *c; 1805 struct rule_head *r, *old; 1806 1807 iptc_fn = TC_REPLACE_ENTRY; 1808 1809 if (!(c = iptcc_find_label(chain, handle))) { 1810 errno = ENOENT; 1811 return 0; 1812 } 1813 1814 if (rulenum >= c->num_rules) { 1815 errno = E2BIG; 1816 return 0; 1817 } 1818 1819 /* Take advantage of the double linked list if possible. */ 1820 if (rulenum + 1 <= c->num_rules/2) { 1821 old = iptcc_get_rule_num(c, rulenum + 1); 1822 } else { 1823 old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1824 } 1825 1826 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1827 errno = ENOMEM; 1828 return 0; 1829 } 1830 1831 memcpy(r->entry, e, e->next_offset); 1832 r->counter_map.maptype = COUNTER_MAP_SET; 1833 1834 if (!iptcc_map_target(handle, r)) { 1835 free(r); 1836 return 0; 1837 } 1838 1839 list_add(&r->list, &old->list); 1840 iptcc_delete_rule(old); 1841 1842 set_changed(handle); 1843 1844 return 1; 1845} 1846 1847/* Append entry `fw' to chain `chain'. Equivalent to insert with 1848 rulenum = length of chain. */ 1849int 1850TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, 1851 const STRUCT_ENTRY *e, 1852 struct xtc_handle *handle) 1853{ 1854 struct chain_head *c; 1855 struct rule_head *r; 1856 1857 iptc_fn = TC_APPEND_ENTRY; 1858 if (!(c = iptcc_find_label(chain, handle))) { 1859 DEBUGP("unable to find chain `%s'\n", chain); 1860 errno = ENOENT; 1861 return 0; 1862 } 1863 1864 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1865 DEBUGP("unable to allocate rule for chain `%s'\n", chain); 1866 errno = ENOMEM; 1867 return 0; 1868 } 1869 1870 memcpy(r->entry, e, e->next_offset); 1871 r->counter_map.maptype = COUNTER_MAP_SET; 1872 1873 if (!iptcc_map_target(handle, r)) { 1874 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1875 free(r); 1876 return 0; 1877 } 1878 1879 list_add_tail(&r->list, &c->rules); 1880 c->num_rules++; 1881 1882 set_changed(handle); 1883 1884 return 1; 1885} 1886 1887static inline int 1888match_different(const STRUCT_ENTRY_MATCH *a, 1889 const unsigned char *a_elems, 1890 const unsigned char *b_elems, 1891 unsigned char **maskptr) 1892{ 1893 const STRUCT_ENTRY_MATCH *b; 1894 unsigned int i; 1895 1896 /* Offset of b is the same as a. */ 1897 b = (void *)b_elems + ((unsigned char *)a - a_elems); 1898 1899 if (a->u.match_size != b->u.match_size) 1900 return 1; 1901 1902 if (strcmp(a->u.user.name, b->u.user.name) != 0) 1903 return 1; 1904 1905 *maskptr += ALIGN(sizeof(*a)); 1906 1907 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) 1908 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) 1909 return 1; 1910 *maskptr += i; 1911 return 0; 1912} 1913 1914static inline int 1915target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask) 1916{ 1917 unsigned int i; 1918 STRUCT_ENTRY_TARGET *ta, *tb; 1919 1920 if (a->type != b->type) 1921 return 0; 1922 1923 ta = GET_TARGET(a->entry); 1924 tb = GET_TARGET(b->entry); 1925 1926 switch (a->type) { 1927 case IPTCC_R_FALLTHROUGH: 1928 return 1; 1929 case IPTCC_R_JUMP: 1930 return a->jump == b->jump; 1931 case IPTCC_R_STANDARD: 1932 return ((STRUCT_STANDARD_TARGET *)ta)->verdict 1933 == ((STRUCT_STANDARD_TARGET *)tb)->verdict; 1934 case IPTCC_R_MODULE: 1935 if (ta->u.target_size != tb->u.target_size) 1936 return 0; 1937 if (strcmp(ta->u.user.name, tb->u.user.name) != 0) 1938 return 0; 1939 1940 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++) 1941 if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0) 1942 return 0; 1943 return 1; 1944 default: 1945 fprintf(stderr, "ERROR: bad type %i\n", a->type); 1946 abort(); 1947 } 1948} 1949 1950static unsigned char * 1951is_same(const STRUCT_ENTRY *a, 1952 const STRUCT_ENTRY *b, 1953 unsigned char *matchmask); 1954 1955 1956/* find the first rule in `chain' which matches `fw' and remove it unless dry_run is set */ 1957static int delete_entry(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, 1958 unsigned char *matchmask, struct xtc_handle *handle, 1959 bool dry_run) 1960{ 1961 struct chain_head *c; 1962 struct rule_head *r, *i; 1963 1964 iptc_fn = TC_DELETE_ENTRY; 1965 if (!(c = iptcc_find_label(chain, handle))) { 1966 errno = ENOENT; 1967 return 0; 1968 } 1969 1970 /* Create a rule_head from origfw. */ 1971 r = iptcc_alloc_rule(c, origfw->next_offset); 1972 if (!r) { 1973 errno = ENOMEM; 1974 return 0; 1975 } 1976 1977 memcpy(r->entry, origfw, origfw->next_offset); 1978 r->counter_map.maptype = COUNTER_MAP_NOMAP; 1979 if (!iptcc_map_target(handle, r)) { 1980 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1981 free(r); 1982 return 0; 1983 } else { 1984 /* iptcc_map_target increment target chain references 1985 * since this is a fake rule only used for matching 1986 * the chain references count is decremented again. 1987 */ 1988 if (r->type == IPTCC_R_JUMP 1989 && r->jump) 1990 r->jump->references--; 1991 } 1992 1993 list_for_each_entry(i, &c->rules, list) { 1994 unsigned char *mask; 1995 1996 mask = is_same(r->entry, i->entry, matchmask); 1997 if (!mask) 1998 continue; 1999 2000 if (!target_same(r, i, mask)) 2001 continue; 2002 2003 /* if we are just doing a dry run, we simply skip the rest */ 2004 if (dry_run){ 2005 free(r); 2006 return 1; 2007 } 2008 2009 /* If we are about to delete the rule that is the 2010 * current iterator, move rule iterator back. next 2011 * pointer will then point to real next node */ 2012 if (i == handle->rule_iterator_cur) { 2013 handle->rule_iterator_cur = 2014 list_entry(handle->rule_iterator_cur->list.prev, 2015 struct rule_head, list); 2016 } 2017 2018 c->num_rules--; 2019 iptcc_delete_rule(i); 2020 2021 set_changed(handle); 2022 free(r); 2023 return 1; 2024 } 2025 2026 free(r); 2027 errno = ENOENT; 2028 return 0; 2029} 2030 2031/* check whether a specified rule is present */ 2032int TC_CHECK_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, 2033 unsigned char *matchmask, struct xtc_handle *handle) 2034{ 2035 /* do a dry-run delete to find out whether a matching rule exists */ 2036 return delete_entry(chain, origfw, matchmask, handle, true); 2037} 2038 2039/* Delete the first rule in `chain' which matches `fw'. */ 2040int TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, 2041 unsigned char *matchmask, struct xtc_handle *handle) 2042{ 2043 return delete_entry(chain, origfw, matchmask, handle, false); 2044} 2045 2046/* Delete the rule in position `rulenum' in `chain'. */ 2047int 2048TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, 2049 unsigned int rulenum, 2050 struct xtc_handle *handle) 2051{ 2052 struct chain_head *c; 2053 struct rule_head *r; 2054 2055 iptc_fn = TC_DELETE_NUM_ENTRY; 2056 2057 if (!(c = iptcc_find_label(chain, handle))) { 2058 errno = ENOENT; 2059 return 0; 2060 } 2061 2062 if (rulenum >= c->num_rules) { 2063 errno = E2BIG; 2064 return 0; 2065 } 2066 2067 /* Take advantage of the double linked list if possible. */ 2068 if (rulenum + 1 <= c->num_rules/2) { 2069 r = iptcc_get_rule_num(c, rulenum + 1); 2070 } else { 2071 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 2072 } 2073 2074 /* If we are about to delete the rule that is the current 2075 * iterator, move rule iterator back. next pointer will then 2076 * point to real next node */ 2077 if (r == handle->rule_iterator_cur) { 2078 handle->rule_iterator_cur = 2079 list_entry(handle->rule_iterator_cur->list.prev, 2080 struct rule_head, list); 2081 } 2082 2083 c->num_rules--; 2084 iptcc_delete_rule(r); 2085 2086 set_changed(handle); 2087 2088 return 1; 2089} 2090 2091/* Flushes the entries in the given chain (ie. empties chain). */ 2092int 2093TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle) 2094{ 2095 struct chain_head *c; 2096 struct rule_head *r, *tmp; 2097 2098 iptc_fn = TC_FLUSH_ENTRIES; 2099 if (!(c = iptcc_find_label(chain, handle))) { 2100 errno = ENOENT; 2101 return 0; 2102 } 2103 2104 list_for_each_entry_safe(r, tmp, &c->rules, list) { 2105 iptcc_delete_rule(r); 2106 } 2107 2108 c->num_rules = 0; 2109 2110 set_changed(handle); 2111 2112 return 1; 2113} 2114 2115/* Zeroes the counters in a chain. */ 2116int 2117TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle) 2118{ 2119 struct chain_head *c; 2120 struct rule_head *r; 2121 2122 iptc_fn = TC_ZERO_ENTRIES; 2123 if (!(c = iptcc_find_label(chain, handle))) { 2124 errno = ENOENT; 2125 return 0; 2126 } 2127 2128 if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 2129 c->counter_map.maptype = COUNTER_MAP_ZEROED; 2130 2131 list_for_each_entry(r, &c->rules, list) { 2132 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 2133 r->counter_map.maptype = COUNTER_MAP_ZEROED; 2134 } 2135 2136 set_changed(handle); 2137 2138 return 1; 2139} 2140 2141STRUCT_COUNTERS * 2142TC_READ_COUNTER(const IPT_CHAINLABEL chain, 2143 unsigned int rulenum, 2144 struct xtc_handle *handle) 2145{ 2146 struct chain_head *c; 2147 struct rule_head *r; 2148 2149 iptc_fn = TC_READ_COUNTER; 2150 CHECK(*handle); 2151 2152 if (!(c = iptcc_find_label(chain, handle))) { 2153 errno = ENOENT; 2154 return NULL; 2155 } 2156 2157 if (!(r = iptcc_get_rule_num(c, rulenum))) { 2158 errno = E2BIG; 2159 return NULL; 2160 } 2161 2162 return &r->entry[0].counters; 2163} 2164 2165int 2166TC_ZERO_COUNTER(const IPT_CHAINLABEL chain, 2167 unsigned int rulenum, 2168 struct xtc_handle *handle) 2169{ 2170 struct chain_head *c; 2171 struct rule_head *r; 2172 2173 iptc_fn = TC_ZERO_COUNTER; 2174 CHECK(handle); 2175 2176 if (!(c = iptcc_find_label(chain, handle))) { 2177 errno = ENOENT; 2178 return 0; 2179 } 2180 2181 if (!(r = iptcc_get_rule_num(c, rulenum))) { 2182 errno = E2BIG; 2183 return 0; 2184 } 2185 2186 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 2187 r->counter_map.maptype = COUNTER_MAP_ZEROED; 2188 2189 set_changed(handle); 2190 2191 return 1; 2192} 2193 2194int 2195TC_SET_COUNTER(const IPT_CHAINLABEL chain, 2196 unsigned int rulenum, 2197 STRUCT_COUNTERS *counters, 2198 struct xtc_handle *handle) 2199{ 2200 struct chain_head *c; 2201 struct rule_head *r; 2202 STRUCT_ENTRY *e; 2203 2204 iptc_fn = TC_SET_COUNTER; 2205 CHECK(handle); 2206 2207 if (!(c = iptcc_find_label(chain, handle))) { 2208 errno = ENOENT; 2209 return 0; 2210 } 2211 2212 if (!(r = iptcc_get_rule_num(c, rulenum))) { 2213 errno = E2BIG; 2214 return 0; 2215 } 2216 2217 e = r->entry; 2218 r->counter_map.maptype = COUNTER_MAP_SET; 2219 2220 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); 2221 2222 set_changed(handle); 2223 2224 return 1; 2225} 2226 2227/* Creates a new chain. */ 2228/* To create a chain, create two rules: error node and unconditional 2229 * return. */ 2230int 2231TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle) 2232{ 2233 static struct chain_head *c; 2234 int capacity; 2235 int exceeded; 2236 2237 iptc_fn = TC_CREATE_CHAIN; 2238 2239 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 2240 QUEUE, RETURN. */ 2241 if (iptcc_find_label(chain, handle) 2242 || strcmp(chain, LABEL_DROP) == 0 2243 || strcmp(chain, LABEL_ACCEPT) == 0 2244 || strcmp(chain, LABEL_QUEUE) == 0 2245 || strcmp(chain, LABEL_RETURN) == 0) { 2246 DEBUGP("Chain `%s' already exists\n", chain); 2247 errno = EEXIST; 2248 return 0; 2249 } 2250 2251 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { 2252 DEBUGP("Chain name `%s' too long\n", chain); 2253 errno = EINVAL; 2254 return 0; 2255 } 2256 2257 c = iptcc_alloc_chain_head(chain, 0); 2258 if (!c) { 2259 DEBUGP("Cannot allocate memory for chain `%s'\n", chain); 2260 errno = ENOMEM; 2261 return 0; 2262 2263 } 2264 handle->num_chains++; /* New user defined chain */ 2265 2266 DEBUGP("Creating chain `%s'\n", chain); 2267 iptc_insert_chain(handle, c); /* Insert sorted */ 2268 2269 /* Inserting chains don't change the correctness of the chain 2270 * index (except if its smaller than index[0], but that 2271 * handled by iptc_insert_chain). It only causes longer lists 2272 * in the buckets. Thus, only rebuild chain index when the 2273 * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains. 2274 */ 2275 capacity = handle->chain_index_sz * CHAIN_INDEX_BUCKET_LEN; 2276 exceeded = handle->num_chains - capacity; 2277 if (exceeded > CHAIN_INDEX_INSERT_MAX) { 2278 debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n", 2279 capacity, exceeded, handle->num_chains); 2280 iptcc_chain_index_rebuild(handle); 2281 } 2282 2283 set_changed(handle); 2284 2285 return 1; 2286} 2287 2288/* Get the number of references to this chain. */ 2289int 2290TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, 2291 struct xtc_handle *handle) 2292{ 2293 struct chain_head *c; 2294 2295 iptc_fn = TC_GET_REFERENCES; 2296 if (!(c = iptcc_find_label(chain, handle))) { 2297 errno = ENOENT; 2298 return 0; 2299 } 2300 2301 *ref = c->references; 2302 2303 return 1; 2304} 2305 2306/* Deletes a chain. */ 2307int 2308TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle) 2309{ 2310 unsigned int references; 2311 struct chain_head *c; 2312 2313 iptc_fn = TC_DELETE_CHAIN; 2314 2315 if (!(c = iptcc_find_label(chain, handle))) { 2316 DEBUGP("cannot find chain `%s'\n", chain); 2317 errno = ENOENT; 2318 return 0; 2319 } 2320 2321 if (TC_BUILTIN(chain, handle)) { 2322 DEBUGP("cannot remove builtin chain `%s'\n", chain); 2323 errno = EINVAL; 2324 return 0; 2325 } 2326 2327 if (!TC_GET_REFERENCES(&references, chain, handle)) { 2328 DEBUGP("cannot get references on chain `%s'\n", chain); 2329 return 0; 2330 } 2331 2332 if (references > 0) { 2333 DEBUGP("chain `%s' still has references\n", chain); 2334 errno = EMLINK; 2335 return 0; 2336 } 2337 2338 if (c->num_rules) { 2339 DEBUGP("chain `%s' is not empty\n", chain); 2340 errno = ENOTEMPTY; 2341 return 0; 2342 } 2343 2344 /* If we are about to delete the chain that is the current 2345 * iterator, move chain iterator forward. */ 2346 if (c == handle->chain_iterator_cur) 2347 iptcc_chain_iterator_advance(handle); 2348 2349 handle->num_chains--; /* One user defined chain deleted */ 2350 2351 //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */ 2352 iptcc_chain_index_delete_chain(c, handle); 2353 free(c); 2354 2355 DEBUGP("chain `%s' deleted\n", chain); 2356 2357 set_changed(handle); 2358 2359 return 1; 2360} 2361 2362/* Renames a chain. */ 2363int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, 2364 const IPT_CHAINLABEL newname, 2365 struct xtc_handle *handle) 2366{ 2367 struct chain_head *c; 2368 iptc_fn = TC_RENAME_CHAIN; 2369 2370 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 2371 QUEUE, RETURN. */ 2372 if (iptcc_find_label(newname, handle) 2373 || strcmp(newname, LABEL_DROP) == 0 2374 || strcmp(newname, LABEL_ACCEPT) == 0 2375 || strcmp(newname, LABEL_QUEUE) == 0 2376 || strcmp(newname, LABEL_RETURN) == 0) { 2377 errno = EEXIST; 2378 return 0; 2379 } 2380 2381 if (!(c = iptcc_find_label(oldname, handle)) 2382 || TC_BUILTIN(oldname, handle)) { 2383 errno = ENOENT; 2384 return 0; 2385 } 2386 2387 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { 2388 errno = EINVAL; 2389 return 0; 2390 } 2391 2392 /* This only unlinks "c" from the list, thus no free(c) */ 2393 iptcc_chain_index_delete_chain(c, handle); 2394 2395 /* Change the name of the chain */ 2396 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL)); 2397 2398 /* Insert sorted into to list again */ 2399 iptc_insert_chain(handle, c); 2400 2401 set_changed(handle); 2402 2403 return 1; 2404} 2405 2406/* Sets the policy on a built-in chain. */ 2407int 2408TC_SET_POLICY(const IPT_CHAINLABEL chain, 2409 const IPT_CHAINLABEL policy, 2410 STRUCT_COUNTERS *counters, 2411 struct xtc_handle *handle) 2412{ 2413 struct chain_head *c; 2414 2415 iptc_fn = TC_SET_POLICY; 2416 2417 if (!(c = iptcc_find_label(chain, handle))) { 2418 DEBUGP("cannot find chain `%s'\n", chain); 2419 errno = ENOENT; 2420 return 0; 2421 } 2422 2423 if (!iptcc_is_builtin(c)) { 2424 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain); 2425 errno = ENOENT; 2426 return 0; 2427 } 2428 2429 if (strcmp(policy, LABEL_ACCEPT) == 0) 2430 c->verdict = -NF_ACCEPT - 1; 2431 else if (strcmp(policy, LABEL_DROP) == 0) 2432 c->verdict = -NF_DROP - 1; 2433 else { 2434 errno = EINVAL; 2435 return 0; 2436 } 2437 2438 if (counters) { 2439 /* set byte and packet counters */ 2440 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS)); 2441 c->counter_map.maptype = COUNTER_MAP_SET; 2442 } else { 2443 c->counter_map.maptype = COUNTER_MAP_NOMAP; 2444 } 2445 2446 set_changed(handle); 2447 2448 return 1; 2449} 2450 2451/* Without this, on gcc 2.7.2.3, we get: 2452 libiptc.c: In function `TC_COMMIT': 2453 libiptc.c:833: fixed or forbidden register was spilled. 2454 This may be due to a compiler bug or to impossible asm 2455 statements or clauses. 2456*/ 2457static void 2458subtract_counters(STRUCT_COUNTERS *answer, 2459 const STRUCT_COUNTERS *a, 2460 const STRUCT_COUNTERS *b) 2461{ 2462 answer->pcnt = a->pcnt - b->pcnt; 2463 answer->bcnt = a->bcnt - b->bcnt; 2464} 2465 2466 2467static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, unsigned int idx) 2468{ 2469 newcounters->counters[idx] = ((STRUCT_COUNTERS) { 0, 0}); 2470 DEBUGP_C("NOMAP => zero\n"); 2471} 2472 2473static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters, 2474 STRUCT_REPLACE *repl, unsigned int idx, 2475 unsigned int mappos) 2476{ 2477 /* Original read: X. 2478 * Atomic read on replacement: X + Y. 2479 * Currently in kernel: Z. 2480 * Want in kernel: X + Y + Z. 2481 * => Add in X + Y 2482 * => Add in replacement read. 2483 */ 2484 newcounters->counters[idx] = repl->counters[mappos]; 2485 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos); 2486} 2487 2488static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters, 2489 STRUCT_REPLACE *repl, unsigned int idx, 2490 unsigned int mappos, STRUCT_COUNTERS *counters) 2491{ 2492 /* Original read: X. 2493 * Atomic read on replacement: X + Y. 2494 * Currently in kernel: Z. 2495 * Want in kernel: Y + Z. 2496 * => Add in Y. 2497 * => Add in (replacement read - original read). 2498 */ 2499 subtract_counters(&newcounters->counters[idx], 2500 &repl->counters[mappos], 2501 counters); 2502 DEBUGP_C("ZEROED => mappos %u\n", mappos); 2503} 2504 2505static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters, 2506 unsigned int idx, STRUCT_COUNTERS *counters) 2507{ 2508 /* Want to set counter (iptables-restore) */ 2509 2510 memcpy(&newcounters->counters[idx], counters, 2511 sizeof(STRUCT_COUNTERS)); 2512 2513 DEBUGP_C("SET\n"); 2514} 2515 2516 2517int 2518TC_COMMIT(struct xtc_handle *handle) 2519{ 2520 /* Replace, then map back the counters. */ 2521 STRUCT_REPLACE *repl; 2522 STRUCT_COUNTERS_INFO *newcounters; 2523 struct chain_head *c; 2524 int ret; 2525 size_t counterlen; 2526 int new_number; 2527 unsigned int new_size; 2528 2529 iptc_fn = TC_COMMIT; 2530 CHECK(*handle); 2531 2532 /* Don't commit if nothing changed. */ 2533 if (!handle->changed) 2534 goto finished; 2535 2536 new_number = iptcc_compile_table_prep(handle, &new_size); 2537 if (new_number < 0) { 2538 errno = ENOMEM; 2539 goto out_zero; 2540 } 2541 2542 repl = malloc(sizeof(*repl) + new_size); 2543 if (!repl) { 2544 errno = ENOMEM; 2545 goto out_zero; 2546 } 2547 memset(repl, 0, sizeof(*repl) + new_size); 2548 2549#if 0 2550 TC_DUMP_ENTRIES(*handle); 2551#endif 2552 2553 counterlen = sizeof(STRUCT_COUNTERS_INFO) 2554 + sizeof(STRUCT_COUNTERS) * new_number; 2555 2556 /* These are the old counters we will get from kernel */ 2557 repl->counters = malloc(sizeof(STRUCT_COUNTERS) 2558 * handle->info.num_entries); 2559 if (!repl->counters) { 2560 errno = ENOMEM; 2561 goto out_free_repl; 2562 } 2563 /* These are the counters we're going to put back, later. */ 2564 newcounters = malloc(counterlen); 2565 if (!newcounters) { 2566 errno = ENOMEM; 2567 goto out_free_repl_counters; 2568 } 2569 memset(newcounters, 0, counterlen); 2570 2571 strcpy(repl->name, handle->info.name); 2572 repl->num_entries = new_number; 2573 repl->size = new_size; 2574 2575 repl->num_counters = handle->info.num_entries; 2576 repl->valid_hooks = handle->info.valid_hooks; 2577 2578 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n", 2579 repl->num_entries, repl->size, repl->num_counters); 2580 2581 ret = iptcc_compile_table(handle, repl); 2582 if (ret < 0) { 2583 errno = ret; 2584 goto out_free_newcounters; 2585 } 2586 2587 2588#ifdef IPTC_DEBUG2 2589 { 2590 int fd = open("/tmp/libiptc-so_set_replace.blob", 2591 O_CREAT|O_WRONLY); 2592 if (fd >= 0) { 2593 write(fd, repl, sizeof(*repl) + repl->size); 2594 close(fd); 2595 } 2596 } 2597#endif 2598 2599 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, 2600 sizeof(*repl) + repl->size); 2601 if (ret < 0) 2602 goto out_free_newcounters; 2603 2604 /* Put counters back. */ 2605 strcpy(newcounters->name, handle->info.name); 2606 newcounters->num_counters = new_number; 2607 2608 list_for_each_entry(c, &handle->chains, list) { 2609 struct rule_head *r; 2610 2611 /* Builtin chains have their own counters */ 2612 if (iptcc_is_builtin(c)) { 2613 DEBUGP("counter for chain-index %u: ", c->foot_index); 2614 switch(c->counter_map.maptype) { 2615 case COUNTER_MAP_NOMAP: 2616 counters_nomap(newcounters, c->foot_index); 2617 break; 2618 case COUNTER_MAP_NORMAL_MAP: 2619 counters_normal_map(newcounters, repl, 2620 c->foot_index, 2621 c->counter_map.mappos); 2622 break; 2623 case COUNTER_MAP_ZEROED: 2624 counters_map_zeroed(newcounters, repl, 2625 c->foot_index, 2626 c->counter_map.mappos, 2627 &c->counters); 2628 break; 2629 case COUNTER_MAP_SET: 2630 counters_map_set(newcounters, c->foot_index, 2631 &c->counters); 2632 break; 2633 } 2634 } 2635 2636 list_for_each_entry(r, &c->rules, list) { 2637 DEBUGP("counter for index %u: ", r->index); 2638 switch (r->counter_map.maptype) { 2639 case COUNTER_MAP_NOMAP: 2640 counters_nomap(newcounters, r->index); 2641 break; 2642 2643 case COUNTER_MAP_NORMAL_MAP: 2644 counters_normal_map(newcounters, repl, 2645 r->index, 2646 r->counter_map.mappos); 2647 break; 2648 2649 case COUNTER_MAP_ZEROED: 2650 counters_map_zeroed(newcounters, repl, 2651 r->index, 2652 r->counter_map.mappos, 2653 &r->entry->counters); 2654 break; 2655 2656 case COUNTER_MAP_SET: 2657 counters_map_set(newcounters, r->index, 2658 &r->entry->counters); 2659 break; 2660 } 2661 } 2662 } 2663 2664#ifdef IPTC_DEBUG2 2665 { 2666 int fd = open("/tmp/libiptc-so_set_add_counters.blob", 2667 O_CREAT|O_WRONLY); 2668 if (fd >= 0) { 2669 write(fd, newcounters, counterlen); 2670 close(fd); 2671 } 2672 } 2673#endif 2674 2675 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, 2676 newcounters, counterlen); 2677 if (ret < 0) 2678 goto out_free_newcounters; 2679 2680 free(repl->counters); 2681 free(repl); 2682 free(newcounters); 2683 2684finished: 2685 return 1; 2686 2687out_free_newcounters: 2688 free(newcounters); 2689out_free_repl_counters: 2690 free(repl->counters); 2691out_free_repl: 2692 free(repl); 2693out_zero: 2694 return 0; 2695} 2696 2697/* Translates errno numbers into more human-readable form than strerror. */ 2698const char * 2699TC_STRERROR(int err) 2700{ 2701 unsigned int i; 2702 struct table_struct { 2703 void *fn; 2704 int err; 2705 const char *message; 2706 } table [] = 2707 { { TC_INIT, EPERM, "Permission denied (you must be root)" }, 2708 { TC_INIT, EINVAL, "Module is wrong version" }, 2709 { TC_INIT, ENOENT, 2710 "Table does not exist (do you need to insmod?)" }, 2711 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, 2712 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, 2713 { TC_DELETE_CHAIN, EMLINK, 2714 "Can't delete chain with references left" }, 2715 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, 2716 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, 2717 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, 2718 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, 2719 { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, 2720 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, 2721 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, 2722 { TC_INSERT_ENTRY, EINVAL, "Target problem" }, 2723 /* ENOENT for DELETE probably means no matching rule */ 2724 { TC_DELETE_ENTRY, ENOENT, 2725 "Bad rule (does a matching rule exist in that chain?)" }, 2726 { TC_SET_POLICY, ENOENT, 2727 "Bad built-in chain name" }, 2728 { TC_SET_POLICY, EINVAL, 2729 "Bad policy name" }, 2730 2731 { NULL, 0, "Incompatible with this kernel" }, 2732 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 2733 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, 2734 { NULL, ENOMEM, "Memory allocation problem" }, 2735 { NULL, ENOENT, "No chain/target/match by that name" }, 2736 }; 2737 2738 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 2739 if ((!table[i].fn || table[i].fn == iptc_fn) 2740 && table[i].err == err) 2741 return table[i].message; 2742 } 2743 2744 return strerror(err); 2745} 2746 2747const struct xtc_ops TC_OPS = { 2748 .commit = TC_COMMIT, 2749 .free = TC_FREE, 2750 .builtin = TC_BUILTIN, 2751 .is_chain = TC_IS_CHAIN, 2752 .flush_entries = TC_FLUSH_ENTRIES, 2753 .create_chain = TC_CREATE_CHAIN, 2754 .set_policy = TC_SET_POLICY, 2755 .strerror = TC_STRERROR, 2756}; 2757