libiptc.c revision 733e54b8250576d6a1e0ab5621ef5b144abdf018
1/* Library which manipulates firewall rules. Version $Revision: 1.56 $ */ 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 (!(old = iptcc_get_rule_num(c, rulenum + 1))) { 1323 errno = E2BIG; 1324 return 0; 1325 } 1326 1327 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1328 errno = ENOMEM; 1329 return 0; 1330 } 1331 1332 memcpy(r->entry, e, e->next_offset); 1333 r->counter_map.maptype = COUNTER_MAP_SET; 1334 1335 if (!iptcc_map_target(*handle, r)) { 1336 free(r); 1337 return 0; 1338 } 1339 1340 list_add(&r->list, &old->list); 1341 iptcc_delete_rule(old); 1342 1343 set_changed(*handle); 1344 1345 return 1; 1346} 1347 1348/* Append entry `fw' to chain `chain'. Equivalent to insert with 1349 rulenum = length of chain. */ 1350int 1351TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, 1352 const STRUCT_ENTRY *e, 1353 TC_HANDLE_T *handle) 1354{ 1355 struct chain_head *c; 1356 struct rule_head *r; 1357 1358 iptc_fn = TC_APPEND_ENTRY; 1359 if (!(c = iptcc_find_label(chain, *handle))) { 1360 DEBUGP("unable to find chain `%s'\n", chain); 1361 errno = ENOENT; 1362 return 0; 1363 } 1364 1365 if (!(r = iptcc_alloc_rule(c, e->next_offset))) { 1366 DEBUGP("unable to allocate rule for chain `%s'\n", chain); 1367 errno = ENOMEM; 1368 return 0; 1369 } 1370 1371 memcpy(r->entry, e, e->next_offset); 1372 r->counter_map.maptype = COUNTER_MAP_SET; 1373 1374 if (!iptcc_map_target(*handle, r)) { 1375 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1376 free(r); 1377 return 0; 1378 } 1379 1380 list_add_tail(&r->list, &c->rules); 1381 c->num_rules++; 1382 1383 set_changed(*handle); 1384 1385 return 1; 1386} 1387 1388static inline int 1389match_different(const STRUCT_ENTRY_MATCH *a, 1390 const unsigned char *a_elems, 1391 const unsigned char *b_elems, 1392 unsigned char **maskptr) 1393{ 1394 const STRUCT_ENTRY_MATCH *b; 1395 unsigned int i; 1396 1397 /* Offset of b is the same as a. */ 1398 b = (void *)b_elems + ((unsigned char *)a - a_elems); 1399 1400 if (a->u.match_size != b->u.match_size) 1401 return 1; 1402 1403 if (strcmp(a->u.user.name, b->u.user.name) != 0) 1404 return 1; 1405 1406 *maskptr += ALIGN(sizeof(*a)); 1407 1408 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++) 1409 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) 1410 return 1; 1411 *maskptr += i; 1412 return 0; 1413} 1414 1415static inline int 1416target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask) 1417{ 1418 unsigned int i; 1419 STRUCT_ENTRY_TARGET *ta, *tb; 1420 1421 if (a->type != b->type) 1422 return 0; 1423 1424 ta = GET_TARGET(a->entry); 1425 tb = GET_TARGET(b->entry); 1426 1427 switch (a->type) { 1428 case IPTCC_R_FALLTHROUGH: 1429 return 1; 1430 case IPTCC_R_JUMP: 1431 return a->jump == b->jump; 1432 case IPTCC_R_STANDARD: 1433 return ((STRUCT_STANDARD_TARGET *)ta)->verdict 1434 == ((STRUCT_STANDARD_TARGET *)tb)->verdict; 1435 case IPTCC_R_MODULE: 1436 if (ta->u.target_size != tb->u.target_size) 1437 return 0; 1438 if (strcmp(ta->u.user.name, tb->u.user.name) != 0) 1439 return 0; 1440 1441 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++) 1442 if (((ta->data[i] ^ ta->data[i]) & mask[i]) != 0) 1443 return 0; 1444 return 1; 1445 default: 1446 fprintf(stderr, "ERROR: bad type %i\n", a->type); 1447 abort(); 1448 } 1449} 1450 1451static unsigned char * 1452is_same(const STRUCT_ENTRY *a, 1453 const STRUCT_ENTRY *b, 1454 unsigned char *matchmask); 1455 1456/* Delete the first rule in `chain' which matches `fw'. */ 1457int 1458TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, 1459 const STRUCT_ENTRY *origfw, 1460 unsigned char *matchmask, 1461 TC_HANDLE_T *handle) 1462{ 1463 struct chain_head *c; 1464 struct rule_head *r, *i; 1465 1466 iptc_fn = TC_DELETE_ENTRY; 1467 if (!(c = iptcc_find_label(chain, *handle))) { 1468 errno = ENOENT; 1469 return 0; 1470 } 1471 1472 /* Create a rule_head from origfw. */ 1473 r = iptcc_alloc_rule(c, origfw->next_offset); 1474 if (!r) { 1475 errno = ENOMEM; 1476 return 0; 1477 } 1478 1479 memcpy(r->entry, origfw, origfw->next_offset); 1480 r->counter_map.maptype = COUNTER_MAP_NOMAP; 1481 if (!iptcc_map_target(*handle, r)) { 1482 DEBUGP("unable to map target of rule for chain `%s'\n", chain); 1483 free(r); 1484 return 0; 1485 } 1486 1487 list_for_each_entry(i, &c->rules, list) { 1488 unsigned char *mask; 1489 1490 mask = is_same(r->entry, i->entry, matchmask); 1491 if (!mask) 1492 continue; 1493 1494 if (!target_same(r, i, mask)) 1495 continue; 1496 1497 /* If we are about to delete the rule that is the 1498 * current iterator, move rule iterator back. next 1499 * pointer will then point to real next node */ 1500 if (i == (*handle)->rule_iterator_cur) { 1501 (*handle)->rule_iterator_cur = 1502 list_entry((*handle)->rule_iterator_cur->list.prev, 1503 struct rule_head, list); 1504 } 1505 1506 c->num_rules--; 1507 iptcc_delete_rule(i); 1508 1509 set_changed(*handle); 1510 free(r); 1511 return 1; 1512 } 1513 1514 free(r); 1515 errno = ENOENT; 1516 return 0; 1517} 1518 1519 1520/* Delete the rule in position `rulenum' in `chain'. */ 1521int 1522TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, 1523 unsigned int rulenum, 1524 TC_HANDLE_T *handle) 1525{ 1526 struct chain_head *c; 1527 struct rule_head *r; 1528 1529 iptc_fn = TC_DELETE_NUM_ENTRY; 1530 1531 if (!(c = iptcc_find_label(chain, *handle))) { 1532 errno = ENOENT; 1533 return 0; 1534 } 1535 1536 if (rulenum >= c->num_rules) { 1537 errno = E2BIG; 1538 return 0; 1539 } 1540 1541 /* Take advantage of the double linked list if possible. */ 1542 if (rulenum + 1 <= c->num_rules/2) { 1543 r = iptcc_get_rule_num(c, rulenum + 1); 1544 } else { 1545 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum); 1546 } 1547 1548 /* If we are about to delete the rule that is the current 1549 * iterator, move rule iterator back. next pointer will then 1550 * point to real next node */ 1551 if (r == (*handle)->rule_iterator_cur) { 1552 (*handle)->rule_iterator_cur = 1553 list_entry((*handle)->rule_iterator_cur->list.prev, 1554 struct rule_head, list); 1555 } 1556 1557 c->num_rules--; 1558 iptcc_delete_rule(r); 1559 1560 set_changed(*handle); 1561 1562 return 1; 1563} 1564 1565/* Check the packet `fw' on chain `chain'. Returns the verdict, or 1566 NULL and sets errno. */ 1567const char * 1568TC_CHECK_PACKET(const IPT_CHAINLABEL chain, 1569 STRUCT_ENTRY *entry, 1570 TC_HANDLE_T *handle) 1571{ 1572 errno = ENOSYS; 1573 return NULL; 1574} 1575 1576/* Flushes the entries in the given chain (ie. empties chain). */ 1577int 1578TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1579{ 1580 struct chain_head *c; 1581 struct rule_head *r, *tmp; 1582 1583 iptc_fn = TC_FLUSH_ENTRIES; 1584 if (!(c = iptcc_find_label(chain, *handle))) { 1585 errno = ENOENT; 1586 return 0; 1587 } 1588 1589 list_for_each_entry_safe(r, tmp, &c->rules, list) { 1590 iptcc_delete_rule(r); 1591 } 1592 1593 c->num_rules = 0; 1594 1595 set_changed(*handle); 1596 1597 return 1; 1598} 1599 1600/* Zeroes the counters in a chain. */ 1601int 1602TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1603{ 1604 struct chain_head *c; 1605 struct rule_head *r; 1606 1607 if (!(c = iptcc_find_label(chain, *handle))) { 1608 errno = ENOENT; 1609 return 0; 1610 } 1611 1612 list_for_each_entry(r, &c->rules, list) { 1613 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 1614 r->counter_map.maptype = COUNTER_MAP_ZEROED; 1615 } 1616 1617 set_changed(*handle); 1618 1619 return 1; 1620} 1621 1622STRUCT_COUNTERS * 1623TC_READ_COUNTER(const IPT_CHAINLABEL chain, 1624 unsigned int rulenum, 1625 TC_HANDLE_T *handle) 1626{ 1627 struct chain_head *c; 1628 struct rule_head *r; 1629 1630 iptc_fn = TC_READ_COUNTER; 1631 CHECK(*handle); 1632 1633 if (!(c = iptcc_find_label(chain, *handle))) { 1634 errno = ENOENT; 1635 return NULL; 1636 } 1637 1638 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1639 errno = E2BIG; 1640 return NULL; 1641 } 1642 1643 return &r->entry[0].counters; 1644} 1645 1646int 1647TC_ZERO_COUNTER(const IPT_CHAINLABEL chain, 1648 unsigned int rulenum, 1649 TC_HANDLE_T *handle) 1650{ 1651 struct chain_head *c; 1652 struct rule_head *r; 1653 1654 iptc_fn = TC_ZERO_COUNTER; 1655 CHECK(*handle); 1656 1657 if (!(c = iptcc_find_label(chain, *handle))) { 1658 errno = ENOENT; 1659 return 0; 1660 } 1661 1662 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1663 errno = E2BIG; 1664 return 0; 1665 } 1666 1667 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) 1668 r->counter_map.maptype = COUNTER_MAP_ZEROED; 1669 1670 set_changed(*handle); 1671 1672 return 1; 1673} 1674 1675int 1676TC_SET_COUNTER(const IPT_CHAINLABEL chain, 1677 unsigned int rulenum, 1678 STRUCT_COUNTERS *counters, 1679 TC_HANDLE_T *handle) 1680{ 1681 struct chain_head *c; 1682 struct rule_head *r; 1683 STRUCT_ENTRY *e; 1684 1685 iptc_fn = TC_SET_COUNTER; 1686 CHECK(*handle); 1687 1688 if (!(c = iptcc_find_label(chain, *handle))) { 1689 errno = ENOENT; 1690 return 0; 1691 } 1692 1693 if (!(r = iptcc_get_rule_num(c, rulenum))) { 1694 errno = E2BIG; 1695 return 0; 1696 } 1697 1698 e = r->entry; 1699 r->counter_map.maptype = COUNTER_MAP_SET; 1700 1701 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); 1702 1703 set_changed(*handle); 1704 1705 return 1; 1706} 1707 1708/* Creates a new chain. */ 1709/* To create a chain, create two rules: error node and unconditional 1710 * return. */ 1711int 1712TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1713{ 1714 static struct chain_head *c; 1715 1716 iptc_fn = TC_CREATE_CHAIN; 1717 1718 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1719 QUEUE, RETURN. */ 1720 if (iptcc_find_label(chain, *handle) 1721 || strcmp(chain, LABEL_DROP) == 0 1722 || strcmp(chain, LABEL_ACCEPT) == 0 1723 || strcmp(chain, LABEL_QUEUE) == 0 1724 || strcmp(chain, LABEL_RETURN) == 0) { 1725 DEBUGP("Chain `%s' already exists\n", chain); 1726 errno = EEXIST; 1727 return 0; 1728 } 1729 1730 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { 1731 DEBUGP("Chain name `%s' too long\n", chain); 1732 errno = EINVAL; 1733 return 0; 1734 } 1735 1736 c = iptcc_alloc_chain_head(chain, 0); 1737 if (!c) { 1738 DEBUGP("Cannot allocate memory for chain `%s'\n", chain); 1739 errno = ENOMEM; 1740 return 0; 1741 1742 } 1743 1744 DEBUGP("Creating chain `%s'\n", chain); 1745 list_add_tail(&c->list, &(*handle)->chains); 1746 1747 set_changed(*handle); 1748 1749 return 1; 1750} 1751 1752/* Get the number of references to this chain. */ 1753int 1754TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, 1755 TC_HANDLE_T *handle) 1756{ 1757 struct chain_head *c; 1758 1759 if (!(c = iptcc_find_label(chain, *handle))) { 1760 errno = ENOENT; 1761 return 0; 1762 } 1763 1764 *ref = c->references; 1765 1766 return 1; 1767} 1768 1769/* Deletes a chain. */ 1770int 1771TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 1772{ 1773 unsigned int references; 1774 struct chain_head *c; 1775 1776 iptc_fn = TC_DELETE_CHAIN; 1777 1778 if (!(c = iptcc_find_label(chain, *handle))) { 1779 DEBUGP("cannot find chain `%s'\n", chain); 1780 errno = ENOENT; 1781 return 0; 1782 } 1783 1784 if (TC_BUILTIN(chain, *handle)) { 1785 DEBUGP("cannot remove builtin chain `%s'\n", chain); 1786 errno = EINVAL; 1787 return 0; 1788 } 1789 1790 if (!TC_GET_REFERENCES(&references, chain, handle)) { 1791 DEBUGP("cannot get references on chain `%s'\n", chain); 1792 return 0; 1793 } 1794 1795 if (references > 0) { 1796 DEBUGP("chain `%s' still has references\n", chain); 1797 errno = EMLINK; 1798 return 0; 1799 } 1800 1801 if (c->num_rules) { 1802 DEBUGP("chain `%s' is not empty\n", chain); 1803 errno = ENOTEMPTY; 1804 return 0; 1805 } 1806 1807 /* If we are about to delete the chain that is the current 1808 * iterator, move chain iterator firward. */ 1809 if (c == (*handle)->chain_iterator_cur) 1810 iptcc_chain_iterator_advance(*handle); 1811 1812 list_del(&c->list); 1813 free(c); 1814 1815 DEBUGP("chain `%s' deleted\n", chain); 1816 1817 set_changed(*handle); 1818 1819 return 1; 1820} 1821 1822/* Renames a chain. */ 1823int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, 1824 const IPT_CHAINLABEL newname, 1825 TC_HANDLE_T *handle) 1826{ 1827 struct chain_head *c; 1828 iptc_fn = TC_RENAME_CHAIN; 1829 1830 /* find_label doesn't cover built-in targets: DROP, ACCEPT, 1831 QUEUE, RETURN. */ 1832 if (iptcc_find_label(newname, *handle) 1833 || strcmp(newname, LABEL_DROP) == 0 1834 || strcmp(newname, LABEL_ACCEPT) == 0 1835 || strcmp(newname, LABEL_QUEUE) == 0 1836 || strcmp(newname, LABEL_RETURN) == 0) { 1837 errno = EEXIST; 1838 return 0; 1839 } 1840 1841 if (!(c = iptcc_find_label(oldname, *handle)) 1842 || TC_BUILTIN(oldname, *handle)) { 1843 errno = ENOENT; 1844 return 0; 1845 } 1846 1847 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) { 1848 errno = EINVAL; 1849 return 0; 1850 } 1851 1852 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL)); 1853 1854 set_changed(*handle); 1855 1856 return 1; 1857} 1858 1859/* Sets the policy on a built-in chain. */ 1860int 1861TC_SET_POLICY(const IPT_CHAINLABEL chain, 1862 const IPT_CHAINLABEL policy, 1863 STRUCT_COUNTERS *counters, 1864 TC_HANDLE_T *handle) 1865{ 1866 struct chain_head *c; 1867 1868 iptc_fn = TC_SET_POLICY; 1869 1870 if (!(c = iptcc_find_label(chain, *handle))) { 1871 DEBUGP("cannot find chain `%s'\n", chain); 1872 errno = ENOENT; 1873 return 0; 1874 } 1875 1876 if (!iptcc_is_builtin(c)) { 1877 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain); 1878 errno = ENOENT; 1879 return 0; 1880 } 1881 1882 if (strcmp(policy, LABEL_ACCEPT) == 0) 1883 c->verdict = -NF_ACCEPT - 1; 1884 else if (strcmp(policy, LABEL_DROP) == 0) 1885 c->verdict = -NF_DROP - 1; 1886 else { 1887 errno = EINVAL; 1888 return 0; 1889 } 1890 1891 if (counters) { 1892 /* set byte and packet counters */ 1893 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS)); 1894 c->counter_map.maptype = COUNTER_MAP_SET; 1895 } else { 1896 c->counter_map.maptype = COUNTER_MAP_NOMAP; 1897 } 1898 1899 set_changed(*handle); 1900 1901 return 1; 1902} 1903 1904/* Without this, on gcc 2.7.2.3, we get: 1905 libiptc.c: In function `TC_COMMIT': 1906 libiptc.c:833: fixed or forbidden register was spilled. 1907 This may be due to a compiler bug or to impossible asm 1908 statements or clauses. 1909*/ 1910static void 1911subtract_counters(STRUCT_COUNTERS *answer, 1912 const STRUCT_COUNTERS *a, 1913 const STRUCT_COUNTERS *b) 1914{ 1915 answer->pcnt = a->pcnt - b->pcnt; 1916 answer->bcnt = a->bcnt - b->bcnt; 1917} 1918 1919 1920static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, 1921 unsigned int index) 1922{ 1923 newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0}); 1924 DEBUGP_C("NOMAP => zero\n"); 1925} 1926 1927static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters, 1928 STRUCT_REPLACE *repl, 1929 unsigned int index, 1930 unsigned int mappos) 1931{ 1932 /* Original read: X. 1933 * Atomic read on replacement: X + Y. 1934 * Currently in kernel: Z. 1935 * Want in kernel: X + Y + Z. 1936 * => Add in X + Y 1937 * => Add in replacement read. 1938 */ 1939 newcounters->counters[index] = repl->counters[mappos]; 1940 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos); 1941} 1942 1943static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters, 1944 STRUCT_REPLACE *repl, 1945 unsigned int index, 1946 unsigned int mappos, 1947 STRUCT_COUNTERS *counters) 1948{ 1949 /* Original read: X. 1950 * Atomic read on replacement: X + Y. 1951 * Currently in kernel: Z. 1952 * Want in kernel: Y + Z. 1953 * => Add in Y. 1954 * => Add in (replacement read - original read). 1955 */ 1956 subtract_counters(&newcounters->counters[index], 1957 &repl->counters[mappos], 1958 counters); 1959 DEBUGP_C("ZEROED => mappos %u\n", mappos); 1960} 1961 1962static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters, 1963 unsigned int index, 1964 STRUCT_COUNTERS *counters) 1965{ 1966 /* Want to set counter (iptables-restore) */ 1967 1968 memcpy(&newcounters->counters[index], counters, 1969 sizeof(STRUCT_COUNTERS)); 1970 1971 DEBUGP_C("SET\n"); 1972} 1973 1974 1975int 1976TC_COMMIT(TC_HANDLE_T *handle) 1977{ 1978 /* Replace, then map back the counters. */ 1979 STRUCT_REPLACE *repl; 1980 STRUCT_COUNTERS_INFO *newcounters; 1981 struct chain_head *c; 1982 int ret; 1983 size_t counterlen; 1984 int new_number; 1985 unsigned int new_size; 1986 1987 CHECK(*handle); 1988 1989 /* Don't commit if nothing changed. */ 1990 if (!(*handle)->changed) 1991 goto finished; 1992 1993 new_number = iptcc_compile_table_prep(*handle, &new_size); 1994 if (new_number < 0) { 1995 errno = ENOMEM; 1996 return 0; 1997 } 1998 1999 repl = malloc(sizeof(*repl) + new_size); 2000 if (!repl) { 2001 errno = ENOMEM; 2002 return 0; 2003 } 2004 memset(repl, 0, sizeof(*repl) + new_size); 2005 2006#if 0 2007 TC_DUMP_ENTRIES(*handle); 2008#endif 2009 2010 counterlen = sizeof(STRUCT_COUNTERS_INFO) 2011 + sizeof(STRUCT_COUNTERS) * new_number; 2012 2013 /* These are the old counters we will get from kernel */ 2014 repl->counters = malloc(sizeof(STRUCT_COUNTERS) 2015 * (*handle)->info.num_entries); 2016 if (!repl->counters) { 2017 free(repl); 2018 errno = ENOMEM; 2019 return 0; 2020 } 2021 /* These are the counters we're going to put back, later. */ 2022 newcounters = malloc(counterlen); 2023 if (!newcounters) { 2024 free(repl->counters); 2025 free(repl); 2026 errno = ENOMEM; 2027 return 0; 2028 } 2029 memset(newcounters, 0, counterlen); 2030 2031 strcpy(repl->name, (*handle)->info.name); 2032 repl->num_entries = new_number; 2033 repl->size = new_size; 2034 2035 repl->num_counters = (*handle)->info.num_entries; 2036 repl->valid_hooks = (*handle)->info.valid_hooks; 2037 2038 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n", 2039 repl->num_entries, repl->size, repl->num_counters); 2040 2041 ret = iptcc_compile_table(*handle, repl); 2042 if (ret < 0) { 2043 errno = ret; 2044 free(repl->counters); 2045 free(repl); 2046 return 0; 2047 } 2048 2049 2050#ifdef IPTC_DEBUG2 2051 { 2052 int fd = open("/tmp/libiptc-so_set_replace.blob", 2053 O_CREAT|O_WRONLY); 2054 if (fd >= 0) { 2055 write(fd, repl, sizeof(*repl) + repl->size); 2056 close(fd); 2057 } 2058 } 2059#endif 2060 2061 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, 2062 sizeof(*repl) + repl->size) < 0) { 2063 free(repl->counters); 2064 free(repl); 2065 free(newcounters); 2066 return 0; 2067 } 2068 2069 /* Put counters back. */ 2070 strcpy(newcounters->name, (*handle)->info.name); 2071 newcounters->num_counters = new_number; 2072 2073 list_for_each_entry(c, &(*handle)->chains, list) { 2074 struct rule_head *r; 2075 2076 /* Builtin chains have their own counters */ 2077 if (iptcc_is_builtin(c)) { 2078 DEBUGP("counter for chain-index %u: ", c->foot_index); 2079 switch(c->counter_map.maptype) { 2080 case COUNTER_MAP_NOMAP: 2081 counters_nomap(newcounters, c->foot_index); 2082 break; 2083 case COUNTER_MAP_NORMAL_MAP: 2084 counters_normal_map(newcounters, repl, 2085 c->foot_index, 2086 c->counter_map.mappos); 2087 break; 2088 case COUNTER_MAP_ZEROED: 2089 counters_map_zeroed(newcounters, repl, 2090 c->foot_index, 2091 c->counter_map.mappos, 2092 &c->counters); 2093 break; 2094 case COUNTER_MAP_SET: 2095 counters_map_set(newcounters, c->foot_index, 2096 &c->counters); 2097 break; 2098 } 2099 } 2100 2101 list_for_each_entry(r, &c->rules, list) { 2102 DEBUGP("counter for index %u: ", r->index); 2103 switch (r->counter_map.maptype) { 2104 case COUNTER_MAP_NOMAP: 2105 counters_nomap(newcounters, r->index); 2106 break; 2107 2108 case COUNTER_MAP_NORMAL_MAP: 2109 counters_normal_map(newcounters, repl, 2110 r->index, 2111 r->counter_map.mappos); 2112 break; 2113 2114 case COUNTER_MAP_ZEROED: 2115 counters_map_zeroed(newcounters, repl, 2116 r->index, 2117 r->counter_map.mappos, 2118 &r->entry->counters); 2119 break; 2120 2121 case COUNTER_MAP_SET: 2122 counters_map_set(newcounters, r->index, 2123 &r->entry->counters); 2124 break; 2125 } 2126 } 2127 } 2128 2129 2130#ifdef KERNEL_64_USERSPACE_32 2131 { 2132 /* Kernel will think that pointer should be 64-bits, and get 2133 padding. So we accomodate here (assumption: alignment of 2134 `counters' is on 64-bit boundary). */ 2135 u_int64_t *kernptr = (u_int64_t *)&newcounters->counters; 2136 if ((unsigned long)&newcounters->counters % 8 != 0) { 2137 fprintf(stderr, 2138 "counters alignment incorrect! Mail rusty!\n"); 2139 abort(); 2140 } 2141 *kernptr = newcounters->counters; 2142 } 2143#endif /* KERNEL_64_USERSPACE_32 */ 2144 2145#ifdef IPTC_DEBUG2 2146 { 2147 int fd = open("/tmp/libiptc-so_set_add_counters.blob", 2148 O_CREAT|O_WRONLY); 2149 if (fd >= 0) { 2150 write(fd, newcounters, counterlen); 2151 close(fd); 2152 } 2153 } 2154#endif 2155 2156 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS, 2157 newcounters, counterlen) < 0) { 2158 free(repl->counters); 2159 free(repl); 2160 free(newcounters); 2161 return 0; 2162 } 2163 2164 free(repl->counters); 2165 free(repl); 2166 free(newcounters); 2167 2168 finished: 2169 TC_FREE(handle); 2170 return 1; 2171} 2172 2173/* Get raw socket. */ 2174int 2175TC_GET_RAW_SOCKET() 2176{ 2177 return sockfd; 2178} 2179 2180/* Translates errno numbers into more human-readable form than strerror. */ 2181const char * 2182TC_STRERROR(int err) 2183{ 2184 unsigned int i; 2185 struct table_struct { 2186 void *fn; 2187 int err; 2188 const char *message; 2189 } table [] = 2190 { { TC_INIT, EPERM, "Permission denied (you must be root)" }, 2191 { TC_INIT, EINVAL, "Module is wrong version" }, 2192 { TC_INIT, ENOENT, 2193 "Table does not exist (do you need to insmod?)" }, 2194 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" }, 2195 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" }, 2196 { TC_DELETE_CHAIN, EMLINK, 2197 "Can't delete chain with references left" }, 2198 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" }, 2199 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" }, 2200 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" }, 2201 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" }, 2202 { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, 2203 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" }, 2204 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" }, 2205 { TC_INSERT_ENTRY, EINVAL, "Target problem" }, 2206 /* EINVAL for CHECK probably means bad interface. */ 2207 { TC_CHECK_PACKET, EINVAL, 2208 "Bad arguments (does that interface exist?)" }, 2209 { TC_CHECK_PACKET, ENOSYS, 2210 "Checking will most likely never get implemented" }, 2211 /* ENOENT for DELETE probably means no matching rule */ 2212 { TC_DELETE_ENTRY, ENOENT, 2213 "Bad rule (does a matching rule exist in that chain?)" }, 2214 { TC_SET_POLICY, ENOENT, 2215 "Bad built-in chain name" }, 2216 { TC_SET_POLICY, EINVAL, 2217 "Bad policy name" }, 2218 2219 { NULL, 0, "Incompatible with this kernel" }, 2220 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" }, 2221 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" }, 2222 { NULL, ENOMEM, "Memory allocation problem" }, 2223 { NULL, ENOENT, "No chain/target/match by that name" }, 2224 }; 2225 2226 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { 2227 if ((!table[i].fn || table[i].fn == iptc_fn) 2228 && table[i].err == err) 2229 return table[i].message; 2230 } 2231 2232 return strerror(err); 2233} 2234