libiptc.c revision 14a1c9175257f73e936a68ba68d3541278c0e52a
1/* Library which manipulates firewall rules. Version 0.1. */ 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 14#ifndef IPT_LIB_DIR 15#define IPT_LIB_DIR "/usr/local/lib/iptables" 16#endif 17 18#ifndef __OPTIMIZE__ 19static STRUCT_ENTRY_TARGET * 20GET_TARGET(STRUCT_ENTRY *e) 21{ 22 return (void *)e + e->target_offset; 23} 24#endif 25 26static int sockfd = -1; 27static void *iptc_fn = NULL; 28 29static const char *hooknames[] 30= { [HOOK_PRE_ROUTING] "PREROUTING", 31 [HOOK_LOCAL_IN] "INPUT", 32 [HOOK_FORWARD] "FORWARD", 33 [HOOK_LOCAL_OUT] "OUTPUT", 34 [HOOK_POST_ROUTING] "POSTROUTING" 35}; 36 37struct counter_map 38{ 39 enum { 40 COUNTER_MAP_NOMAP, 41 COUNTER_MAP_NORMAL_MAP, 42 COUNTER_MAP_ZEROED 43 } maptype; 44 unsigned int mappos; 45}; 46 47/* Convenience structures */ 48struct ipt_error_target 49{ 50 STRUCT_ENTRY_TARGET t; 51 char error[TABLE_MAXNAMELEN]; 52}; 53 54struct chain_cache 55{ 56 char name[TABLE_MAXNAMELEN]; 57 /* This is the first rule in chain. */ 58 STRUCT_ENTRY *start; 59 /* Last rule in chain */ 60 STRUCT_ENTRY *end; 61}; 62 63STRUCT_TC_HANDLE 64{ 65 /* Have changes been made? */ 66 int changed; 67 /* Size in here reflects original state. */ 68 STRUCT_GETINFO info; 69 70 struct counter_map *counter_map; 71 /* Array of hook names */ 72 const char **hooknames; 73 74 /* Cached position of chain heads (NULL = no cache). */ 75 unsigned int cache_num_chains; 76 unsigned int cache_num_builtins; 77 struct chain_cache *cache_chain_heads; 78 79 /* Chain iterator: current chain cache entry. */ 80 struct chain_cache *cache_chain_iteration; 81 82 /* Rule iterator: terminal rule */ 83 STRUCT_ENTRY *cache_rule_end; 84 85 /* Number in here reflects current state. */ 86 unsigned int new_number; 87 STRUCT_GET_ENTRIES entries; 88}; 89 90static void 91set_changed(TC_HANDLE_T h) 92{ 93 if (h->cache_chain_heads) { 94 free(h->cache_chain_heads); 95 h->cache_chain_heads = NULL; 96 h->cache_num_chains = 0; 97 h->cache_chain_iteration = NULL; 98 h->cache_rule_end = NULL; 99 } 100 h->changed = 1; 101} 102 103#ifndef NDEBUG 104static void do_check(TC_HANDLE_T h, unsigned int line); 105#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) 106#else 107#define CHECK(h) 108#endif 109 110static inline int 111get_number(const STRUCT_ENTRY *i, 112 const STRUCT_ENTRY *seek, 113 unsigned int *pos) 114{ 115 if (i == seek) 116 return 1; 117 (*pos)++; 118 return 0; 119} 120 121static unsigned int 122entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek) 123{ 124 unsigned int pos = 0; 125 126 if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size, 127 get_number, seek, &pos) == 0) { 128 fprintf(stderr, "ERROR: offset %i not an entry!\n", 129 (char *)seek - (char *)h->entries.entrytable); 130 abort(); 131 } 132 return pos; 133} 134 135static inline int 136get_entry_n(STRUCT_ENTRY *i, 137 unsigned int number, 138 unsigned int *pos, 139 STRUCT_ENTRY **pe) 140{ 141 if (*pos == number) { 142 *pe = i; 143 return 1; 144 } 145 (*pos)++; 146 return 0; 147} 148 149static STRUCT_ENTRY * 150index2entry(TC_HANDLE_T h, unsigned int index) 151{ 152 unsigned int pos = 0; 153 STRUCT_ENTRY *ret = NULL; 154 155 ENTRY_ITERATE(h->entries.entrytable, h->entries.size, 156 get_entry_n, index, &pos, &ret); 157 158 return ret; 159} 160 161static inline STRUCT_ENTRY * 162get_entry(TC_HANDLE_T h, unsigned int offset) 163{ 164 return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset); 165} 166 167static inline unsigned long 168entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) 169{ 170 return (char *)e - (char *)h->entries.entrytable; 171} 172 173static unsigned long 174index2offset(TC_HANDLE_T h, unsigned int index) 175{ 176 return entry2offset(h, index2entry(h, index)); 177} 178 179static const char * 180get_errorlabel(TC_HANDLE_T h, unsigned int offset) 181{ 182 STRUCT_ENTRY *e; 183 184 e = get_entry(h, offset); 185 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) { 186 fprintf(stderr, "ERROR: offset %u not an error node!\n", 187 offset); 188 abort(); 189 } 190 191 return (const char *)GET_TARGET(e)->data; 192} 193 194/* Allocate handle of given size */ 195static TC_HANDLE_T 196alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) 197{ 198 size_t len; 199 TC_HANDLE_T h; 200 201 len = sizeof(STRUCT_TC_HANDLE) 202 + size 203 + num_rules * sizeof(struct counter_map); 204 205 if ((h = malloc(len)) == NULL) { 206 errno = ENOMEM; 207 return NULL; 208 } 209 210 h->changed = 0; 211 h->cache_num_chains = 0; 212 h->cache_chain_heads = NULL; 213 h->counter_map = (void *)h 214 + sizeof(STRUCT_TC_HANDLE) 215 + size; 216 strcpy(h->info.name, tablename); 217 strcpy(h->entries.name, tablename); 218 219 return h; 220} 221 222TC_HANDLE_T 223TC_INIT(const char *tablename) 224{ 225 TC_HANDLE_T h; 226 STRUCT_GETINFO info; 227 unsigned int i; 228 int tmp; 229 socklen_t s; 230 231 iptc_fn = TC_INIT; 232 233 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); 234 if (sockfd < 0) 235 return NULL; 236 237 s = sizeof(info); 238 if (strlen(tablename) >= TABLE_MAXNAMELEN) { 239 errno = EINVAL; 240 return NULL; 241 } 242 strcpy(info.name, tablename); 243 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) 244 return NULL; 245 246 if ((h = alloc_handle(info.name, info.size, info.num_entries)) 247 == NULL) 248 return NULL; 249 250/* Too hard --RR */ 251#if 0 252 sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name); 253 dynlib = dlopen(pathname, RTLD_NOW); 254 if (!dynlib) { 255 errno = ENOENT; 256 return NULL; 257 } 258 h->hooknames = dlsym(dynlib, "hooknames"); 259 if (!h->hooknames) { 260 errno = ENOENT; 261 return NULL; 262 } 263#else 264 h->hooknames = hooknames; 265#endif 266 267 /* Initialize current state */ 268 h->info = info; 269 h->new_number = h->info.num_entries; 270 for (i = 0; i < h->info.num_entries; i++) 271 h->counter_map[i] 272 = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i}); 273 274 h->entries.size = h->info.size; 275 276 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; 277 278 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries, 279 &tmp) < 0) { 280 free(h); 281 return NULL; 282 } 283 284 CHECK(h); 285 return h; 286} 287 288static inline int 289print_match(const STRUCT_ENTRY_MATCH *m) 290{ 291 printf("Match name: `%s'\n", m->u.user.name); 292 return 0; 293} 294 295static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); 296 297void 298TC_DUMP_ENTRIES(const TC_HANDLE_T handle) 299{ 300 CHECK(handle); 301 302 printf("libiptc v%s. %u entries, %u bytes.\n", 303 NETFILTER_VERSION, 304 handle->new_number, handle->entries.size); 305 printf("Table `%s'\n", handle->info.name); 306 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 307 handle->info.hook_entry[HOOK_PRE_ROUTING], 308 handle->info.hook_entry[HOOK_LOCAL_IN], 309 handle->info.hook_entry[HOOK_FORWARD], 310 handle->info.hook_entry[HOOK_LOCAL_OUT], 311 handle->info.hook_entry[HOOK_POST_ROUTING]); 312 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 313 handle->info.underflow[HOOK_PRE_ROUTING], 314 handle->info.underflow[HOOK_LOCAL_IN], 315 handle->info.underflow[HOOK_FORWARD], 316 handle->info.underflow[HOOK_LOCAL_OUT], 317 handle->info.underflow[HOOK_POST_ROUTING]); 318 319 ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size, 320 dump_entry, handle); 321} 322 323/* Returns 0 if not hook entry, else hooknumber + 1 */ 324static inline unsigned int 325is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) 326{ 327 unsigned int i; 328 329 for (i = 0; i < NUMHOOKS; i++) { 330 if ((h->info.valid_hooks & (1 << i)) 331 && get_entry(h, h->info.hook_entry[i]) == e) 332 return i+1; 333 } 334 return 0; 335} 336 337static inline int 338add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev) 339{ 340 unsigned int builtin; 341 342 /* Last entry. End it. */ 343 if (entry2offset(h, e) + e->next_offset == h->entries.size) { 344 /* This is the ERROR node at end of the table */ 345 h->cache_chain_heads[h->cache_num_chains-1].end = *prev; 346 return 0; 347 } 348 349 /* We know this is the start of a new chain if it's an ERROR 350 target, or a hook entry point */ 351 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) { 352 /* prev was last entry in previous chain */ 353 h->cache_chain_heads[h->cache_num_chains-1].end 354 = *prev; 355 356 strcpy(h->cache_chain_heads[h->cache_num_chains].name, 357 (const char *)GET_TARGET(e)->data); 358 h->cache_chain_heads[h->cache_num_chains].start 359 = (void *)e + e->next_offset; 360 h->cache_num_chains++; 361 } else if ((builtin = is_hook_entry(e, h)) != 0) { 362 if (h->cache_num_chains > 0) 363 /* prev was last entry in previous chain */ 364 h->cache_chain_heads[h->cache_num_chains-1].end 365 = *prev; 366 367 strcpy(h->cache_chain_heads[h->cache_num_chains].name, 368 h->hooknames[builtin-1]); 369 h->cache_chain_heads[h->cache_num_chains].start 370 = (void *)e; 371 h->cache_num_chains++; 372 } 373 374 *prev = e; 375 return 0; 376} 377 378static int alphasort(const void *a, const void *b) 379{ 380 return strcmp(((struct chain_cache *)a)->name, 381 ((struct chain_cache *)b)->name); 382} 383 384static int populate_cache(TC_HANDLE_T h) 385{ 386 unsigned int i; 387 STRUCT_ENTRY *prev; 388 389 /* # chains < # rules / 2 + num builtins - 1 */ 390 h->cache_chain_heads = malloc((h->new_number / 2 + 4) 391 * sizeof(struct chain_cache)); 392 if (!h->cache_chain_heads) { 393 errno = ENOMEM; 394 return 0; 395 } 396 397 h->cache_num_chains = 0; 398 h->cache_num_builtins = 0; 399 400 /* Count builtins */ 401 for (i = 0; i < NUMHOOKS; i++) { 402 if (h->info.valid_hooks & (1 << i)) 403 h->cache_num_builtins++; 404 } 405 406 prev = NULL; 407 ENTRY_ITERATE(h->entries.entrytable, h->entries.size, 408 add_chain, h, &prev); 409 410 qsort(h->cache_chain_heads + h->cache_num_builtins, 411 h->cache_num_chains - h->cache_num_builtins, 412 sizeof(struct chain_cache), alphasort); 413 414 return 1; 415} 416 417/* Returns cache ptr if found, otherwise NULL. */ 418static struct chain_cache * 419find_label(const char *name, TC_HANDLE_T handle) 420{ 421 unsigned int i; 422 423 if (handle->cache_chain_heads == NULL 424 && !populate_cache(handle)) 425 return NULL; 426 427 /* FIXME: Linear search through builtins, then binary --RR */ 428 for (i = 0; i < handle->cache_num_chains; i++) { 429 if (strcmp(handle->cache_chain_heads[i].name, name) == 0) 430 return &handle->cache_chain_heads[i]; 431 } 432 433 return NULL; 434} 435 436/* Does this chain exist? */ 437int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) 438{ 439 return find_label(chain, handle) != NULL; 440} 441 442/* Returns the position of the final (ie. unconditional) element. */ 443static unsigned int 444get_chain_end(const TC_HANDLE_T handle, unsigned int start) 445{ 446 unsigned int last_off, off; 447 STRUCT_ENTRY *e; 448 449 last_off = start; 450 e = get_entry(handle, start); 451 452 /* Terminate when we meet a error label or a hook entry. */ 453 for (off = start + e->next_offset; 454 off < handle->entries.size; 455 last_off = off, off += e->next_offset) { 456 STRUCT_ENTRY_TARGET *t; 457 unsigned int i; 458 459 e = get_entry(handle, off); 460 461 /* We hit an entry point. */ 462 for (i = 0; i < NUMHOOKS; i++) { 463 if ((handle->info.valid_hooks & (1 << i)) 464 && off == handle->info.hook_entry[i]) 465 return last_off; 466 } 467 468 /* We hit a user chain label */ 469 t = GET_TARGET(e); 470 if (strcmp(t->u.user.name, ERROR_TARGET) == 0) 471 return last_off; 472 } 473 /* SHOULD NEVER HAPPEN */ 474 fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n", 475 handle->entries.size, off); 476 abort(); 477} 478 479/* Iterator functions to run through the chains. */ 480const char * 481TC_FIRST_CHAIN(TC_HANDLE_T *handle) 482{ 483 if ((*handle)->cache_chain_heads == NULL 484 && !populate_cache(*handle)) 485 return NULL; 486 487 (*handle)->cache_chain_iteration 488 = &(*handle)->cache_chain_heads[0]; 489 490 return (*handle)->cache_chain_iteration->name; 491} 492 493/* Iterator functions to run through the chains. Returns NULL at end. */ 494const char * 495TC_NEXT_CHAIN(TC_HANDLE_T *handle) 496{ 497 (*handle)->cache_chain_iteration++; 498 499 if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads 500 == (*handle)->cache_num_chains) 501 return NULL; 502 503 return (*handle)->cache_chain_iteration->name; 504} 505 506/* Get first rule in the given chain: NULL for empty chain. */ 507const STRUCT_ENTRY * 508TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) 509{ 510 struct chain_cache *c; 511 512 c = find_label(chain, *handle); 513 if (!c) { 514 errno = ENOENT; 515 return NULL; 516 } 517 518 /* Empty chain: single return/policy rule */ 519 if (c->start == c->end) 520 return NULL; 521 522 (*handle)->cache_rule_end = c->end; 523 return c->start; 524} 525 526/* Returns NULL when rules run out. */ 527const STRUCT_ENTRY * 528TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) 529{ 530 if ((void *)prev + prev->next_offset 531 == (void *)(*handle)->cache_rule_end) 532 return NULL; 533 534 return (void *)prev + prev->next_offset; 535} 536 537#if 0 538/* How many rules in this chain? */ 539unsigned int 540TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) 541{ 542 unsigned int off = 0; 543 STRUCT_ENTRY *start, *end; 544 545 CHECK(*handle); 546 if (!find_label(&off, chain, *handle)) { 547 errno = ENOENT; 548 return (unsigned int)-1; 549 } 550 551 start = get_entry(*handle, off); 552 end = get_entry(*handle, get_chain_end(*handle, off)); 553 554 return entry2index(*handle, end) - entry2index(*handle, start); 555} 556 557/* Get n'th rule in this chain. */ 558const STRUCT_ENTRY *TC_GET_RULE(const char *chain, 559 unsigned int n, 560 TC_HANDLE_T *handle) 561{ 562 unsigned int pos = 0, chainindex; 563 564 CHECK(*handle); 565 if (!find_label(&pos, chain, *handle)) { 566 errno = ENOENT; 567 return NULL; 568 } 569 570 chainindex = entry2index(*handle, get_entry(*handle, pos)); 571 572 return index2entry(*handle, chainindex + n); 573} 574#endif 575 576static const char * 577target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) 578{ 579 int spos; 580 unsigned int labelidx; 581 STRUCT_ENTRY *jumpto; 582 583 /* To avoid const warnings */ 584 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; 585 586 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) 587 return GET_TARGET(e)->u.user.name; 588 589 /* Standard target: evaluate */ 590 spos = *(int *)GET_TARGET(e)->data; 591 if (spos < 0) { 592 if (spos == RETURN) 593 return LABEL_RETURN; 594 else if (spos == -NF_ACCEPT-1) 595 return LABEL_ACCEPT; 596 else if (spos == -NF_DROP-1) 597 return LABEL_DROP; 598 else if (spos == -NF_QUEUE-1) 599 return LABEL_QUEUE; 600 601 fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n", 602 entry2offset(handle, e), handle->entries.size, 603 spos); 604 abort(); 605 } 606 607 jumpto = get_entry(handle, spos); 608 609 /* Fall through rule */ 610 if (jumpto == (void *)e + e->next_offset) 611 return ""; 612 613 /* Must point to head of a chain: ie. after error rule */ 614 labelidx = entry2index(handle, jumpto) - 1; 615 return get_errorlabel(handle, index2offset(handle, labelidx)); 616} 617 618/* Returns a pointer to the target name of this position. */ 619const char *TC_GET_TARGET(const STRUCT_ENTRY *e, 620 TC_HANDLE_T *handle) 621{ 622 return target_name(*handle, e); 623} 624 625/* Is this a built-in chain? Actually returns hook + 1. */ 626int 627TC_BUILTIN(const char *chain, const TC_HANDLE_T handle) 628{ 629 unsigned int i; 630 631 for (i = 0; i < NUMHOOKS; i++) { 632 if ((handle->info.valid_hooks & (1 << i)) 633 && handle->hooknames[i] 634 && strcmp(handle->hooknames[i], chain) == 0) 635 return i+1; 636 } 637 return 0; 638} 639 640/* Get the policy of a given built-in chain */ 641const char * 642TC_GET_POLICY(const char *chain, 643 STRUCT_COUNTERS *counters, 644 TC_HANDLE_T *handle) 645{ 646 unsigned int start; 647 STRUCT_ENTRY *e; 648 int hook; 649 650 hook = TC_BUILTIN(chain, *handle); 651 if (hook != 0) 652 start = (*handle)->info.hook_entry[hook-1]; 653 else 654 return NULL; 655 656 e = get_entry(*handle, get_chain_end(*handle, start)); 657 *counters = e->counters; 658 659 return target_name(*handle, e); 660} 661 662static int 663correct_verdict(STRUCT_ENTRY *e, 664 char *base, 665 unsigned int offset, int delta_offset) 666{ 667 STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e); 668 unsigned int curr = (char *)e - base; 669 670 /* Trap: insert of fall-through rule. Don't change fall-through 671 verdict to jump-over-next-rule. */ 672 if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0 673 && t->verdict > (int)offset 674 && !(curr == offset && 675 t->verdict == curr + e->next_offset)) { 676 t->verdict += delta_offset; 677 } 678 679 return 0; 680} 681 682/* Adjusts standard verdict jump positions after an insertion/deletion. */ 683static int 684set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle) 685{ 686 ENTRY_ITERATE((*handle)->entries.entrytable, 687 (*handle)->entries.size, 688 correct_verdict, (char *)(*handle)->entries.entrytable, 689 offset, delta_offset); 690 691 set_changed(*handle); 692 return 1; 693} 694 695/* If prepend is set, then we are prepending to a chain: if the 696 * insertion position is an entry point, keep the entry point. */ 697static int 698insert_rules(unsigned int num_rules, unsigned int rules_size, 699 const STRUCT_ENTRY *insert, 700 unsigned int offset, unsigned int num_rules_offset, 701 int prepend, 702 TC_HANDLE_T *handle) 703{ 704 TC_HANDLE_T newh; 705 STRUCT_GETINFO newinfo; 706 unsigned int i; 707 708 if (offset >= (*handle)->entries.size) { 709 errno = EINVAL; 710 return 0; 711 } 712 713 newinfo = (*handle)->info; 714 715 /* Fix up entry points. */ 716 for (i = 0; i < NUMHOOKS; i++) { 717 /* Entry points to START of chain, so keep same if 718 inserting on at that point. */ 719 if ((*handle)->info.hook_entry[i] > offset) 720 newinfo.hook_entry[i] += rules_size; 721 722 /* Underflow always points to END of chain (policy), 723 so if something is inserted at same point, it 724 should be advanced. */ 725 if ((*handle)->info.underflow[i] >= offset) 726 newinfo.underflow[i] += rules_size; 727 } 728 729 newh = alloc_handle((*handle)->info.name, 730 (*handle)->info.size + rules_size, 731 (*handle)->info.num_entries + num_rules); 732 if (!newh) 733 return 0; 734 newh->info = newinfo; 735 736 /* Copy pre... */ 737 memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset); 738 /* ... Insert new ... */ 739 memcpy((char *)newh->entries.entrytable + offset, insert, rules_size); 740 /* ... copy post */ 741 memcpy((char *)newh->entries.entrytable + offset + rules_size, 742 (char *)(*handle)->entries.entrytable + offset, 743 (*handle)->entries.size - offset); 744 745 /* Move counter map. */ 746 /* Copy pre... */ 747 memcpy(newh->counter_map, (*handle)->counter_map, 748 sizeof(struct counter_map) * num_rules_offset); 749 /* ... copy post */ 750 memcpy(newh->counter_map + num_rules_offset + num_rules, 751 (*handle)->counter_map + num_rules_offset, 752 sizeof(struct counter_map) * ((*handle)->new_number 753 - num_rules_offset)); 754 /* Set intermediates to no counter copy */ 755 for (i = 0; i < num_rules; i++) 756 newh->counter_map[num_rules_offset+i] 757 = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); 758 759 newh->new_number = (*handle)->new_number + num_rules; 760 newh->entries.size = (*handle)->entries.size + rules_size; 761 newh->hooknames = (*handle)->hooknames; 762 763 if ((*handle)->cache_chain_heads) 764 free((*handle)->cache_chain_heads); 765 free(*handle); 766 *handle = newh; 767 768 return set_verdict(offset, rules_size, handle); 769} 770 771static int 772delete_rules(unsigned int num_rules, unsigned int rules_size, 773 unsigned int offset, unsigned int num_rules_offset, 774 TC_HANDLE_T *handle) 775{ 776 unsigned int i; 777 778 if (offset + rules_size > (*handle)->entries.size) { 779 errno = EINVAL; 780 return 0; 781 } 782 783 /* Fix up entry points. */ 784 for (i = 0; i < NUMHOOKS; i++) { 785 /* In practice, we never delete up to a hook entry, 786 since the built-in chains are always first, 787 so these two are never equal */ 788 if ((*handle)->info.hook_entry[i] >= offset + rules_size) 789 (*handle)->info.hook_entry[i] -= rules_size; 790 else if ((*handle)->info.hook_entry[i] > offset) { 791 fprintf(stderr, "ERROR: Deleting entry %u %u %u\n", 792 i, (*handle)->info.hook_entry[i], offset); 793 abort(); 794 } 795 796 /* Underflow points to policy (terminal) rule in 797 built-in, so sequality is valid here (when deleting 798 the last rule). */ 799 if ((*handle)->info.underflow[i] >= offset + rules_size) 800 (*handle)->info.underflow[i] -= rules_size; 801 else if ((*handle)->info.underflow[i] > offset) { 802 fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n", 803 i, (*handle)->info.underflow[i], offset); 804 abort(); 805 } 806 } 807 808 /* Move the rules down. */ 809 memmove((char *)(*handle)->entries.entrytable + offset, 810 (char *)(*handle)->entries.entrytable + offset + rules_size, 811 (*handle)->entries.size - (offset + rules_size)); 812 813 /* Move the counter map down. */ 814 memmove(&(*handle)->counter_map[num_rules_offset], 815 &(*handle)->counter_map[num_rules_offset + num_rules], 816 sizeof(struct counter_map) 817 * ((*handle)->new_number - (num_rules + num_rules_offset))); 818 819 /* Fix numbers */ 820 (*handle)->new_number -= num_rules; 821 (*handle)->entries.size -= rules_size; 822 823 return set_verdict(offset, -(int)rules_size, handle); 824} 825 826static int 827standard_map(STRUCT_ENTRY *e, int verdict) 828{ 829 STRUCT_STANDARD_TARGET *t; 830 831 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 832 833 if (t->target.u.target_size 834 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { 835 errno = EINVAL; 836 return 0; 837 } 838 /* memset for memcmp convenience on delete/replace */ 839 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); 840 strcpy(t->target.u.user.name, STANDARD_TARGET); 841 t->verdict = verdict; 842 843 return 1; 844} 845 846static int 847map_target(const TC_HANDLE_T handle, 848 STRUCT_ENTRY *e, 849 unsigned int offset, 850 STRUCT_ENTRY_TARGET *old) 851{ 852 STRUCT_ENTRY_TARGET *t = GET_TARGET(e); 853 854 /* Save old target (except data, which we don't change, except for 855 standard case, where we don't care). */ 856 *old = *t; 857 858 /* Maybe it's empty (=> fall through) */ 859 if (strcmp(t->u.user.name, "") == 0) 860 return standard_map(e, offset + e->next_offset); 861 /* Maybe it's a standard target name... */ 862 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) 863 return standard_map(e, -NF_ACCEPT - 1); 864 else if (strcmp(t->u.user.name, LABEL_DROP) == 0) 865 return standard_map(e, -NF_DROP - 1); 866 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0) 867 return standard_map(e, -NF_QUEUE - 1); 868 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0) 869 return standard_map(e, RETURN); 870 else if (TC_BUILTIN(t->u.user.name, handle)) { 871 /* Can't jump to builtins. */ 872 errno = EINVAL; 873 return 0; 874 } else { 875 /* Maybe it's an existing chain name. */ 876 struct chain_cache *c; 877 878 c = find_label(t->u.user.name, handle); 879 if (c) 880 return standard_map(e, entry2offset(handle, c->start)); 881 } 882 883 /* Must be a module? If not, kernel will reject... */ 884 /* memset to all 0 for your memcmp convenience. */ 885 memset(t->u.user.name + strlen(t->u.user.name), 886 0, 887 FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); 888 return 1; 889} 890 891static void 892unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old) 893{ 894 STRUCT_ENTRY_TARGET *t = GET_TARGET(e); 895 896 /* Save old target (except data, which we don't change, except for 897 standard case, where we don't care). */ 898 *t = *old; 899} 900 901/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ 902int 903TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, 904 const STRUCT_ENTRY *e, 905 unsigned int rulenum, 906 TC_HANDLE_T *handle) 907{ 908 unsigned int chainindex, offset; 909 STRUCT_ENTRY_TARGET old; 910 struct chain_cache *c; 911 STRUCT_ENTRY *tmp; 912 int ret; 913 914 iptc_fn = TC_INSERT_ENTRY; 915 if (!(c = find_label(chain, *handle))) { 916 errno = ENOENT; 917 return 0; 918 } 919 920 chainindex = entry2index(*handle, c->start); 921 922 tmp = index2entry(*handle, chainindex + rulenum); 923 if (!tmp || tmp > c->end) { 924 errno = E2BIG; 925 return 0; 926 } 927 offset = index2offset(*handle, chainindex + rulenum); 928 929 /* Mapping target actually alters entry, but that's 930 transparent to the caller. */ 931 if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) 932 return 0; 933 934 ret = insert_rules(1, e->next_offset, e, offset, 935 chainindex + rulenum, rulenum == 0, handle); 936 unmap_target((STRUCT_ENTRY *)e, &old); 937 return ret; 938} 939 940/* Atomically replace rule `rulenum' in `chain' with `fw'. */ 941int 942TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, 943 const STRUCT_ENTRY *e, 944 unsigned int rulenum, 945 TC_HANDLE_T *handle) 946{ 947 unsigned int chainindex, offset; 948 STRUCT_ENTRY_TARGET old; 949 struct chain_cache *c; 950 STRUCT_ENTRY *tmp; 951 int ret; 952 953 iptc_fn = TC_REPLACE_ENTRY; 954 955 if (!(c = find_label(chain, *handle))) { 956 errno = ENOENT; 957 return 0; 958 } 959 960 chainindex = entry2index(*handle, c->start); 961 962 tmp = index2entry(*handle, chainindex + rulenum); 963 if (!tmp || tmp >= c->end) { 964 errno = E2BIG; 965 return 0; 966 } 967 968 offset = index2offset(*handle, chainindex + rulenum); 969 /* Replace = delete and insert. */ 970 if (!delete_rules(1, get_entry(*handle, offset)->next_offset, 971 offset, chainindex + rulenum, handle)) 972 return 0; 973 974 if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) 975 return 0; 976 977 ret = insert_rules(1, e->next_offset, e, offset, 978 chainindex + rulenum, 1, handle); 979 unmap_target((STRUCT_ENTRY *)e, &old); 980 return ret; 981} 982 983/* Append entry `fw' to chain `chain'. Equivalent to insert with 984 rulenum = length of chain. */ 985int 986TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, 987 const STRUCT_ENTRY *e, 988 TC_HANDLE_T *handle) 989{ 990 struct chain_cache *c; 991 STRUCT_ENTRY_TARGET old; 992 int ret; 993 994 iptc_fn = TC_APPEND_ENTRY; 995 if (!(c = find_label(chain, *handle))) { 996 errno = ENOENT; 997 return 0; 998 } 999 1000 if (!map_target(*handle, (STRUCT_ENTRY *)e, 1001 entry2offset(*handle, c->end), &old)) 1002 return 0; 1003 1004 ret = insert_rules(1, e->next_offset, e, 1005 entry2offset(*handle, c->end), 1006 entry2index(*handle, c->end), 1007 0, handle); 1008 unmap_target((STRUCT_ENTRY *)e, &old); 1009 return ret; 1010} 1011 1012static inline int 1013match_different(const STRUCT_ENTRY_MATCH *a, 1014 const unsigned char *a_elems, 1015 const unsigned char *b_elems, 1016 unsigned char **maskptr) 1017{ 1018 const STRUCT_ENTRY_MATCH *b; 1019 unsigned int i; 1020 1021 /* Offset of b is the same as a. */ 1022 b = (void *)b_elems + ((unsigned char *)a - a_elems); 1023 1024 if (a->u.match_size != b->u.match_size) 1025 return 1; 1026 1027 if (strcmp(a->u.user.name, b->u.user.name) != 0) 1028 return 1; 1029 1030 *maskptr += ALIGN(sizeof(*a)); 1031 1032 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) 1033 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) 1034 return 1; 1035 *maskptr += i; 1036 return 0; 1037} 1038 1039static inline int 1040target_different(const unsigned char *a_targdata, 1041 const unsigned char *b_targdata, 1042 unsigned int tdatasize, 1043 const unsigned char *mask) 1044{ 1045 unsigned int i; 1046 for (i = 0; i < tdatasize; i++) 1047 if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0) 1048 return 1; 1049 1050 return 0; 1051} 1052 1053static int 1054is_same(const STRUCT_ENTRY *a, 1055 const STRUCT_ENTRY *b, 1056 unsigned char *matchmask); 1057 1058/* Delete the first rule in `chain' which matches `fw'. */ 1059int 1060TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, 1061 const STRUCT_ENTRY *origfw, 1062 unsigned char *matchmask, 1063 TC_HANDLE_T *handle) 1064{ 1065 unsigned int offset; 1066 struct chain_cache *c; 1067 STRUCT_ENTRY *e, *fw; 1068 1069 iptc_fn = TC_DELETE_ENTRY; 1070 if (!(c = find_label(chain, *handle))) { 1071 errno = ENOENT; 1072 return 0; 1073 } 1074 1075 fw = malloc(origfw->next_offset); 1076 if (fw == NULL) { 1077 errno = ENOMEM; 1078 return 0; 1079 } 1080 1081 for (offset = entry2offset(*handle, c->start); 1082 offset < entry2offset(*handle, c->end); 1083 offset += e->next_offset) { 1084 STRUCT_ENTRY_TARGET discard; 1085 1086 memcpy(fw, origfw, origfw->next_offset); 1087 1088 /* FIXME: handle this in is_same --RR */ 1089 if (!map_target(*handle, fw, offset, &discard)) { 1090 free(fw); 1091 return 0; 1092 } 1093 e = get_entry(*handle, offset); 1094 1095#if 0 1096 printf("Deleting:\n"); 1097 dump_entry(newe); 1098#endif 1099 if (is_same(e, fw, matchmask)) { 1100 int ret; 1101 ret = delete_rules(1, e->next_offset, 1102 offset, entry2index(*handle, e), 1103 handle); 1104 free(fw); 1105 return ret; 1106 } 1107 } 1108 1109 free(fw); 1110 errno = ENOENT; 1111 return 0; 1112} 1113 1114/* Delete the rule in position `rulenum' in `chain'. */ 1115int 1116TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, 1117 unsigned int rulenum, 1118 TC_HANDLE_T *handle) 1119{ 1120 unsigned int index; 1121 int ret; 1122 STRUCT_ENTRY *e; 1123 struct chain_cache *c; 1124 1125 iptc_fn = TC_DELETE_NUM_ENTRY; 1126 if (!(c = find_label(chain, *handle))) { 1127 errno = ENOENT; 1128 return 0; 1129 } 1130 1131 index = entry2index(*handle, c->start) + rulenum; 1132 1133 if (index >= entry2index(*handle, c->end)) { 1134 errno = E2BIG; 1135 return 0; 1136 } 1137 1138 e = index2entry(*handle, index); 1139 if (e == NULL) { 1140 errno = EINVAL; 1141 return 0; 1142 } 1143 1144 ret = delete_rules(1, e->next_offset, entry2offset(*handle, e), 1145 index, handle); 1146 return ret; 1147} 1148 1149/* Check the packet `fw' on chain `chain'. Returns the verdict, or 1150 NULL and sets errno. */ 1151const char * 1152TC_CHECK_PACKET(const IPT_CHAINLABEL chain, 1153 STRUCT_ENTRY *entry, 1154 TC_HANDLE_T *handle) 1155{ 1156 errno = ENOSYS; 1157 return NULL; 1158} 1159 1160/* Flushes the entries in the given chain (ie. empties chain). */ 1161int 1162TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1163{ 1164 unsigned int startindex, endindex; 1165 struct chain_cache *c; 1166 int ret; 1167 1168 iptc_fn = TC_FLUSH_ENTRIES; 1169 if (!(c = find_label(chain, *handle))) { 1170 errno = ENOENT; 1171 return 0; 1172 } 1173 startindex = entry2index(*handle, c->start); 1174 endindex = entry2index(*handle, c->end); 1175 1176 ret = delete_rules(endindex - startindex, 1177 (char *)c->end - (char *)c->start, 1178 entry2offset(*handle, c->start), startindex, 1179 handle); 1180 return ret; 1181} 1182 1183/* Zeroes the counters in a chain. */ 1184int 1185TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1186{ 1187 unsigned int i, end; 1188 struct chain_cache *c; 1189 1190 if (!(c = find_label(chain, *handle))) { 1191 errno = ENOENT; 1192 return 0; 1193 } 1194 1195 i = entry2index(*handle, c->start); 1196 end = entry2index(*handle, c->end); 1197 1198 for (; i <= end; i++) { 1199 if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP) 1200 (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED; 1201 } 1202 set_changed(*handle); 1203 1204 return 1; 1205} 1206 1207/* Creates a new chain. */ 1208/* To create a chain, create two rules: error node and unconditional 1209 * return. */ 1210int 1211TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1212{ 1213 int ret; 1214 struct { 1215 STRUCT_ENTRY head; 1216 struct ipt_error_target name; 1217 STRUCT_ENTRY ret; 1218 STRUCT_STANDARD_TARGET target; 1219 } newc; 1220 1221 iptc_fn = TC_CREATE_CHAIN; 1222 1223 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1224 QUEUE, RETURN. */ 1225 if (find_label(chain, *handle) 1226 || strcmp(chain, LABEL_DROP) == 0 1227 || strcmp(chain, LABEL_ACCEPT) == 0 1228 || strcmp(chain, LABEL_QUEUE) == 0 1229 || strcmp(chain, LABEL_RETURN) == 0) { 1230 errno = EEXIST; 1231 return 0; 1232 } 1233 1234 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { 1235 errno = EINVAL; 1236 return 0; 1237 } 1238 1239 memset(&newc, 0, sizeof(newc)); 1240 newc.head.target_offset = sizeof(STRUCT_ENTRY); 1241 newc.head.next_offset 1242 = sizeof(STRUCT_ENTRY) 1243 + ALIGN(sizeof(struct ipt_error_target)); 1244 strcpy(newc.name.t.u.user.name, ERROR_TARGET); 1245 newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target)); 1246 strcpy(newc.name.error, chain); 1247 1248 newc.ret.target_offset = sizeof(STRUCT_ENTRY); 1249 newc.ret.next_offset 1250 = sizeof(STRUCT_ENTRY) 1251 + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 1252 strcpy(newc.target.target.u.user.name, STANDARD_TARGET); 1253 newc.target.target.u.target_size 1254 = ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 1255 newc.target.verdict = RETURN; 1256 1257 /* Add just before terminal entry */ 1258 ret = insert_rules(2, sizeof(newc), &newc.head, 1259 index2offset(*handle, (*handle)->new_number - 1), 1260 (*handle)->new_number - 1, 1261 0, handle); 1262 return ret; 1263} 1264 1265static int 1266count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref) 1267{ 1268 STRUCT_STANDARD_TARGET *t; 1269 1270 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) { 1271 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 1272 1273 if (t->verdict == offset) 1274 (*ref)++; 1275 } 1276 1277 return 0; 1278} 1279 1280/* Get the number of references to this chain. */ 1281int 1282TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, 1283 TC_HANDLE_T *handle) 1284{ 1285 struct chain_cache *c; 1286 1287 if (!(c = find_label(chain, *handle))) { 1288 errno = ENOENT; 1289 return 0; 1290 } 1291 1292 *ref = 0; 1293 ENTRY_ITERATE((*handle)->entries.entrytable, 1294 (*handle)->entries.size, 1295 count_ref, entry2offset(*handle, c->start), ref); 1296 return 1; 1297} 1298 1299/* Deletes a chain. */ 1300int 1301TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1302{ 1303 unsigned int labelidx, labeloff; 1304 unsigned int references; 1305 struct chain_cache *c; 1306 int ret; 1307 1308 if (!TC_GET_REFERENCES(&references, chain, handle)) 1309 return 0; 1310 1311 iptc_fn = TC_DELETE_CHAIN; 1312 1313 if (TC_BUILTIN(chain, *handle)) { 1314 errno = EINVAL; 1315 return 0; 1316 } 1317 1318 if (references > 0) { 1319 errno = EMLINK; 1320 return 0; 1321 } 1322 1323 if (!(c = find_label(chain, *handle))) { 1324 errno = ENOENT; 1325 return 0; 1326 } 1327 1328 if ((void *)c->start != c->end) { 1329 errno = ENOTEMPTY; 1330 return 0; 1331 } 1332 1333 /* Need label index: preceeds chain start */ 1334 labelidx = entry2index(*handle, c->start) - 1; 1335 labeloff = index2offset(*handle, labelidx); 1336 1337 ret = delete_rules(2, 1338 get_entry(*handle, labeloff)->next_offset 1339 + c->start->next_offset, 1340 labeloff, labelidx, handle); 1341 return ret; 1342} 1343 1344/* Renames a chain. */ 1345int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, 1346 const IPT_CHAINLABEL newname, 1347 TC_HANDLE_T *handle) 1348{ 1349 unsigned int labeloff, labelidx; 1350 struct chain_cache *c; 1351 struct ipt_error_target *t; 1352 1353 iptc_fn = TC_RENAME_CHAIN; 1354 1355 /* find_label doesn't cover built-in targets: DROP, ACCEPT 1356 RETURN. */ 1357 if (find_label(newname, *handle) 1358 || strcmp(newname, LABEL_DROP) == 0 1359 || strcmp(newname, LABEL_ACCEPT) == 0 1360 || strcmp(newname, LABEL_RETURN) == 0) { 1361 errno = EEXIST; 1362 return 0; 1363 } 1364 1365 if (!(c = find_label(oldname, *handle)) 1366 || TC_BUILTIN(oldname, *handle)) { 1367 errno = ENOENT; 1368 return 0; 1369 } 1370 1371 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { 1372 errno = EINVAL; 1373 return 0; 1374 } 1375 1376 /* Need label index: preceeds chain start */ 1377 labelidx = entry2index(*handle, c->start) - 1; 1378 labeloff = index2offset(*handle, labelidx); 1379 1380 t = (struct ipt_error_target *) 1381 GET_TARGET(get_entry(*handle, labeloff)); 1382 1383 memset(t->error, 0, sizeof(t->error)); 1384 strcpy(t->error, newname); 1385 set_changed(*handle); 1386 1387 return 1; 1388} 1389 1390/* Sets the policy on a built-in chain. */ 1391int 1392TC_SET_POLICY(const IPT_CHAINLABEL chain, 1393 const IPT_CHAINLABEL policy, 1394 TC_HANDLE_T *handle) 1395{ 1396 unsigned int hook; 1397 unsigned int policyoff; 1398 STRUCT_ENTRY *e; 1399 STRUCT_STANDARD_TARGET *t; 1400 1401 iptc_fn = TC_SET_POLICY; 1402 /* Figure out which chain. */ 1403 hook = TC_BUILTIN(chain, *handle); 1404 if (hook == 0) { 1405 errno = ENOENT; 1406 return 0; 1407 } else 1408 hook--; 1409 1410 policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]); 1411 if (policyoff != (*handle)->info.underflow[hook]) { 1412 printf("ERROR: Policy for `%s' offset %u != underflow %u\n", 1413 chain, policyoff, (*handle)->info.underflow[hook]); 1414 return 0; 1415 } 1416 1417 e = get_entry(*handle, policyoff); 1418 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 1419 1420 if (strcmp(policy, LABEL_ACCEPT) == 0) 1421 t->verdict = -NF_ACCEPT - 1; 1422 else if (strcmp(policy, LABEL_DROP) == 0) 1423 t->verdict = -NF_DROP - 1; 1424 else { 1425 errno = EINVAL; 1426 return 0; 1427 } 1428 (*handle)->counter_map[entry2index(*handle, e)] 1429 = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); 1430 set_changed(*handle); 1431 1432 return 1; 1433} 1434 1435/* Without this, on gcc 2.7.2.3, we get: 1436 libiptc.c: In function `TC_COMMIT': 1437 libiptc.c:833: fixed or forbidden register was spilled. 1438 This may be due to a compiler bug or to impossible asm 1439 statements or clauses. 1440*/ 1441static void 1442subtract_counters(STRUCT_COUNTERS *answer, 1443 const STRUCT_COUNTERS *a, 1444 const STRUCT_COUNTERS *b) 1445{ 1446 answer->pcnt = a->pcnt - b->pcnt; 1447 answer->bcnt = a->bcnt - b->bcnt; 1448} 1449 1450int 1451TC_COMMIT(TC_HANDLE_T *handle) 1452{ 1453 /* Replace, then map back the counters. */ 1454 STRUCT_REPLACE *repl; 1455 STRUCT_COUNTERS_INFO *newcounters; 1456 unsigned int i; 1457 size_t counterlen 1458 = sizeof(STRUCT_COUNTERS_INFO) 1459 + sizeof(STRUCT_COUNTERS) * (*handle)->new_number; 1460 1461 CHECK(*handle); 1462#if 0 1463 TC_TC_DUMP_ENTRIES(*handle); 1464#endif 1465 1466 /* Don't commit if nothing changed. */ 1467 if (!(*handle)->changed) 1468 goto finished; 1469 1470 repl = malloc(sizeof(*repl) + (*handle)->entries.size); 1471 if (!repl) { 1472 errno = ENOMEM; 1473 return 0; 1474 } 1475 1476 /* These are the old counters we will get from kernel */ 1477 repl->counters = malloc(sizeof(STRUCT_COUNTERS) 1478 * (*handle)->info.num_entries); 1479 if (!repl->counters) { 1480 free(repl); 1481 errno = ENOMEM; 1482 return 0; 1483 } 1484 1485 /* These are the counters we're going to put back, later. */ 1486 newcounters = malloc(counterlen); 1487 if (!newcounters) { 1488 free(repl->counters); 1489 free(repl); 1490 errno = ENOMEM; 1491 return 0; 1492 } 1493 1494 strcpy(repl->name, (*handle)->info.name); 1495 repl->num_entries = (*handle)->new_number; 1496 repl->size = (*handle)->entries.size; 1497 memcpy(repl->hook_entry, (*handle)->info.hook_entry, 1498 sizeof(repl->hook_entry)); 1499 memcpy(repl->underflow, (*handle)->info.underflow, 1500 sizeof(repl->underflow)); 1501 repl->num_counters = (*handle)->info.num_entries; 1502 repl->valid_hooks = (*handle)->info.valid_hooks; 1503 memcpy(repl->entries, (*handle)->entries.entrytable, 1504 (*handle)->entries.size); 1505 1506 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, 1507 sizeof(*repl) + (*handle)->entries.size) < 0) { 1508 free(repl->counters); 1509 free(repl); 1510 free(newcounters); 1511 return 0; 1512 } 1513 1514 /* Put counters back. */ 1515 strcpy(newcounters->name, (*handle)->info.name); 1516 newcounters->num_counters = (*handle)->new_number; 1517 for (i = 0; i < (*handle)->new_number; i++) { 1518 unsigned int mappos = (*handle)->counter_map[i].mappos; 1519 switch ((*handle)->counter_map[i].maptype) { 1520 case COUNTER_MAP_NOMAP: 1521 newcounters->counters[i] 1522 = ((STRUCT_COUNTERS){ 0, 0 }); 1523 break; 1524 1525 case COUNTER_MAP_NORMAL_MAP: 1526 /* Original read: X. 1527 * Atomic read on replacement: X + Y. 1528 * Currently in kernel: Z. 1529 * Want in kernel: X + Y + Z. 1530 * => Add in X + Y 1531 * => Add in replacement read. 1532 */ 1533 newcounters->counters[i] = repl->counters[mappos]; 1534 break; 1535 1536 case COUNTER_MAP_ZEROED: 1537 /* Original read: X. 1538 * Atomic read on replacement: X + Y. 1539 * Currently in kernel: Z. 1540 * Want in kernel: Y + Z. 1541 * => Add in Y. 1542 * => Add in (replacement read - original read). 1543 */ 1544 subtract_counters(&newcounters->counters[i], 1545 &repl->counters[mappos], 1546 &index2entry(*handle, i)->counters); 1547 break; 1548 } 1549 } 1550 1551 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, 1552 newcounters, counterlen) < 0) { 1553 free(repl->counters); 1554 free(repl); 1555 free(newcounters); 1556 return 0; 1557 } 1558 1559 free(repl->counters); 1560 free(repl); 1561 free(newcounters); 1562 1563 finished: 1564 if ((*handle)->cache_chain_heads) 1565 free((*handle)->cache_chain_heads); 1566 free(*handle); 1567 *handle = NULL; 1568 return 1; 1569} 1570 1571/* Get raw socket. */ 1572int 1573TC_GET_RAW_SOCKET() 1574{ 1575 return sockfd; 1576} 1577 1578/* Translates errno numbers into more human-readable form than strerror. */ 1579const char * 1580TC_STRERROR(int err) 1581{ 1582 unsigned int i; 1583 struct table_struct { 1584 void *fn; 1585 int err; 1586 const char *message; 1587 } table [] = 1588 { { NULL, 0, "Incompatible with this kernel" }, 1589 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 1590 { NULL, ENOSYS, "Will be implemented real soon. I promise." }, 1591 { NULL, ENOMEM, "Memory allocation problem" }, 1592 { TC_INIT, EPERM, "Permission denied (you must be root)" }, 1593 { TC_INIT, EINVAL, "Module is wrong version" }, 1594 { TC_INIT, ENOENT, "Table does not exist (do you need to insmod?)" }, 1595 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, 1596 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, 1597 { TC_DELETE_CHAIN, EMLINK, 1598 "Can't delete chain with references left" }, 1599 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, 1600 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, 1601 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, 1602 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, 1603 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, 1604 { TC_INSERT_ENTRY, EINVAL, "Target problem" }, 1605 /* EINVAL for CHECK probably means bad interface. */ 1606 { TC_CHECK_PACKET, EINVAL, 1607 "Bad arguments (does that interface exist?)" }, 1608 /* ENOENT for DELETE probably means no matching rule */ 1609 { TC_DELETE_ENTRY, ENOENT, 1610 "Bad rule (does a matching rule exist in that chain?)" }, 1611 { TC_SET_POLICY, ENOENT, 1612 "Bad built-in chain name" }, 1613 { TC_SET_POLICY, EINVAL, 1614 "Bad policy name" }, 1615 { NULL, ENOENT, "No chain/target/match by that name" } 1616 }; 1617 1618 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 1619 if ((!table[i].fn || table[i].fn == iptc_fn) 1620 && table[i].err == err) 1621 return table[i].message; 1622 } 1623 1624 return strerror(err); 1625} 1626