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