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