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