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