libiptc.c revision daade4452715cbd1feea05d5231c5e38e3b0b98b
1/* Library which manipulates firewall rules. Version $Revision$ */ 2 3/* Architecture of firewall rules is as follows: 4 * 5 * Chains go INPUT, FORWARD, OUTPUT then user chains. 6 * Each user chain starts with an ERROR node. 7 * Every chain ends with an unconditional jump: a RETURN for user chains, 8 * and a POLICY for built-ins. 9 */ 10 11/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See 12 * COPYING for details). 13 * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org> 14 * 15 * 2003-Jun-20: Harald Welte <laforge@netfilter.org>: 16 * - Reimplementation of chain cache to use offsets instead of entries 17 * 2003-Jun-23: Harald Welte <laforge@netfilter.org>: 18 * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/) 19 * don't rebuild the chain cache after every operation, instead fix it 20 * up after a ruleset change. 21 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>: 22 * - futher performance work: total reimplementation of libiptc. 23 * - libiptc now has a real internal (linked-list) represntation of the 24 * ruleset and a parser/compiler from/to this internal representation 25 * - again sponsored by Astaro AG (http://www.astaro.com/) 26 */ 27#include <sys/types.h> 28#include <sys/socket.h> 29 30#include "linux_list.h" 31 32//#define IPTC_DEBUG2 1 33 34#ifdef IPTC_DEBUG2 35#include <fcntl.h> 36#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args) 37#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args) 38#else 39#define DEBUGP(x, args...) 40#define DEBUGP_C(x, args...) 41#endif 42 43#ifndef IPT_LIB_DIR 44#define IPT_LIB_DIR "/usr/local/lib/iptables" 45#endif 46 47static int sockfd = -1; 48static void *iptc_fn = NULL; 49 50static const char *hooknames[] 51= { [HOOK_PRE_ROUTING] "PREROUTING", 52 [HOOK_LOCAL_IN] "INPUT", 53 [HOOK_FORWARD] "FORWARD", 54 [HOOK_LOCAL_OUT] "OUTPUT", 55 [HOOK_POST_ROUTING] "POSTROUTING", 56#ifdef HOOK_DROPPING 57 [HOOK_DROPPING] "DROPPING" 58#endif 59}; 60 61/* Convenience structures */ 62struct ipt_error_target 63{ 64 STRUCT_ENTRY_TARGET t; 65 char error[TABLE_MAXNAMELEN]; 66}; 67 68struct chain_head; 69struct rule_head; 70 71struct counter_map 72{ 73 enum { 74 COUNTER_MAP_NOMAP, 75 COUNTER_MAP_NORMAL_MAP, 76 COUNTER_MAP_ZEROED, 77 COUNTER_MAP_SET 78 } maptype; 79 unsigned int mappos; 80}; 81 82enum iptcc_rule_type { 83 IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */ 84 IPTCC_R_MODULE, /* extension module (SNAT, ...) */ 85 IPTCC_R_FALLTHROUGH, /* fallthrough rule */ 86 IPTCC_R_JUMP, /* jump to other chain */ 87}; 88 89struct rule_head 90{ 91 struct list_head list; 92 struct chain_head *chain; 93 struct counter_map counter_map; 94 95 unsigned int index; /* index (needed for counter_map) */ 96 unsigned int offset; /* offset in rule blob */ 97 98 enum iptcc_rule_type type; 99 struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */ 100 101 unsigned int size; /* size of entry data */ 102 STRUCT_ENTRY entry[0]; 103}; 104 105struct chain_head 106{ 107 struct list_head list; 108 char name[TABLE_MAXNAMELEN]; 109 unsigned int hooknum; /* hook number+1 if builtin */ 110 unsigned int references; /* how many jumps reference us */ 111 int verdict; /* verdict if builtin */ 112 113 STRUCT_COUNTERS counters; /* per-chain counters */ 114 struct counter_map counter_map; 115 116 unsigned int num_rules; /* number of rules in list */ 117 struct list_head rules; /* list of rules */ 118 119 unsigned int index; /* index (needed for jump resolval) */ 120 unsigned int head_offset; /* offset in rule blob */ 121 unsigned int foot_index; /* index (needed for counter_map) */ 122 unsigned int foot_offset; /* offset in rule blob */ 123}; 124 125STRUCT_TC_HANDLE 126{ 127 int changed; /* Have changes been made? */ 128 129 struct list_head chains; 130 131 struct chain_head *chain_iterator_cur; 132 struct rule_head *rule_iterator_cur; 133 134 STRUCT_GETINFO info; 135 STRUCT_GET_ENTRIES *entries; 136}; 137 138/* allocate a new chain head for the cache */ 139static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum) 140{ 141 struct chain_head *c = malloc(sizeof(*c)); 142 if (!c) 143 return NULL; 144 memset(c, 0, sizeof(*c)); 145 146 strncpy(c->name, name, TABLE_MAXNAMELEN); 147 c->hooknum = hooknum; 148 INIT_LIST_HEAD(&c->rules); 149 150 return c; 151} 152 153/* allocate and initialize a new rule for the cache */ 154static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size) 155{ 156 struct rule_head *r = malloc(sizeof(*r)+size); 157 if (!r) 158 return NULL; 159 memset(r, 0, sizeof(*r)); 160 161 r->chain = c; 162 r->size = size; 163 164 return r; 165} 166 167/* notify us that the ruleset has been modified by the user */ 168static void 169set_changed(TC_HANDLE_T h) 170{ 171 h->changed = 1; 172} 173 174#ifdef IPTC_DEBUG 175static void do_check(TC_HANDLE_T h, unsigned int line); 176#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0) 177#else 178#define CHECK(h) 179#endif 180 181 182/********************************************************************** 183 * iptc blob utility functions (iptcb_*) 184 **********************************************************************/ 185 186static inline int 187iptcb_get_number(const STRUCT_ENTRY *i, 188 const STRUCT_ENTRY *seek, 189 unsigned int *pos) 190{ 191 if (i == seek) 192 return 1; 193 (*pos)++; 194 return 0; 195} 196 197static inline int 198iptcb_get_entry_n(STRUCT_ENTRY *i, 199 unsigned int number, 200 unsigned int *pos, 201 STRUCT_ENTRY **pe) 202{ 203 if (*pos == number) { 204 *pe = i; 205 return 1; 206 } 207 (*pos)++; 208 return 0; 209} 210 211static inline STRUCT_ENTRY * 212iptcb_get_entry(TC_HANDLE_T h, unsigned int offset) 213{ 214 return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset); 215} 216 217static unsigned int 218iptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek) 219{ 220 unsigned int pos = 0; 221 222 if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size, 223 iptcb_get_number, seek, &pos) == 0) { 224 fprintf(stderr, "ERROR: offset %u not an entry!\n", 225 (unsigned int)((char *)seek - (char *)h->entries->entrytable)); 226 abort(); 227 } 228 return pos; 229} 230 231static inline STRUCT_ENTRY * 232iptcb_offset2entry(TC_HANDLE_T h, unsigned int offset) 233{ 234 return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset); 235} 236 237 238static inline unsigned long 239iptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) 240{ 241 return (void *)e - (void *)h->entries->entrytable; 242} 243 244static inline unsigned int 245iptcb_offset2index(const TC_HANDLE_T h, unsigned int offset) 246{ 247 return iptcb_entry2index(h, iptcb_offset2entry(h, offset)); 248} 249 250/* Returns 0 if not hook entry, else hooknumber + 1 */ 251static inline unsigned int 252iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) 253{ 254 unsigned int i; 255 256 for (i = 0; i < NUMHOOKS; i++) { 257 if ((h->info.valid_hooks & (1 << i)) 258 && iptcb_get_entry(h, h->info.hook_entry[i]) == e) 259 return i+1; 260 } 261 return 0; 262} 263 264 265/********************************************************************** 266 * iptc cache utility functions (iptcc_*) 267 **********************************************************************/ 268 269/* Is the given chain builtin (1) or user-defined (0) */ 270static unsigned int iptcc_is_builtin(struct chain_head *c) 271{ 272 return (c->hooknum ? 1 : 0); 273} 274 275/* Get a specific rule within a chain */ 276static struct rule_head *iptcc_get_rule_num(struct chain_head *c, 277 unsigned int rulenum) 278{ 279 struct rule_head *r; 280 unsigned int num = 0; 281 282 list_for_each_entry(r, &c->rules, list) { 283 num++; 284 if (num == rulenum) 285 return r; 286 } 287 return NULL; 288} 289 290/* Get a specific rule within a chain backwards */ 291static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c, 292 unsigned int rulenum) 293{ 294 struct rule_head *r; 295 unsigned int num = 0; 296 297 list_for_each_entry_reverse(r, &c->rules, list) { 298 num++; 299 if (num == rulenum) 300 return r; 301 } 302 return NULL; 303} 304 305/* Returns chain head if found, otherwise NULL. */ 306static struct chain_head * 307iptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset) 308{ 309 struct list_head *pos; 310 311 if (list_empty(&handle->chains)) 312 return NULL; 313 314 list_for_each(pos, &handle->chains) { 315 struct chain_head *c = list_entry(pos, struct chain_head, list); 316 if (offset >= c->head_offset && offset <= c->foot_offset) 317 return c; 318 } 319 320 return NULL; 321} 322/* Returns chain head if found, otherwise NULL. */ 323static struct chain_head * 324iptcc_find_label(const char *name, TC_HANDLE_T handle) 325{ 326 struct list_head *pos; 327 328 if (list_empty(&handle->chains)) 329 return NULL; 330 331 list_for_each(pos, &handle->chains) { 332 struct chain_head *c = list_entry(pos, struct chain_head, list); 333 if (!strcmp(c->name, name)) 334 return c; 335 } 336 337 return NULL; 338} 339 340/* called when rule is to be removed from cache */ 341static void iptcc_delete_rule(struct rule_head *r) 342{ 343 DEBUGP("deleting rule %p (offset %u)\n", r, r->offset); 344 /* clean up reference count of called chain */ 345 if (r->type == IPTCC_R_JUMP 346 && r->jump) 347 r->jump->references--; 348 349 list_del(&r->list); 350 free(r); 351} 352 353 354/********************************************************************** 355 * RULESET PARSER (blob -> cache) 356 **********************************************************************/ 357 358static int alphasort(const void *a, const void *b) 359{ 360 return strcmp(((struct chain_head *)a)->name, 361 ((struct chain_head *)b)->name); 362} 363 364/* Delete policy rule of previous chain, since cache doesn't contain 365 * chain policy rules. 366 * WARNING: This function has ugly design and relies on a lot of context, only 367 * to be called from specific places within the parser */ 368static int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num) 369{ 370 if (h->chain_iterator_cur) { 371 /* policy rule is last rule */ 372 struct rule_head *pr = (struct rule_head *) 373 h->chain_iterator_cur->rules.prev; 374 375 /* save verdict */ 376 h->chain_iterator_cur->verdict = 377 *(int *)GET_TARGET(pr->entry)->data; 378 379 /* save counter and counter_map information */ 380 h->chain_iterator_cur->counter_map.maptype = 381 COUNTER_MAP_NORMAL_MAP; 382 h->chain_iterator_cur->counter_map.mappos = num-1; 383 memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters, 384 sizeof(h->chain_iterator_cur->counters)); 385 386 /* foot_offset points to verdict rule */ 387 h->chain_iterator_cur->foot_index = num; 388 h->chain_iterator_cur->foot_offset = pr->offset; 389 390 /* delete rule from cache */ 391 iptcc_delete_rule(pr); 392 h->chain_iterator_cur->num_rules--; 393 394 return 1; 395 } 396 return 0; 397} 398 399/* Another ugly helper function split out of cache_add_entry to make it less 400 * spaghetti code */ 401static void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c, 402 unsigned int offset, unsigned int *num) 403{ 404 __iptcc_p_del_policy(h, *num); 405 406 c->head_offset = offset; 407 c->index = *num; 408 409 list_add_tail(&c->list, &h->chains); 410 h->chain_iterator_cur = c; 411} 412 413/* main parser function: add an entry from the blob to the cache */ 414static int cache_add_entry(STRUCT_ENTRY *e, 415 TC_HANDLE_T h, 416 STRUCT_ENTRY **prev, 417 unsigned int *num) 418{ 419 unsigned int builtin; 420 unsigned int offset = (char *)e - (char *)h->entries->entrytable; 421 422 DEBUGP("entering..."); 423 424 /* Last entry ("policy rule"). End it.*/ 425 if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) { 426 /* This is the ERROR node at the end of the chain */ 427 DEBUGP_C("%u:%u: end of table:\n", *num, offset); 428 429 __iptcc_p_del_policy(h, *num); 430 431 h->chain_iterator_cur = NULL; 432 goto out_inc; 433 } 434 435 /* We know this is the start of a new chain if it's an ERROR 436 * target, or a hook entry point */ 437 438 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) { 439 struct chain_head *c = 440 iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0); 441 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset, 442 (char *)c->name, c); 443 if (!c) { 444 errno = -ENOMEM; 445 return -1; 446 } 447 448 __iptcc_p_add_chain(h, c, offset, num); 449 450 } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) { 451 struct chain_head *c = 452 iptcc_alloc_chain_head((char *)hooknames[builtin-1], 453 builtin); 454 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n", 455 *num, offset, c, &c->rules); 456 if (!c) { 457 errno = -ENOMEM; 458 return -1; 459 } 460 461 c->hooknum = builtin; 462 463 __iptcc_p_add_chain(h, c, offset, num); 464 465 /* FIXME: this is ugly. */ 466 goto new_rule; 467 } else { 468 /* has to be normal rule */ 469 struct rule_head *r; 470new_rule: 471 472 if (!(r = iptcc_alloc_rule(h->chain_iterator_cur, 473 e->next_offset))) { 474 errno = ENOMEM; 475 return -1; 476 } 477 DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r); 478 479 r->index = *num; 480 r->offset = offset; 481 memcpy(r->entry, e, e->next_offset); 482 r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP; 483 r->counter_map.mappos = r->index; 484 485 /* handling of jumps, etc. */ 486 if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) { 487 STRUCT_STANDARD_TARGET *t; 488 489 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 490 if (t->target.u.target_size 491 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { 492 errno = EINVAL; 493 return -1; 494 } 495 496 if (t->verdict < 0) { 497 DEBUGP_C("standard, verdict=%d\n", t->verdict); 498 r->type = IPTCC_R_STANDARD; 499 } else if (t->verdict == r->offset+e->next_offset) { 500 DEBUGP_C("fallthrough\n"); 501 r->type = IPTCC_R_FALLTHROUGH; 502 } else { 503 DEBUGP_C("jump, target=%u\n", t->verdict); 504 r->type = IPTCC_R_JUMP; 505 /* Jump target fixup has to be deferred 506 * until second pass, since we migh not 507 * yet have parsed the target */ 508 } 509 } else { 510 DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name); 511 r->type = IPTCC_R_MODULE; 512 } 513 514 list_add_tail(&r->list, &h->chain_iterator_cur->rules); 515 h->chain_iterator_cur->num_rules++; 516 } 517out_inc: 518 (*num)++; 519 return 0; 520} 521 522 523/* parse an iptables blob into it's pieces */ 524static int parse_table(TC_HANDLE_T h) 525{ 526 STRUCT_ENTRY *prev; 527 unsigned int num = 0; 528 struct chain_head *c; 529 530 /* First pass: over ruleset blob */ 531 ENTRY_ITERATE(h->entries->entrytable, h->entries->size, 532 cache_add_entry, h, &prev, &num); 533 534 /* Second pass: fixup parsed data from first pass */ 535 list_for_each_entry(c, &h->chains, list) { 536 struct rule_head *r; 537 list_for_each_entry(r, &c->rules, list) { 538 struct chain_head *c; 539 STRUCT_STANDARD_TARGET *t; 540 541 if (r->type != IPTCC_R_JUMP) 542 continue; 543 544 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 545 c = iptcc_find_chain_by_offset(h, t->verdict); 546 if (!c) 547 return -1; 548 r->jump = c; 549 c->references++; 550 } 551 } 552 553 /* FIXME: sort chains */ 554 555 return 1; 556} 557 558 559/********************************************************************** 560 * RULESET COMPILATION (cache -> blob) 561 **********************************************************************/ 562 563/* Convenience structures */ 564struct iptcb_chain_start{ 565 STRUCT_ENTRY e; 566 struct ipt_error_target name; 567}; 568#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \ 569 ALIGN(sizeof(struct ipt_error_target))) 570 571struct iptcb_chain_foot { 572 STRUCT_ENTRY e; 573 STRUCT_STANDARD_TARGET target; 574}; 575#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \ 576 ALIGN(sizeof(STRUCT_STANDARD_TARGET))) 577 578struct iptcb_chain_error { 579 STRUCT_ENTRY entry; 580 struct ipt_error_target target; 581}; 582#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \ 583 ALIGN(sizeof(struct ipt_error_target))) 584 585 586 587/* compile rule from cache into blob */ 588static inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r) 589{ 590 /* handle jumps */ 591 if (r->type == IPTCC_R_JUMP) { 592 STRUCT_STANDARD_TARGET *t; 593 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 594 /* memset for memcmp convenience on delete/replace */ 595 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); 596 strcpy(t->target.u.user.name, STANDARD_TARGET); 597 /* Jumps can only happen to builtin chains, so we 598 * can safely assume that they always have a header */ 599 t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE; 600 } else if (r->type == IPTCC_R_FALLTHROUGH) { 601 STRUCT_STANDARD_TARGET *t; 602 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry); 603 t->verdict = r->offset + r->size; 604 } 605 606 /* copy entry from cache to blob */ 607 memcpy((char *)repl->entries+r->offset, r->entry, r->size); 608 609 return 1; 610} 611 612/* compile chain from cache into blob */ 613static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c) 614{ 615 int ret; 616 struct rule_head *r; 617 struct iptcb_chain_start *head; 618 struct iptcb_chain_foot *foot; 619 620 /* only user-defined chains have heaer */ 621 if (!iptcc_is_builtin(c)) { 622 /* put chain header in place */ 623 head = (void *)repl->entries + c->head_offset; 624 head->e.target_offset = sizeof(STRUCT_ENTRY); 625 head->e.next_offset = IPTCB_CHAIN_START_SIZE; 626 strcpy(head->name.t.u.user.name, ERROR_TARGET); 627 head->name.t.u.target_size = 628 ALIGN(sizeof(struct ipt_error_target)); 629 strcpy(head->name.error, c->name); 630 } else { 631 repl->hook_entry[c->hooknum-1] = c->head_offset; 632 repl->underflow[c->hooknum-1] = c->foot_offset; 633 } 634 635 /* iterate over rules */ 636 list_for_each_entry(r, &c->rules, list) { 637 ret = iptcc_compile_rule(h, repl, r); 638 if (ret < 0) 639 return ret; 640 } 641 642 /* put chain footer in place */ 643 foot = (void *)repl->entries + c->foot_offset; 644 foot->e.target_offset = sizeof(STRUCT_ENTRY); 645 foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE; 646 strcpy(foot->target.target.u.user.name, STANDARD_TARGET); 647 foot->target.target.u.target_size = 648 ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 649 /* builtin targets have verdict, others return */ 650 if (iptcc_is_builtin(c)) 651 foot->target.verdict = c->verdict; 652 else 653 foot->target.verdict = RETURN; 654 /* set policy-counters */ 655 memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS)); 656 657 return 0; 658} 659 660/* calculate offset and number for every rule in the cache */ 661static int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c, 662 int *offset, int *num) 663{ 664 struct rule_head *r; 665 666 c->head_offset = *offset; 667 DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset); 668 669 if (!iptcc_is_builtin(c)) { 670 /* Chain has header */ 671 *offset += sizeof(STRUCT_ENTRY) 672 + ALIGN(sizeof(struct ipt_error_target)); 673 (*num)++; 674 } 675 676 list_for_each_entry(r, &c->rules, list) { 677 DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num); 678 r->offset = *offset; 679 r->index = *num; 680 *offset += r->size; 681 (*num)++; 682 } 683 684 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num, 685 *offset, *num); 686 c->foot_offset = *offset; 687 c->foot_index = *num; 688 *offset += sizeof(STRUCT_ENTRY) 689 + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); 690 (*num)++; 691 692 return 1; 693} 694 695/* put the pieces back together again */ 696static int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size) 697{ 698 struct chain_head *c; 699 unsigned int offset = 0, num = 0; 700 int ret = 0; 701 702 /* First pass: calculate offset for every rule */ 703 list_for_each_entry(c, &h->chains, list) { 704 ret = iptcc_compile_chain_offsets(h, c, &offset, &num); 705 if (ret < 0) 706 return ret; 707 } 708 709 /* Append one error rule at end of chain */ 710 num++; 711 offset += sizeof(STRUCT_ENTRY) 712 + ALIGN(sizeof(struct ipt_error_target)); 713 714 /* ruleset size is now in offset */ 715 *size = offset; 716 return num; 717} 718 719static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl) 720{ 721 struct chain_head *c; 722 struct iptcb_chain_error *error; 723 724 /* Second pass: copy from cache to offsets, fill in jumps */ 725 list_for_each_entry(c, &h->chains, list) { 726 int ret = iptcc_compile_chain(h, repl, c); 727 if (ret < 0) 728 return ret; 729 } 730 731 /* Append error rule at end of chain */ 732 error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE; 733 error->entry.target_offset = sizeof(STRUCT_ENTRY); 734 error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE; 735 error->target.t.u.user.target_size = 736 ALIGN(sizeof(struct ipt_error_target)); 737 strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET); 738 strcpy((char *)&error->target.error, "ERROR"); 739 740 return 1; 741} 742 743/********************************************************************** 744 * EXTERNAL API (operates on cache only) 745 **********************************************************************/ 746 747/* Allocate handle of given size */ 748static TC_HANDLE_T 749alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) 750{ 751 size_t len; 752 TC_HANDLE_T h; 753 754 len = sizeof(STRUCT_TC_HANDLE) + size; 755 756 h = malloc(sizeof(STRUCT_TC_HANDLE)); 757 if (!h) { 758 errno = ENOMEM; 759 return NULL; 760 } 761 memset(h, 0, sizeof(*h)); 762 INIT_LIST_HEAD(&h->chains); 763 strcpy(h->info.name, tablename); 764 765 h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size); 766 if (!h->entries) 767 goto out_free_handle; 768 769 strcpy(h->entries->name, tablename); 770 h->entries->size = size; 771 772 return h; 773 774out_free_handle: 775 free(h); 776 777 return NULL; 778} 779 780 781TC_HANDLE_T 782TC_INIT(const char *tablename) 783{ 784 TC_HANDLE_T h; 785 STRUCT_GETINFO info; 786 int tmp; 787 socklen_t s; 788 789 iptc_fn = TC_INIT; 790 791 if (sockfd != -1) { 792 close(sockfd); 793 sockfd = -1; 794 } 795 796 if (strlen(tablename) >= TABLE_MAXNAMELEN) { 797 errno = EINVAL; 798 return NULL; 799 } 800 801 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW); 802 if (sockfd < 0) 803 return NULL; 804 805 s = sizeof(info); 806 807 strcpy(info.name, tablename); 808 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) 809 return NULL; 810 811 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n", 812 info.valid_hooks, info.num_entries, info.size); 813 814 if ((h = alloc_handle(info.name, info.size, info.num_entries)) 815 == NULL) { 816 close(sockfd); 817 sockfd = -1; 818 return NULL; 819 } 820 821 /* Initialize current state */ 822 h->info = info; 823 824 h->entries->size = h->info.size; 825 826 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; 827 828 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries, 829 &tmp) < 0) 830 goto error; 831 832#ifdef IPTC_DEBUG2 833 { 834 int fd = open("/tmp/libiptc-so_get_entries.blob", 835 O_CREAT|O_WRONLY); 836 if (fd >= 0) { 837 write(fd, h->entries, tmp); 838 close(fd); 839 } 840 } 841#endif 842 843 if (parse_table(h) < 0) 844 goto error; 845 846 CHECK(h); 847 return h; 848error: 849 TC_FREE(&h); 850 return NULL; 851} 852 853void 854TC_FREE(TC_HANDLE_T *h) 855{ 856 struct chain_head *c, *tmp; 857 858 close(sockfd); 859 sockfd = -1; 860 861 list_for_each_entry_safe(c, tmp, &(*h)->chains, list) { 862 struct rule_head *r, *rtmp; 863 864 list_for_each_entry_safe(r, rtmp, &c->rules, list) { 865 free(r); 866 } 867 868 free(c); 869 } 870 871 free((*h)->entries); 872 free(*h); 873 874 *h = NULL; 875} 876 877static inline int 878print_match(const STRUCT_ENTRY_MATCH *m) 879{ 880 printf("Match name: `%s'\n", m->u.user.name); 881 return 0; 882} 883 884static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); 885 886void 887TC_DUMP_ENTRIES(const TC_HANDLE_T handle) 888{ 889 CHECK(handle); 890#if 0 891 printf("libiptc v%s. %u bytes.\n", 892 IPTABLES_VERSION, handle->entries->size); 893 printf("Table `%s'\n", handle->info.name); 894 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 895 handle->info.hook_entry[HOOK_PRE_ROUTING], 896 handle->info.hook_entry[HOOK_LOCAL_IN], 897 handle->info.hook_entry[HOOK_FORWARD], 898 handle->info.hook_entry[HOOK_LOCAL_OUT], 899 handle->info.hook_entry[HOOK_POST_ROUTING]); 900 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n", 901 handle->info.underflow[HOOK_PRE_ROUTING], 902 handle->info.underflow[HOOK_LOCAL_IN], 903 handle->info.underflow[HOOK_FORWARD], 904 handle->info.underflow[HOOK_LOCAL_OUT], 905 handle->info.underflow[HOOK_POST_ROUTING]); 906 907 ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size, 908 dump_entry, handle); 909#endif 910} 911 912/* Does this chain exist? */ 913int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) 914{ 915 return iptcc_find_label(chain, handle) != NULL; 916} 917 918static void iptcc_chain_iterator_advance(TC_HANDLE_T handle) 919{ 920 struct chain_head *c = handle->chain_iterator_cur; 921 922 if (c->list.next == &handle->chains) 923 handle->chain_iterator_cur = NULL; 924 else 925 handle->chain_iterator_cur = 926 list_entry(c->list.next, struct chain_head, list); 927} 928 929/* Iterator functions to run through the chains. */ 930const char * 931TC_FIRST_CHAIN(TC_HANDLE_T *handle) 932{ 933 struct chain_head *c = list_entry((*handle)->chains.next, 934 struct chain_head, list); 935 936 iptc_fn = TC_FIRST_CHAIN; 937 938 939 if (list_empty(&(*handle)->chains)) { 940 DEBUGP(": no chains\n"); 941 return NULL; 942 } 943 944 (*handle)->chain_iterator_cur = c; 945 iptcc_chain_iterator_advance(*handle); 946 947 DEBUGP(": returning `%s'\n", c->name); 948 return c->name; 949} 950 951/* Iterator functions to run through the chains. Returns NULL at end. */ 952const char * 953TC_NEXT_CHAIN(TC_HANDLE_T *handle) 954{ 955 struct chain_head *c = (*handle)->chain_iterator_cur; 956 957 iptc_fn = TC_NEXT_CHAIN; 958 959 if (!c) { 960 DEBUGP(": no more chains\n"); 961 return NULL; 962 } 963 964 iptcc_chain_iterator_advance(*handle); 965 966 DEBUGP(": returning `%s'\n", c->name); 967 return c->name; 968} 969 970/* Get first rule in the given chain: NULL for empty chain. */ 971const STRUCT_ENTRY * 972TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) 973{ 974 struct chain_head *c; 975 struct rule_head *r; 976 977 iptc_fn = TC_FIRST_RULE; 978 979 DEBUGP("first rule(%s): ", chain); 980 981 c = iptcc_find_label(chain, *handle); 982 if (!c) { 983 errno = ENOENT; 984 return NULL; 985 } 986 987 /* Empty chain: single return/policy rule */ 988 if (list_empty(&c->rules)) { 989 DEBUGP_C("no rules, returning NULL\n"); 990 return NULL; 991 } 992 993 r = list_entry(c->rules.next, struct rule_head, list); 994 (*handle)->rule_iterator_cur = r; 995 DEBUGP_C("%p\n", r); 996 997 return r->entry; 998} 999 1000/* Returns NULL when rules run out. */ 1001const STRUCT_ENTRY * 1002TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) 1003{ 1004 struct rule_head *r; 1005 1006 DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur); 1007 1008 if (!(*handle)->rule_iterator_cur) { 1009 DEBUGP_C("returning NULL\n"); 1010 return NULL; 1011 } 1012 1013 r = list_entry((*handle)->rule_iterator_cur->list.next, 1014 struct rule_head, list); 1015 1016 iptc_fn = TC_NEXT_RULE; 1017 1018 DEBUGP_C("next=%p, head=%p...", &r->list, 1019 &(*handle)->rule_iterator_cur->chain->rules); 1020 1021 if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) { 1022 (*handle)->rule_iterator_cur = NULL; 1023 DEBUGP_C("finished, returning NULL\n"); 1024 return NULL; 1025 } 1026 1027 (*handle)->rule_iterator_cur = r; 1028 1029 /* NOTE: prev is without any influence ! */ 1030 DEBUGP_C("returning rule %p\n", r); 1031 return r->entry; 1032} 1033 1034/* How many rules in this chain? */ 1035unsigned int 1036TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) 1037{ 1038 struct chain_head *c; 1039 iptc_fn = TC_NUM_RULES; 1040 CHECK(*handle); 1041 1042 c = iptcc_find_label(chain, *handle); 1043 if (!c) { 1044 errno = ENOENT; 1045 return (unsigned int)-1; 1046 } 1047 1048 return c->num_rules; 1049} 1050 1051const STRUCT_ENTRY *TC_GET_RULE(const char *chain, 1052 unsigned int n, 1053 TC_HANDLE_T *handle) 1054{ 1055 struct chain_head *c; 1056 struct rule_head *r; 1057 1058 iptc_fn = TC_GET_RULE; 1059 1060 CHECK(*handle); 1061 1062 c = iptcc_find_label(chain, *handle); 1063 if (!c) { 1064 errno = ENOENT; 1065 return NULL; 1066 } 1067 1068 r = iptcc_get_rule_num(c, n); 1069 if (!r) 1070 return NULL; 1071 return r->entry; 1072} 1073 1074/* Returns a pointer to the target name of this position. */ 1075const char *standard_target_map(int verdict) 1076{ 1077 switch (verdict) { 1078 case RETURN: 1079 return LABEL_RETURN; 1080 break; 1081 case -NF_ACCEPT-1: 1082 return LABEL_ACCEPT; 1083 break; 1084 case -NF_DROP-1: 1085 return LABEL_DROP; 1086 break; 1087 case -NF_QUEUE-1: 1088 return LABEL_QUEUE; 1089 break; 1090 default: 1091 fprintf(stderr, "ERROR: %d not a valid target)\n", 1092 verdict); 1093 abort(); 1094 break; 1095 } 1096 /* not reached */ 1097 return NULL; 1098} 1099 1100/* Returns a pointer to the target name of this position. */ 1101const char *TC_GET_TARGET(const STRUCT_ENTRY *ce, 1102 TC_HANDLE_T *handle) 1103{ 1104 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; 1105 struct rule_head *r = container_of(e, struct rule_head, entry[0]); 1106 1107 iptc_fn = TC_GET_TARGET; 1108 1109 switch(r->type) { 1110 int spos; 1111 case IPTCC_R_FALLTHROUGH: 1112 return ""; 1113 break; 1114 case IPTCC_R_JUMP: 1115 DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name); 1116 return r->jump->name; 1117 break; 1118 case IPTCC_R_STANDARD: 1119 spos = *(int *)GET_TARGET(e)->data; 1120 DEBUGP("r=%p, spos=%d'\n", r, spos); 1121 return standard_target_map(spos); 1122 break; 1123 case IPTCC_R_MODULE: 1124 return GET_TARGET(e)->u.user.name; 1125 break; 1126 } 1127 return NULL; 1128} 1129/* Is this a built-in chain? Actually returns hook + 1. */ 1130int 1131TC_BUILTIN(const char *chain, const TC_HANDLE_T handle) 1132{ 1133 struct chain_head *c; 1134 1135 iptc_fn = TC_BUILTIN; 1136 1137 c = iptcc_find_label(chain, handle); 1138 if (!c) { 1139 errno = ENOENT; 1140 return 0; 1141 } 1142 1143 return iptcc_is_builtin(c); 1144} 1145 1146/* Get the policy of a given built-in chain */ 1147const char * 1148TC_GET_POLICY(const char *chain, 1149 STRUCT_COUNTERS *counters, 1150 TC_HANDLE_T *handle) 1151{ 1152 struct chain_head *c; 1153 1154 iptc_fn = TC_GET_POLICY; 1155 1156 DEBUGP("called for chain %s\n", chain); 1157 1158 c = iptcc_find_label(chain, *handle); 1159 if (!c) { 1160 errno = ENOENT; 1161 return NULL; 1162 } 1163 1164 if (!iptcc_is_builtin(c)) 1165 return NULL; 1166 1167 *counters = c->counters; 1168 1169 return standard_target_map(c->verdict); 1170} 1171 1172static int 1173iptcc_standard_map(struct rule_head *r, int verdict) 1174{ 1175 STRUCT_ENTRY *e = r->entry; 1176 STRUCT_STANDARD_TARGET *t; 1177 1178 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); 1179 1180 if (t->target.u.target_size 1181 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) { 1182 errno = EINVAL; 1183 return 0; 1184 } 1185 /* memset for memcmp convenience on delete/replace */ 1186 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN); 1187 strcpy(t->target.u.user.name, STANDARD_TARGET); 1188 t->verdict = verdict; 1189 1190 r->type = IPTCC_R_STANDARD; 1191 1192 return 1; 1193} 1194 1195static int 1196iptcc_map_target(const TC_HANDLE_T handle, 1197 struct rule_head *r) 1198{ 1199 STRUCT_ENTRY *e = r->entry; 1200 STRUCT_ENTRY_TARGET *t = GET_TARGET(e); 1201 1202 /* Maybe it's empty (=> fall through) */ 1203 if (strcmp(t->u.user.name, "") == 0) { 1204 r->type = IPTCC_R_FALLTHROUGH; 1205 return 1; 1206 } 1207 /* Maybe it's a standard target name... */ 1208 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0) 1209 return iptcc_standard_map(r, -NF_ACCEPT - 1); 1210 else if (strcmp(t->u.user.name, LABEL_DROP) == 0) 1211 return iptcc_standard_map(r, -NF_DROP - 1); 1212 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0) 1213 return iptcc_standard_map(r, -NF_QUEUE - 1); 1214 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0) 1215 return iptcc_standard_map(r, RETURN); 1216 else if (TC_BUILTIN(t->u.user.name, handle)) { 1217 /* Can't jump to builtins. */ 1218 errno = EINVAL; 1219 return 0; 1220 } else { 1221 /* Maybe it's an existing chain name. */ 1222 struct chain_head *c; 1223 DEBUGP("trying to find chain `%s': ", t->u.user.name); 1224 1225 c = iptcc_find_label(t->u.user.name, handle); 1226 if (c) { 1227 DEBUGP_C("found!\n"); 1228 r->type = IPTCC_R_JUMP; 1229 r->jump = c; 1230 c->references++; 1231 return 1; 1232 } 1233 DEBUGP_C("not found :(\n"); 1234 } 1235 1236 /* Must be a module? If not, kernel will reject... */ 1237 /* memset to all 0 for your memcmp convenience. */ 1238 memset(t->u.user.name + strlen(t->u.user.name), 1239 0, 1240 FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); 1241 r->type = IPTCC_R_MODULE; 1242 set_changed(handle); 1243 return 1; 1244} 1245 1246/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ 1247int 1248TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, 1249 const STRUCT_ENTRY *e, 1250 unsigned int rulenum, 1251 TC_HANDLE_T *handle) 1252{ 1253 struct chain_head *c; 1254 struct rule_head *r; 1255 struct list_head *prev; 1256 1257 iptc_fn = TC_INSERT_ENTRY; 1258 1259 if (!(c = iptcc_find_label(chain, *handle))) { 1260 errno = ENOENT; 1261 return 0; 1262 } 1263 1264 /* first rulenum index = 0 1265 first c->num_rules index = 1 */ 1266 if (rulenum > c->num_rules) { 1267 errno = E2BIG; 1268 return 0; 1269 } 1270 1271 /* If we are inserting at the end just take advantage of the 1272 double linked list, insert will happen before the entry 1273 prev points to. */ 1274 if (rulenum == c->num_rules) { 1275 prev = &c->rules; 1276 } else if (rulenum + 1 <= c->num_rules/2) { 1277 r = iptcc_get_rule_num(c, rulenum + 1); 1278 prev = &r->list; 1279 } else { 1280 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1281 prev = &r->list; 1282 } 1283 1284 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1285 errno = ENOMEM; 1286 return 0; 1287 } 1288 1289 memcpy(r->entry, e, e->next_offset); 1290 r->counter_map.maptype = COUNTER_MAP_SET; 1291 1292 if (!iptcc_map_target(*handle, r)) { 1293 free(r); 1294 return 0; 1295 } 1296 1297 list_add_tail(&r->list, prev); 1298 c->num_rules++; 1299 1300 set_changed(*handle); 1301 1302 return 1; 1303} 1304 1305/* Atomically replace rule `rulenum' in `chain' with `fw'. */ 1306int 1307TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, 1308 const STRUCT_ENTRY *e, 1309 unsigned int rulenum, 1310 TC_HANDLE_T *handle) 1311{ 1312 struct chain_head *c; 1313 struct rule_head *r, *old; 1314 1315 iptc_fn = TC_REPLACE_ENTRY; 1316 1317 if (!(c = iptcc_find_label(chain, *handle))) { 1318 errno = ENOENT; 1319 return 0; 1320 } 1321 1322 if (rulenum >= c->num_rules) { 1323 errno = E2BIG; 1324 return 0; 1325 } 1326 1327 /* Take advantage of the double linked list if possible. */ 1328 if (rulenum + 1 <= c->num_rules/2) { 1329 old = iptcc_get_rule_num(c, rulenum + 1); 1330 } else { 1331 old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1332 } 1333 1334 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1335 errno = ENOMEM; 1336 return 0; 1337 } 1338 1339 memcpy(r->entry, e, e->next_offset); 1340 r->counter_map.maptype = COUNTER_MAP_SET; 1341 1342 if (!iptcc_map_target(*handle, r)) { 1343 free(r); 1344 return 0; 1345 } 1346 1347 list_add(&r->list, &old->list); 1348 iptcc_delete_rule(old); 1349 1350 set_changed(*handle); 1351 1352 return 1; 1353} 1354 1355/* Append entry `fw' to chain `chain'. Equivalent to insert with 1356 rulenum = length of chain. */ 1357int 1358TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, 1359 const STRUCT_ENTRY *e, 1360 TC_HANDLE_T *handle) 1361{ 1362 struct chain_head *c; 1363 struct rule_head *r; 1364 1365 iptc_fn = TC_APPEND_ENTRY; 1366 if (!(c = iptcc_find_label(chain, *handle))) { 1367 DEBUGP("unable to find chain `%s'\n", chain); 1368 errno = ENOENT; 1369 return 0; 1370 } 1371 1372 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1373 DEBUGP("unable to allocate rule for chain `%s'\n", chain); 1374 errno = ENOMEM; 1375 return 0; 1376 } 1377 1378 memcpy(r->entry, e, e->next_offset); 1379 r->counter_map.maptype = COUNTER_MAP_SET; 1380 1381 if (!iptcc_map_target(*handle, r)) { 1382 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1383 free(r); 1384 return 0; 1385 } 1386 1387 list_add_tail(&r->list, &c->rules); 1388 c->num_rules++; 1389 1390 set_changed(*handle); 1391 1392 return 1; 1393} 1394 1395static inline int 1396match_different(const STRUCT_ENTRY_MATCH *a, 1397 const unsigned char *a_elems, 1398 const unsigned char *b_elems, 1399 unsigned char **maskptr) 1400{ 1401 const STRUCT_ENTRY_MATCH *b; 1402 unsigned int i; 1403 1404 /* Offset of b is the same as a. */ 1405 b = (void *)b_elems + ((unsigned char *)a - a_elems); 1406 1407 if (a->u.match_size != b->u.match_size) 1408 return 1; 1409 1410 if (strcmp(a->u.user.name, b->u.user.name) != 0) 1411 return 1; 1412 1413 *maskptr += ALIGN(sizeof(*a)); 1414 1415 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) 1416 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) 1417 return 1; 1418 *maskptr += i; 1419 return 0; 1420} 1421 1422static inline int 1423target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask) 1424{ 1425 unsigned int i; 1426 STRUCT_ENTRY_TARGET *ta, *tb; 1427 1428 if (a->type != b->type) 1429 return 0; 1430 1431 ta = GET_TARGET(a->entry); 1432 tb = GET_TARGET(b->entry); 1433 1434 switch (a->type) { 1435 case IPTCC_R_FALLTHROUGH: 1436 return 1; 1437 case IPTCC_R_JUMP: 1438 return a->jump == b->jump; 1439 case IPTCC_R_STANDARD: 1440 return ((STRUCT_STANDARD_TARGET *)ta)->verdict 1441 == ((STRUCT_STANDARD_TARGET *)tb)->verdict; 1442 case IPTCC_R_MODULE: 1443 if (ta->u.target_size != tb->u.target_size) 1444 return 0; 1445 if (strcmp(ta->u.user.name, tb->u.user.name) != 0) 1446 return 0; 1447 1448 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++) 1449 if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0) 1450 return 0; 1451 return 1; 1452 default: 1453 fprintf(stderr, "ERROR: bad type %i\n", a->type); 1454 abort(); 1455 } 1456} 1457 1458static unsigned char * 1459is_same(const STRUCT_ENTRY *a, 1460 const STRUCT_ENTRY *b, 1461 unsigned char *matchmask); 1462 1463/* Delete the first rule in `chain' which matches `fw'. */ 1464int 1465TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, 1466 const STRUCT_ENTRY *origfw, 1467 unsigned char *matchmask, 1468 TC_HANDLE_T *handle) 1469{ 1470 struct chain_head *c; 1471 struct rule_head *r, *i; 1472 1473 iptc_fn = TC_DELETE_ENTRY; 1474 if (!(c = iptcc_find_label(chain, *handle))) { 1475 errno = ENOENT; 1476 return 0; 1477 } 1478 1479 /* Create a rule_head from origfw. */ 1480 r = iptcc_alloc_rule(c, origfw->next_offset); 1481 if (!r) { 1482 errno = ENOMEM; 1483 return 0; 1484 } 1485 1486 memcpy(r->entry, origfw, origfw->next_offset); 1487 r->counter_map.maptype = COUNTER_MAP_NOMAP; 1488 if (!iptcc_map_target(*handle, r)) { 1489 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1490 free(r); 1491 return 0; 1492 } 1493 1494 list_for_each_entry(i, &c->rules, list) { 1495 unsigned char *mask; 1496 1497 mask = is_same(r->entry, i->entry, matchmask); 1498 if (!mask) 1499 continue; 1500 1501 if (!target_same(r, i, mask)) 1502 continue; 1503 1504 /* If we are about to delete the rule that is the 1505 * current iterator, move rule iterator back. next 1506 * pointer will then point to real next node */ 1507 if (i == (*handle)->rule_iterator_cur) { 1508 (*handle)->rule_iterator_cur = 1509 list_entry((*handle)->rule_iterator_cur->list.prev, 1510 struct rule_head, list); 1511 } 1512 1513 c->num_rules--; 1514 iptcc_delete_rule(i); 1515 1516 set_changed(*handle); 1517 free(r); 1518 return 1; 1519 } 1520 1521 free(r); 1522 errno = ENOENT; 1523 return 0; 1524} 1525 1526 1527/* Delete the rule in position `rulenum' in `chain'. */ 1528int 1529TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, 1530 unsigned int rulenum, 1531 TC_HANDLE_T *handle) 1532{ 1533 struct chain_head *c; 1534 struct rule_head *r; 1535 1536 iptc_fn = TC_DELETE_NUM_ENTRY; 1537 1538 if (!(c = iptcc_find_label(chain, *handle))) { 1539 errno = ENOENT; 1540 return 0; 1541 } 1542 1543 if (rulenum >= c->num_rules) { 1544 errno = E2BIG; 1545 return 0; 1546 } 1547 1548 /* Take advantage of the double linked list if possible. */ 1549 if (rulenum + 1 <= c->num_rules/2) { 1550 r = iptcc_get_rule_num(c, rulenum + 1); 1551 } else { 1552 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1553 } 1554 1555 /* If we are about to delete the rule that is the current 1556 * iterator, move rule iterator back. next pointer will then 1557 * point to real next node */ 1558 if (r == (*handle)->rule_iterator_cur) { 1559 (*handle)->rule_iterator_cur = 1560 list_entry((*handle)->rule_iterator_cur->list.prev, 1561 struct rule_head, list); 1562 } 1563 1564 c->num_rules--; 1565 iptcc_delete_rule(r); 1566 1567 set_changed(*handle); 1568 1569 return 1; 1570} 1571 1572/* Check the packet `fw' on chain `chain'. Returns the verdict, or 1573 NULL and sets errno. */ 1574const char * 1575TC_CHECK_PACKET(const IPT_CHAINLABEL chain, 1576 STRUCT_ENTRY *entry, 1577 TC_HANDLE_T *handle) 1578{ 1579 errno = ENOSYS; 1580 return NULL; 1581} 1582 1583/* Flushes the entries in the given chain (ie. empties chain). */ 1584int 1585TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1586{ 1587 struct chain_head *c; 1588 struct rule_head *r, *tmp; 1589 1590 iptc_fn = TC_FLUSH_ENTRIES; 1591 if (!(c = iptcc_find_label(chain, *handle))) { 1592 errno = ENOENT; 1593 return 0; 1594 } 1595 1596 list_for_each_entry_safe(r, tmp, &c->rules, list) { 1597 iptcc_delete_rule(r); 1598 } 1599 1600 c->num_rules = 0; 1601 1602 set_changed(*handle); 1603 1604 return 1; 1605} 1606 1607/* Zeroes the counters in a chain. */ 1608int 1609TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1610{ 1611 struct chain_head *c; 1612 struct rule_head *r; 1613 1614 if (!(c = iptcc_find_label(chain, *handle))) { 1615 errno = ENOENT; 1616 return 0; 1617 } 1618 1619 list_for_each_entry(r, &c->rules, list) { 1620 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 1621 r->counter_map.maptype = COUNTER_MAP_ZEROED; 1622 } 1623 1624 set_changed(*handle); 1625 1626 return 1; 1627} 1628 1629STRUCT_COUNTERS * 1630TC_READ_COUNTER(const IPT_CHAINLABEL chain, 1631 unsigned int rulenum, 1632 TC_HANDLE_T *handle) 1633{ 1634 struct chain_head *c; 1635 struct rule_head *r; 1636 1637 iptc_fn = TC_READ_COUNTER; 1638 CHECK(*handle); 1639 1640 if (!(c = iptcc_find_label(chain, *handle))) { 1641 errno = ENOENT; 1642 return NULL; 1643 } 1644 1645 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1646 errno = E2BIG; 1647 return NULL; 1648 } 1649 1650 return &r->entry[0].counters; 1651} 1652 1653int 1654TC_ZERO_COUNTER(const IPT_CHAINLABEL chain, 1655 unsigned int rulenum, 1656 TC_HANDLE_T *handle) 1657{ 1658 struct chain_head *c; 1659 struct rule_head *r; 1660 1661 iptc_fn = TC_ZERO_COUNTER; 1662 CHECK(*handle); 1663 1664 if (!(c = iptcc_find_label(chain, *handle))) { 1665 errno = ENOENT; 1666 return 0; 1667 } 1668 1669 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1670 errno = E2BIG; 1671 return 0; 1672 } 1673 1674 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 1675 r->counter_map.maptype = COUNTER_MAP_ZEROED; 1676 1677 set_changed(*handle); 1678 1679 return 1; 1680} 1681 1682int 1683TC_SET_COUNTER(const IPT_CHAINLABEL chain, 1684 unsigned int rulenum, 1685 STRUCT_COUNTERS *counters, 1686 TC_HANDLE_T *handle) 1687{ 1688 struct chain_head *c; 1689 struct rule_head *r; 1690 STRUCT_ENTRY *e; 1691 1692 iptc_fn = TC_SET_COUNTER; 1693 CHECK(*handle); 1694 1695 if (!(c = iptcc_find_label(chain, *handle))) { 1696 errno = ENOENT; 1697 return 0; 1698 } 1699 1700 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1701 errno = E2BIG; 1702 return 0; 1703 } 1704 1705 e = r->entry; 1706 r->counter_map.maptype = COUNTER_MAP_SET; 1707 1708 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); 1709 1710 set_changed(*handle); 1711 1712 return 1; 1713} 1714 1715/* Creates a new chain. */ 1716/* To create a chain, create two rules: error node and unconditional 1717 * return. */ 1718int 1719TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1720{ 1721 static struct chain_head *c; 1722 1723 iptc_fn = TC_CREATE_CHAIN; 1724 1725 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1726 QUEUE, RETURN. */ 1727 if (iptcc_find_label(chain, *handle) 1728 || strcmp(chain, LABEL_DROP) == 0 1729 || strcmp(chain, LABEL_ACCEPT) == 0 1730 || strcmp(chain, LABEL_QUEUE) == 0 1731 || strcmp(chain, LABEL_RETURN) == 0) { 1732 DEBUGP("Chain `%s' already exists\n", chain); 1733 errno = EEXIST; 1734 return 0; 1735 } 1736 1737 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { 1738 DEBUGP("Chain name `%s' too long\n", chain); 1739 errno = EINVAL; 1740 return 0; 1741 } 1742 1743 c = iptcc_alloc_chain_head(chain, 0); 1744 if (!c) { 1745 DEBUGP("Cannot allocate memory for chain `%s'\n", chain); 1746 errno = ENOMEM; 1747 return 0; 1748 1749 } 1750 1751 DEBUGP("Creating chain `%s'\n", chain); 1752 list_add_tail(&c->list, &(*handle)->chains); 1753 1754 set_changed(*handle); 1755 1756 return 1; 1757} 1758 1759/* Get the number of references to this chain. */ 1760int 1761TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, 1762 TC_HANDLE_T *handle) 1763{ 1764 struct chain_head *c; 1765 1766 if (!(c = iptcc_find_label(chain, *handle))) { 1767 errno = ENOENT; 1768 return 0; 1769 } 1770 1771 *ref = c->references; 1772 1773 return 1; 1774} 1775 1776/* Deletes a chain. */ 1777int 1778TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1779{ 1780 unsigned int references; 1781 struct chain_head *c; 1782 1783 iptc_fn = TC_DELETE_CHAIN; 1784 1785 if (!(c = iptcc_find_label(chain, *handle))) { 1786 DEBUGP("cannot find chain `%s'\n", chain); 1787 errno = ENOENT; 1788 return 0; 1789 } 1790 1791 if (TC_BUILTIN(chain, *handle)) { 1792 DEBUGP("cannot remove builtin chain `%s'\n", chain); 1793 errno = EINVAL; 1794 return 0; 1795 } 1796 1797 if (!TC_GET_REFERENCES(&references, chain, handle)) { 1798 DEBUGP("cannot get references on chain `%s'\n", chain); 1799 return 0; 1800 } 1801 1802 if (references > 0) { 1803 DEBUGP("chain `%s' still has references\n", chain); 1804 errno = EMLINK; 1805 return 0; 1806 } 1807 1808 if (c->num_rules) { 1809 DEBUGP("chain `%s' is not empty\n", chain); 1810 errno = ENOTEMPTY; 1811 return 0; 1812 } 1813 1814 /* If we are about to delete the chain that is the current 1815 * iterator, move chain iterator firward. */ 1816 if (c == (*handle)->chain_iterator_cur) 1817 iptcc_chain_iterator_advance(*handle); 1818 1819 list_del(&c->list); 1820 free(c); 1821 1822 DEBUGP("chain `%s' deleted\n", chain); 1823 1824 set_changed(*handle); 1825 1826 return 1; 1827} 1828 1829/* Renames a chain. */ 1830int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, 1831 const IPT_CHAINLABEL newname, 1832 TC_HANDLE_T *handle) 1833{ 1834 struct chain_head *c; 1835 iptc_fn = TC_RENAME_CHAIN; 1836 1837 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1838 QUEUE, RETURN. */ 1839 if (iptcc_find_label(newname, *handle) 1840 || strcmp(newname, LABEL_DROP) == 0 1841 || strcmp(newname, LABEL_ACCEPT) == 0 1842 || strcmp(newname, LABEL_QUEUE) == 0 1843 || strcmp(newname, LABEL_RETURN) == 0) { 1844 errno = EEXIST; 1845 return 0; 1846 } 1847 1848 if (!(c = iptcc_find_label(oldname, *handle)) 1849 || TC_BUILTIN(oldname, *handle)) { 1850 errno = ENOENT; 1851 return 0; 1852 } 1853 1854 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { 1855 errno = EINVAL; 1856 return 0; 1857 } 1858 1859 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL)); 1860 1861 set_changed(*handle); 1862 1863 return 1; 1864} 1865 1866/* Sets the policy on a built-in chain. */ 1867int 1868TC_SET_POLICY(const IPT_CHAINLABEL chain, 1869 const IPT_CHAINLABEL policy, 1870 STRUCT_COUNTERS *counters, 1871 TC_HANDLE_T *handle) 1872{ 1873 struct chain_head *c; 1874 1875 iptc_fn = TC_SET_POLICY; 1876 1877 if (!(c = iptcc_find_label(chain, *handle))) { 1878 DEBUGP("cannot find chain `%s'\n", chain); 1879 errno = ENOENT; 1880 return 0; 1881 } 1882 1883 if (!iptcc_is_builtin(c)) { 1884 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain); 1885 errno = ENOENT; 1886 return 0; 1887 } 1888 1889 if (strcmp(policy, LABEL_ACCEPT) == 0) 1890 c->verdict = -NF_ACCEPT - 1; 1891 else if (strcmp(policy, LABEL_DROP) == 0) 1892 c->verdict = -NF_DROP - 1; 1893 else { 1894 errno = EINVAL; 1895 return 0; 1896 } 1897 1898 if (counters) { 1899 /* set byte and packet counters */ 1900 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS)); 1901 c->counter_map.maptype = COUNTER_MAP_SET; 1902 } else { 1903 c->counter_map.maptype = COUNTER_MAP_NOMAP; 1904 } 1905 1906 set_changed(*handle); 1907 1908 return 1; 1909} 1910 1911/* Without this, on gcc 2.7.2.3, we get: 1912 libiptc.c: In function `TC_COMMIT': 1913 libiptc.c:833: fixed or forbidden register was spilled. 1914 This may be due to a compiler bug or to impossible asm 1915 statements or clauses. 1916*/ 1917static void 1918subtract_counters(STRUCT_COUNTERS *answer, 1919 const STRUCT_COUNTERS *a, 1920 const STRUCT_COUNTERS *b) 1921{ 1922 answer->pcnt = a->pcnt - b->pcnt; 1923 answer->bcnt = a->bcnt - b->bcnt; 1924} 1925 1926 1927static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, 1928 unsigned int index) 1929{ 1930 newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0}); 1931 DEBUGP_C("NOMAP => zero\n"); 1932} 1933 1934static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters, 1935 STRUCT_REPLACE *repl, 1936 unsigned int index, 1937 unsigned int mappos) 1938{ 1939 /* Original read: X. 1940 * Atomic read on replacement: X + Y. 1941 * Currently in kernel: Z. 1942 * Want in kernel: X + Y + Z. 1943 * => Add in X + Y 1944 * => Add in replacement read. 1945 */ 1946 newcounters->counters[index] = repl->counters[mappos]; 1947 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos); 1948} 1949 1950static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters, 1951 STRUCT_REPLACE *repl, 1952 unsigned int index, 1953 unsigned int mappos, 1954 STRUCT_COUNTERS *counters) 1955{ 1956 /* Original read: X. 1957 * Atomic read on replacement: X + Y. 1958 * Currently in kernel: Z. 1959 * Want in kernel: Y + Z. 1960 * => Add in Y. 1961 * => Add in (replacement read - original read). 1962 */ 1963 subtract_counters(&newcounters->counters[index], 1964 &repl->counters[mappos], 1965 counters); 1966 DEBUGP_C("ZEROED => mappos %u\n", mappos); 1967} 1968 1969static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters, 1970 unsigned int index, 1971 STRUCT_COUNTERS *counters) 1972{ 1973 /* Want to set counter (iptables-restore) */ 1974 1975 memcpy(&newcounters->counters[index], counters, 1976 sizeof(STRUCT_COUNTERS)); 1977 1978 DEBUGP_C("SET\n"); 1979} 1980 1981 1982int 1983TC_COMMIT(TC_HANDLE_T *handle) 1984{ 1985 /* Replace, then map back the counters. */ 1986 STRUCT_REPLACE *repl; 1987 STRUCT_COUNTERS_INFO *newcounters; 1988 struct chain_head *c; 1989 int ret; 1990 size_t counterlen; 1991 int new_number; 1992 unsigned int new_size; 1993 1994 CHECK(*handle); 1995 1996 /* Don't commit if nothing changed. */ 1997 if (!(*handle)->changed) 1998 goto finished; 1999 2000 new_number = iptcc_compile_table_prep(*handle, &new_size); 2001 if (new_number < 0) { 2002 errno = ENOMEM; 2003 return 0; 2004 } 2005 2006 repl = malloc(sizeof(*repl) + new_size); 2007 if (!repl) { 2008 errno = ENOMEM; 2009 return 0; 2010 } 2011 memset(repl, 0, sizeof(*repl) + new_size); 2012 2013#if 0 2014 TC_DUMP_ENTRIES(*handle); 2015#endif 2016 2017 counterlen = sizeof(STRUCT_COUNTERS_INFO) 2018 + sizeof(STRUCT_COUNTERS) * new_number; 2019 2020 /* These are the old counters we will get from kernel */ 2021 repl->counters = malloc(sizeof(STRUCT_COUNTERS) 2022 * (*handle)->info.num_entries); 2023 if (!repl->counters) { 2024 free(repl); 2025 errno = ENOMEM; 2026 return 0; 2027 } 2028 /* These are the counters we're going to put back, later. */ 2029 newcounters = malloc(counterlen); 2030 if (!newcounters) { 2031 free(repl->counters); 2032 free(repl); 2033 errno = ENOMEM; 2034 return 0; 2035 } 2036 memset(newcounters, 0, counterlen); 2037 2038 strcpy(repl->name, (*handle)->info.name); 2039 repl->num_entries = new_number; 2040 repl->size = new_size; 2041 2042 repl->num_counters = (*handle)->info.num_entries; 2043 repl->valid_hooks = (*handle)->info.valid_hooks; 2044 2045 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n", 2046 repl->num_entries, repl->size, repl->num_counters); 2047 2048 ret = iptcc_compile_table(*handle, repl); 2049 if (ret < 0) { 2050 errno = ret; 2051 free(repl->counters); 2052 free(repl); 2053 return 0; 2054 } 2055 2056 2057#ifdef IPTC_DEBUG2 2058 { 2059 int fd = open("/tmp/libiptc-so_set_replace.blob", 2060 O_CREAT|O_WRONLY); 2061 if (fd >= 0) { 2062 write(fd, repl, sizeof(*repl) + repl->size); 2063 close(fd); 2064 } 2065 } 2066#endif 2067 2068 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, 2069 sizeof(*repl) + repl->size) < 0) { 2070 free(repl->counters); 2071 free(repl); 2072 free(newcounters); 2073 return 0; 2074 } 2075 2076 /* Put counters back. */ 2077 strcpy(newcounters->name, (*handle)->info.name); 2078 newcounters->num_counters = new_number; 2079 2080 list_for_each_entry(c, &(*handle)->chains, list) { 2081 struct rule_head *r; 2082 2083 /* Builtin chains have their own counters */ 2084 if (iptcc_is_builtin(c)) { 2085 DEBUGP("counter for chain-index %u: ", c->foot_index); 2086 switch(c->counter_map.maptype) { 2087 case COUNTER_MAP_NOMAP: 2088 counters_nomap(newcounters, c->foot_index); 2089 break; 2090 case COUNTER_MAP_NORMAL_MAP: 2091 counters_normal_map(newcounters, repl, 2092 c->foot_index, 2093 c->counter_map.mappos); 2094 break; 2095 case COUNTER_MAP_ZEROED: 2096 counters_map_zeroed(newcounters, repl, 2097 c->foot_index, 2098 c->counter_map.mappos, 2099 &c->counters); 2100 break; 2101 case COUNTER_MAP_SET: 2102 counters_map_set(newcounters, c->foot_index, 2103 &c->counters); 2104 break; 2105 } 2106 } 2107 2108 list_for_each_entry(r, &c->rules, list) { 2109 DEBUGP("counter for index %u: ", r->index); 2110 switch (r->counter_map.maptype) { 2111 case COUNTER_MAP_NOMAP: 2112 counters_nomap(newcounters, r->index); 2113 break; 2114 2115 case COUNTER_MAP_NORMAL_MAP: 2116 counters_normal_map(newcounters, repl, 2117 r->index, 2118 r->counter_map.mappos); 2119 break; 2120 2121 case COUNTER_MAP_ZEROED: 2122 counters_map_zeroed(newcounters, repl, 2123 r->index, 2124 r->counter_map.mappos, 2125 &r->entry->counters); 2126 break; 2127 2128 case COUNTER_MAP_SET: 2129 counters_map_set(newcounters, r->index, 2130 &r->entry->counters); 2131 break; 2132 } 2133 } 2134 } 2135 2136 2137#ifdef KERNEL_64_USERSPACE_32 2138 { 2139 /* Kernel will think that pointer should be 64-bits, and get 2140 padding. So we accomodate here (assumption: alignment of 2141 `counters' is on 64-bit boundary). */ 2142 u_int64_t *kernptr = (u_int64_t *)&newcounters->counters; 2143 if ((unsigned long)&newcounters->counters % 8 != 0) { 2144 fprintf(stderr, 2145 "counters alignment incorrect! Mail rusty!\n"); 2146 abort(); 2147 } 2148 *kernptr = newcounters->counters; 2149 } 2150#endif /* KERNEL_64_USERSPACE_32 */ 2151 2152#ifdef IPTC_DEBUG2 2153 { 2154 int fd = open("/tmp/libiptc-so_set_add_counters.blob", 2155 O_CREAT|O_WRONLY); 2156 if (fd >= 0) { 2157 write(fd, newcounters, counterlen); 2158 close(fd); 2159 } 2160 } 2161#endif 2162 2163 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, 2164 newcounters, counterlen) < 0) { 2165 free(repl->counters); 2166 free(repl); 2167 free(newcounters); 2168 return 0; 2169 } 2170 2171 free(repl->counters); 2172 free(repl); 2173 free(newcounters); 2174 2175 finished: 2176 TC_FREE(handle); 2177 return 1; 2178} 2179 2180/* Get raw socket. */ 2181int 2182TC_GET_RAW_SOCKET() 2183{ 2184 return sockfd; 2185} 2186 2187/* Translates errno numbers into more human-readable form than strerror. */ 2188const char * 2189TC_STRERROR(int err) 2190{ 2191 unsigned int i; 2192 struct table_struct { 2193 void *fn; 2194 int err; 2195 const char *message; 2196 } table [] = 2197 { { TC_INIT, EPERM, "Permission denied (you must be root)" }, 2198 { TC_INIT, EINVAL, "Module is wrong version" }, 2199 { TC_INIT, ENOENT, 2200 "Table does not exist (do you need to insmod?)" }, 2201 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, 2202 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, 2203 { TC_DELETE_CHAIN, EMLINK, 2204 "Can't delete chain with references left" }, 2205 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, 2206 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, 2207 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, 2208 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, 2209 { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, 2210 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, 2211 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, 2212 { TC_INSERT_ENTRY, EINVAL, "Target problem" }, 2213 /* EINVAL for CHECK probably means bad interface. */ 2214 { TC_CHECK_PACKET, EINVAL, 2215 "Bad arguments (does that interface exist?)" }, 2216 { TC_CHECK_PACKET, ENOSYS, 2217 "Checking will most likely never get implemented" }, 2218 /* ENOENT for DELETE probably means no matching rule */ 2219 { TC_DELETE_ENTRY, ENOENT, 2220 "Bad rule (does a matching rule exist in that chain?)" }, 2221 { TC_SET_POLICY, ENOENT, 2222 "Bad built-in chain name" }, 2223 { TC_SET_POLICY, EINVAL, 2224 "Bad policy name" }, 2225 2226 { NULL, 0, "Incompatible with this kernel" }, 2227 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 2228 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, 2229 { NULL, ENOMEM, "Memory allocation problem" }, 2230 { NULL, ENOENT, "No chain/target/match by that name" }, 2231 }; 2232 2233 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 2234 if ((!table[i].fn || table[i].fn == iptc_fn) 2235 && table[i].err == err) 2236 return table[i].message; 2237 } 2238 2239 return strerror(err); 2240} 2241