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