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