1 /* Library which manipulates firewall rules. Version $Revision$ */
3 /* Architecture of firewall rules is as follows:
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.
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>
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 * - further 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/)
27 * 2008-Jan+Jul: Jesper Dangaard Brouer <hawk@comx.dk>
28 * - performance work: speedup chain list "name" searching.
29 * - performance work: speedup initial ruleset parsing.
30 * - sponsored by ComX Networks A/S (http://www.comx.dk/)
32 #include <sys/types.h>
33 #include <sys/socket.h>
36 #include "linux_list.h"
38 //#define IPTC_DEBUG2 1
42 #define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
43 #define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
45 #define DEBUGP(x, args...)
46 #define DEBUGP_C(x, args...)
50 #define debug(x, args...) fprintf(stderr, x, ## args)
52 #define debug(x, args...)
55 static void *iptc_fn
= NULL
;
57 static const char *hooknames
[] = {
58 [HOOK_PRE_ROUTING
] = "PREROUTING",
59 [HOOK_LOCAL_IN
] = "INPUT",
60 [HOOK_FORWARD
] = "FORWARD",
61 [HOOK_LOCAL_OUT
] = "OUTPUT",
62 [HOOK_POST_ROUTING
] = "POSTROUTING",
64 [HOOK_DROPPING
] = "DROPPING"
68 /* Convenience structures */
69 struct ipt_error_target
71 STRUCT_ENTRY_TARGET t
;
72 char error
[TABLE_MAXNAMELEN
];
82 COUNTER_MAP_NORMAL_MAP
,
89 enum iptcc_rule_type
{
90 IPTCC_R_STANDARD
, /* standard target (ACCEPT, ...) */
91 IPTCC_R_MODULE
, /* extension module (SNAT, ...) */
92 IPTCC_R_FALLTHROUGH
, /* fallthrough rule */
93 IPTCC_R_JUMP
, /* jump to other chain */
98 struct list_head list
;
99 struct chain_head
*chain
;
100 struct counter_map counter_map
;
102 unsigned int index
; /* index (needed for counter_map) */
103 unsigned int offset
; /* offset in rule blob */
105 enum iptcc_rule_type type
;
106 struct chain_head
*jump
; /* jump target, if IPTCC_R_JUMP */
108 unsigned int size
; /* size of entry data */
109 STRUCT_ENTRY entry
[0];
114 struct list_head list
;
115 char name
[TABLE_MAXNAMELEN
];
116 unsigned int hooknum
; /* hook number+1 if builtin */
117 unsigned int references
; /* how many jumps reference us */
118 int verdict
; /* verdict if builtin */
120 STRUCT_COUNTERS counters
; /* per-chain counters */
121 struct counter_map counter_map
;
123 unsigned int num_rules
; /* number of rules in list */
124 struct list_head rules
; /* list of rules */
126 unsigned int index
; /* index (needed for jump resolval) */
127 unsigned int head_offset
; /* offset in rule blob */
128 unsigned int foot_index
; /* index (needed for counter_map) */
129 unsigned int foot_offset
; /* offset in rule blob */
135 int changed
; /* Have changes been made? */
137 struct list_head chains
;
139 struct chain_head
*chain_iterator_cur
;
140 struct rule_head
*rule_iterator_cur
;
142 unsigned int num_chains
; /* number of user defined chains */
144 struct chain_head
**chain_index
; /* array for fast chain list access*/
145 unsigned int chain_index_sz
;/* size of chain index array */
147 int sorted_offsets
; /* if chains are received sorted from kernel,
148 * then the offsets are also sorted. Says if its
149 * possible to bsearch offsets using chain_index.
153 STRUCT_GET_ENTRIES
*entries
;
157 BSEARCH_NAME
, /* Binary search after chain name */
158 BSEARCH_OFFSET
, /* Binary search based on offset */
161 /* allocate a new chain head for the cache */
162 static struct chain_head
*iptcc_alloc_chain_head(const char *name
, int hooknum
)
164 struct chain_head
*c
= malloc(sizeof(*c
));
167 memset(c
, 0, sizeof(*c
));
169 strncpy(c
->name
, name
, TABLE_MAXNAMELEN
);
170 c
->hooknum
= hooknum
;
171 INIT_LIST_HEAD(&c
->rules
);
176 /* allocate and initialize a new rule for the cache */
177 static struct rule_head
*iptcc_alloc_rule(struct chain_head
*c
, unsigned int size
)
179 struct rule_head
*r
= malloc(sizeof(*r
)+size
);
182 memset(r
, 0, sizeof(*r
));
190 /* notify us that the ruleset has been modified by the user */
192 set_changed(struct xtc_handle
*h
)
198 static void do_check(struct xtc_handle
*h
, unsigned int line
);
199 #define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
205 /**********************************************************************
206 * iptc blob utility functions (iptcb_*)
207 **********************************************************************/
210 iptcb_get_number(const STRUCT_ENTRY
*i
,
211 const STRUCT_ENTRY
*seek
,
221 iptcb_get_entry_n(STRUCT_ENTRY
*i
,
226 if (*pos
== number
) {
234 static inline STRUCT_ENTRY
*
235 iptcb_get_entry(struct xtc_handle
*h
, unsigned int offset
)
237 return (STRUCT_ENTRY
*)((char *)h
->entries
->entrytable
+ offset
);
241 iptcb_entry2index(struct xtc_handle
*const h
, const STRUCT_ENTRY
*seek
)
243 unsigned int pos
= 0;
245 if (ENTRY_ITERATE(h
->entries
->entrytable
, h
->entries
->size
,
246 iptcb_get_number
, seek
, &pos
) == 0) {
247 fprintf(stderr
, "ERROR: offset %u not an entry!\n",
248 (unsigned int)((char *)seek
- (char *)h
->entries
->entrytable
));
254 static inline STRUCT_ENTRY
*
255 iptcb_offset2entry(struct xtc_handle
*h
, unsigned int offset
)
257 return (STRUCT_ENTRY
*) ((void *)h
->entries
->entrytable
+offset
);
261 static inline unsigned long
262 iptcb_entry2offset(struct xtc_handle
*const h
, const STRUCT_ENTRY
*e
)
264 return (void *)e
- (void *)h
->entries
->entrytable
;
267 static inline unsigned int
268 iptcb_offset2index(struct xtc_handle
*const h
, unsigned int offset
)
270 return iptcb_entry2index(h
, iptcb_offset2entry(h
, offset
));
273 /* Returns 0 if not hook entry, else hooknumber + 1 */
274 static inline unsigned int
275 iptcb_ent_is_hook_entry(STRUCT_ENTRY
*e
, struct xtc_handle
*h
)
279 for (i
= 0; i
< NUMHOOKS
; i
++) {
280 if ((h
->info
.valid_hooks
& (1 << i
))
281 && iptcb_get_entry(h
, h
->info
.hook_entry
[i
]) == e
)
288 /**********************************************************************
289 * Chain index (cache utility) functions
290 **********************************************************************
291 * The chain index is an array with pointers into the chain list, with
292 * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to
293 * speedup chain list searching, by find a more optimal starting
294 * points when searching the linked list.
296 * The starting point can be found fast by using a binary search of
297 * the chain index. Thus, reducing the previous search complexity of
298 * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN.
300 * A nice property of the chain index, is that the "bucket" list
301 * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will
302 * change this). Oppose to hashing, where the "bucket" list length can
305 #ifndef CHAIN_INDEX_BUCKET_LEN
306 #define CHAIN_INDEX_BUCKET_LEN 40
309 /* Another nice property of the chain index is that inserting/creating
310 * chains in chain list don't change the correctness of the chain
311 * index, it only causes longer lists in the buckets.
313 * To mitigate the performance penalty of longer bucket lists and the
314 * penalty of rebuilding, the chain index is rebuild only when
315 * CHAIN_INDEX_INSERT_MAX chains has been added.
317 #ifndef CHAIN_INDEX_INSERT_MAX
318 #define CHAIN_INDEX_INSERT_MAX 355
321 static inline unsigned int iptcc_is_builtin(struct chain_head
*c
);
323 /* Use binary search in the chain index array, to find a chain_head
324 * pointer closest to the place of the searched name element.
326 * Notes that, binary search (obviously) requires that the chain list
329 * The not so obvious: The chain index array, is actually both sorted
330 * by name and offset, at the same time!. This is only true because,
331 * chain are stored sorted in the kernel (as we pushed it in sorted).
334 static struct list_head
*
335 __iptcc_bsearch_chain_index(const char *name
, unsigned int offset
,
336 unsigned int *idx
, struct xtc_handle
*handle
,
337 enum bsearch_type type
)
339 unsigned int pos
, end
;
342 struct list_head
*list_pos
;
343 list_pos
=&handle
->chains
;
345 /* Check for empty array, e.g. no user defined chains */
346 if (handle
->chain_index_sz
== 0) {
347 debug("WARNING: handle->chain_index_sz == 0\n");
352 end
= handle
->chain_index_sz
;
355 debug("bsearch Find chain:%s (pos:%d end:%d) (offset:%d)\n",
356 name
, pos
, end
, offset
);
360 if (!handle
->chain_index
[pos
]) {
361 fprintf(stderr
, "ERROR: NULL pointer chain_index[%d]\n", pos
);
362 return &handle
->chains
; /* Be safe, return orig start pos */
365 debug("bsearch Index[%d] name:%s ",
366 pos
, handle
->chain_index
[pos
]->name
);
368 /* Support for different compare functions */
371 res
= strcmp(name
, handle
->chain_index
[pos
]->name
);
374 debug("head_offset:[%d] foot_offset:[%d] ",
375 handle
->chain_index
[pos
]->head_offset
,
376 handle
->chain_index
[pos
]->foot_offset
);
377 res
= offset
- handle
->chain_index
[pos
]->head_offset
;
380 fprintf(stderr
, "ERROR: %d not a valid bsearch type\n",
385 debug("res:%d ", res
);
388 list_pos
= &handle
->chain_index
[pos
]->list
;
391 if (res
== 0) { /* Found element, by direct hit */
392 debug("[found] Direct hit pos:%d end:%d\n", pos
, end
);
394 } else if (res
< 0) { /* Too far, jump back */
398 /* Exit case: First element of array */
400 debug("[found] Reached first array elem (end%d)\n",end
);
403 debug("jump back to pos:%d (end:%d)\n", pos
, end
);
405 } else if (res
> 0 ){ /* Not far enough, jump forward */
407 /* Exit case: Last element of array */
408 if (pos
== handle
->chain_index_sz
-1) {
409 debug("[found] Last array elem (end:%d)\n", end
);
413 /* Exit case: Next index less, thus elem in this list section */
416 res
= strcmp(name
, handle
->chain_index
[pos
+1]->name
);
419 res
= offset
- handle
->chain_index
[pos
+1]->head_offset
;
424 debug("[found] closest list (end:%d)\n", end
);
429 debug("jump forward to pos:%d (end:%d)\n", pos
, end
);
436 /* Wrapper for string chain name based bsearch */
437 static struct list_head
*
438 iptcc_bsearch_chain_index(const char *name
, unsigned int *idx
,
439 struct xtc_handle
*handle
)
441 return __iptcc_bsearch_chain_index(name
, 0, idx
, handle
, BSEARCH_NAME
);
445 /* Wrapper for offset chain based bsearch */
446 static struct list_head
*
447 iptcc_bsearch_chain_offset(unsigned int offset
, unsigned int *idx
,
448 struct xtc_handle
*handle
)
450 struct list_head
*pos
;
452 /* If chains were not received sorted from kernel, then the
453 * offset bsearch is not possible.
455 if (!handle
->sorted_offsets
)
456 pos
= handle
->chains
.next
;
458 pos
= __iptcc_bsearch_chain_index(NULL
, offset
, idx
, handle
,
465 /* Trivial linear search of chain index. Function used for verifying
466 the output of bsearch function */
467 static struct list_head
*
468 iptcc_linearly_search_chain_index(const char *name
, struct xtc_handle
*handle
)
473 struct list_head
*list_pos
;
474 list_pos
= &handle
->chains
;
476 if (handle
->chain_index_sz
)
477 list_pos
= &handle
->chain_index
[0]->list
;
479 /* Linearly walk of chain index array */
481 for (i
=0; i
< handle
->chain_index_sz
; i
++) {
482 if (handle
->chain_index
[i
]) {
483 res
= strcmp(handle
->chain_index
[i
]->name
, name
);
485 break; // One step too far
486 list_pos
= &handle
->chain_index
[i
]->list
;
496 static int iptcc_chain_index_alloc(struct xtc_handle
*h
)
498 unsigned int list_length
= CHAIN_INDEX_BUCKET_LEN
;
499 unsigned int array_elems
;
500 unsigned int array_mem
;
502 /* Allocate memory for the chain index array */
503 array_elems
= (h
->num_chains
/ list_length
) +
504 (h
->num_chains
% list_length
? 1 : 0);
505 array_mem
= sizeof(h
->chain_index
) * array_elems
;
507 debug("Alloc Chain index, elems:%d mem:%d bytes\n",
508 array_elems
, array_mem
);
510 h
->chain_index
= malloc(array_mem
);
511 if (h
->chain_index
== NULL
&& array_mem
> 0) {
512 h
->chain_index_sz
= 0;
515 memset(h
->chain_index
, 0, array_mem
);
516 h
->chain_index_sz
= array_elems
;
521 static void iptcc_chain_index_free(struct xtc_handle
*h
)
523 h
->chain_index_sz
= 0;
524 free(h
->chain_index
);
529 static void iptcc_chain_index_dump(struct xtc_handle
*h
)
533 /* Dump: contents of chain index array */
534 for (i
=0; i
< h
->chain_index_sz
; i
++) {
535 if (h
->chain_index
[i
]) {
536 fprintf(stderr
, "Chain index[%d].name: %s\n",
537 i
, h
->chain_index
[i
]->name
);
543 /* Build the chain index */
544 static int iptcc_chain_index_build(struct xtc_handle
*h
)
546 unsigned int list_length
= CHAIN_INDEX_BUCKET_LEN
;
547 unsigned int chains
= 0;
548 unsigned int cindex
= 0;
549 struct chain_head
*c
;
551 /* Build up the chain index array here */
552 debug("Building chain index\n");
554 debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n",
555 h
->num_chains
, list_length
, h
->chain_index_sz
);
557 if (h
->chain_index_sz
== 0)
560 list_for_each_entry(c
, &h
->chains
, list
) {
562 /* Issue: The index array needs to start after the
563 * builtin chains, as they are not sorted */
564 if (!iptcc_is_builtin(c
)) {
565 cindex
=chains
/ list_length
;
567 /* Safe guard, break out on array limit, this
568 * is useful if chains are added and array is
569 * rebuild, without realloc of memory. */
570 if (cindex
>= h
->chain_index_sz
)
573 if ((chains
% list_length
)== 0) {
574 debug("\nIndex[%d] Chains:", cindex
);
575 h
->chain_index
[cindex
] = c
;
579 debug("%s, ", c
->name
);
586 static int iptcc_chain_index_rebuild(struct xtc_handle
*h
)
588 debug("REBUILD chain index array\n");
589 iptcc_chain_index_free(h
);
590 if ((iptcc_chain_index_alloc(h
)) < 0)
592 iptcc_chain_index_build(h
);
596 /* Delete chain (pointer) from index array. Removing an element from
597 * the chain list only affects the chain index array, if the chain
598 * index points-to/uses that list pointer.
600 * There are different strategies, the simple and safe is to rebuild
601 * the chain index every time. The more advanced is to update the
602 * array index to point to the next element, but that requires some
603 * house keeping and boundry checks. The advanced is implemented, as
604 * the simple approach behaves badly when all chains are deleted
605 * because list_for_each processing will always hit the first chain
606 * index, thus causing a rebuild for every chain.
608 static int iptcc_chain_index_delete_chain(struct chain_head
*c
, struct xtc_handle
*h
)
610 struct list_head
*index_ptr
, *index_ptr2
, *next
;
611 struct chain_head
*c2
;
612 unsigned int idx
, idx2
;
614 index_ptr
= iptcc_bsearch_chain_index(c
->name
, &idx
, h
);
616 debug("Del chain[%s] c->list:%p index_ptr:%p\n",
617 c
->name
, &c
->list
, index_ptr
);
619 /* Save the next pointer */
623 if (index_ptr
== &c
->list
) { /* Chain used as index ptr */
625 /* See if its possible to avoid a rebuild, by shifting
626 * to next pointer. Its possible if the next pointer
627 * is located in the same index bucket.
629 c2
= list_entry(next
, struct chain_head
, list
);
630 index_ptr2
= iptcc_bsearch_chain_index(c2
->name
, &idx2
, h
);
633 return iptcc_chain_index_rebuild(h
);
635 /* Avoiding rebuild */
636 debug("Update cindex[%d] with next ptr name:[%s]\n",
638 h
->chain_index
[idx
]=c2
;
646 /**********************************************************************
647 * iptc cache utility functions (iptcc_*)
648 **********************************************************************/
650 /* Is the given chain builtin (1) or user-defined (0) */
651 static inline unsigned int iptcc_is_builtin(struct chain_head
*c
)
653 return (c
->hooknum
? 1 : 0);
656 /* Get a specific rule within a chain */
657 static struct rule_head
*iptcc_get_rule_num(struct chain_head
*c
,
658 unsigned int rulenum
)
661 unsigned int num
= 0;
663 list_for_each_entry(r
, &c
->rules
, list
) {
671 /* Get a specific rule within a chain backwards */
672 static struct rule_head
*iptcc_get_rule_num_reverse(struct chain_head
*c
,
673 unsigned int rulenum
)
676 unsigned int num
= 0;
678 list_for_each_entry_reverse(r
, &c
->rules
, list
) {
686 /* Returns chain head if found, otherwise NULL. */
687 static struct chain_head
*
688 iptcc_find_chain_by_offset(struct xtc_handle
*handle
, unsigned int offset
)
690 struct list_head
*pos
;
691 struct list_head
*list_start_pos
;
694 if (list_empty(&handle
->chains
))
697 /* Find a smart place to start the search */
698 list_start_pos
= iptcc_bsearch_chain_offset(offset
, &i
, handle
);
700 /* Note that iptcc_bsearch_chain_offset() skips builtin
701 * chains, but this function is only used for finding jump
702 * targets, and a buildin chain is not a valid jump target */
704 debug("Offset:[%u] starting search at index:[%u]\n", offset
, i
);
705 // list_for_each(pos, &handle->chains) {
706 list_for_each(pos
, list_start_pos
->prev
) {
707 struct chain_head
*c
= list_entry(pos
, struct chain_head
, list
);
709 if (offset
>= c
->head_offset
&& offset
<= c
->foot_offset
) {
710 debug("Offset search found chain:[%s]\n", c
->name
);
718 /* Returns chain head if found, otherwise NULL. */
719 static struct chain_head
*
720 iptcc_find_label(const char *name
, struct xtc_handle
*handle
)
722 struct list_head
*pos
;
723 struct list_head
*list_start_pos
;
727 if (list_empty(&handle
->chains
))
730 /* First look at builtin chains */
731 list_for_each(pos
, &handle
->chains
) {
732 struct chain_head
*c
= list_entry(pos
, struct chain_head
, list
);
733 if (!iptcc_is_builtin(c
))
735 if (!strcmp(c
->name
, name
))
739 /* Find a smart place to start the search via chain index */
740 //list_start_pos = iptcc_linearly_search_chain_index(name, handle);
741 list_start_pos
= iptcc_bsearch_chain_index(name
, &i
, handle
);
743 /* Handel if bsearch bails out early */
744 if (list_start_pos
== &handle
->chains
) {
745 list_start_pos
= pos
;
749 /* Verify result of bsearch against linearly index search */
750 struct list_head
*test_pos
;
751 struct chain_head
*test_c
, *tmp_c
;
752 test_pos
= iptcc_linearly_search_chain_index(name
, handle
);
753 if (list_start_pos
!= test_pos
) {
754 debug("BUG in chain_index search\n");
755 test_c
=list_entry(test_pos
, struct chain_head
,list
);
756 tmp_c
=list_entry(list_start_pos
,struct chain_head
,list
);
757 debug("Verify search found:\n");
758 debug(" Chain:%s\n", test_c
->name
);
759 debug("BSearch found:\n");
760 debug(" Chain:%s\n", tmp_c
->name
);
766 /* Initial/special case, no user defined chains */
767 if (handle
->num_chains
== 0)
770 /* Start searching through the chain list */
771 list_for_each(pos
, list_start_pos
->prev
) {
772 struct chain_head
*c
= list_entry(pos
, struct chain_head
, list
);
773 res
= strcmp(c
->name
, name
);
774 debug("List search name:%s == %s res:%d\n", name
, c
->name
, res
);
778 /* We can stop earlier as we know list is sorted */
779 if (res
>0 && !iptcc_is_builtin(c
)) { /* Walked too far*/
780 debug(" Not in list, walked too far, sorted list\n");
784 /* Stop on wrap around, if list head is reached */
785 if (pos
== &handle
->chains
) {
786 debug("Stop, list head reached\n");
791 debug("List search NOT found name:%s\n", name
);
795 /* called when rule is to be removed from cache */
796 static void iptcc_delete_rule(struct rule_head
*r
)
798 DEBUGP("deleting rule %p (offset %u)\n", r
, r
->offset
);
799 /* clean up reference count of called chain */
800 if (r
->type
== IPTCC_R_JUMP
802 r
->jump
->references
--;
809 /**********************************************************************
810 * RULESET PARSER (blob -> cache)
811 **********************************************************************/
813 /* Delete policy rule of previous chain, since cache doesn't contain
814 * chain policy rules.
815 * WARNING: This function has ugly design and relies on a lot of context, only
816 * to be called from specific places within the parser */
817 static int __iptcc_p_del_policy(struct xtc_handle
*h
, unsigned int num
)
819 if (h
->chain_iterator_cur
) {
820 /* policy rule is last rule */
821 struct rule_head
*pr
= (struct rule_head
*)
822 h
->chain_iterator_cur
->rules
.prev
;
825 h
->chain_iterator_cur
->verdict
=
826 *(int *)GET_TARGET(pr
->entry
)->data
;
828 /* save counter and counter_map information */
829 h
->chain_iterator_cur
->counter_map
.maptype
=
830 COUNTER_MAP_NORMAL_MAP
;
831 h
->chain_iterator_cur
->counter_map
.mappos
= num
-1;
832 memcpy(&h
->chain_iterator_cur
->counters
, &pr
->entry
->counters
,
833 sizeof(h
->chain_iterator_cur
->counters
));
835 /* foot_offset points to verdict rule */
836 h
->chain_iterator_cur
->foot_index
= num
;
837 h
->chain_iterator_cur
->foot_offset
= pr
->offset
;
839 /* delete rule from cache */
840 iptcc_delete_rule(pr
);
841 h
->chain_iterator_cur
->num_rules
--;
848 /* alphabetically insert a chain into the list */
849 static void iptc_insert_chain(struct xtc_handle
*h
, struct chain_head
*c
)
851 struct chain_head
*tmp
;
852 struct list_head
*list_start_pos
;
855 /* Find a smart place to start the insert search */
856 list_start_pos
= iptcc_bsearch_chain_index(c
->name
, &i
, h
);
858 /* Handle the case, where chain.name is smaller than index[0] */
859 if (i
==0 && strcmp(c
->name
, h
->chain_index
[0]->name
) <= 0) {
860 h
->chain_index
[0] = c
; /* Update chain index head */
861 list_start_pos
= h
->chains
.next
;
862 debug("Update chain_index[0] with %s\n", c
->name
);
865 /* Handel if bsearch bails out early */
866 if (list_start_pos
== &h
->chains
) {
867 list_start_pos
= h
->chains
.next
;
870 /* sort only user defined chains */
872 list_for_each_entry(tmp
, list_start_pos
->prev
, list
) {
873 if (!tmp
->hooknum
&& strcmp(c
->name
, tmp
->name
) <= 0) {
874 list_add(&c
->list
, tmp
->list
.prev
);
878 /* Stop if list head is reached */
879 if (&tmp
->list
== &h
->chains
) {
880 debug("Insert, list head reached add to tail\n");
886 /* survived till end of list: add at tail */
887 list_add_tail(&c
->list
, &h
->chains
);
890 /* Another ugly helper function split out of cache_add_entry to make it less
892 static void __iptcc_p_add_chain(struct xtc_handle
*h
, struct chain_head
*c
,
893 unsigned int offset
, unsigned int *num
)
895 struct list_head
*tail
= h
->chains
.prev
;
896 struct chain_head
*ctail
;
898 __iptcc_p_del_policy(h
, *num
);
900 c
->head_offset
= offset
;
903 /* Chains from kernel are already sorted, as they are inserted
904 * sorted. But there exists an issue when shifting to 1.4.0
905 * from an older version, as old versions allow last created
906 * chain to be unsorted.
908 if (iptcc_is_builtin(c
)) /* Only user defined chains are sorted*/
909 list_add_tail(&c
->list
, &h
->chains
);
911 ctail
= list_entry(tail
, struct chain_head
, list
);
913 if (strcmp(c
->name
, ctail
->name
) > 0 ||
914 iptcc_is_builtin(ctail
))
915 list_add_tail(&c
->list
, &h
->chains
);/* Already sorted*/
917 iptc_insert_chain(h
, c
);/* Was not sorted */
919 /* Notice, if chains were not received sorted
920 * from kernel, then an offset bsearch is no
923 h
->sorted_offsets
= 0;
925 debug("NOTICE: chain:[%s] was NOT sorted(ctail:%s)\n",
926 c
->name
, ctail
->name
);
930 h
->chain_iterator_cur
= c
;
933 /* main parser function: add an entry from the blob to the cache */
934 static int cache_add_entry(STRUCT_ENTRY
*e
,
935 struct xtc_handle
*h
,
939 unsigned int builtin
;
940 unsigned int offset
= (char *)e
- (char *)h
->entries
->entrytable
;
942 DEBUGP("entering...");
944 /* Last entry ("policy rule"). End it.*/
945 if (iptcb_entry2offset(h
,e
) + e
->next_offset
== h
->entries
->size
) {
946 /* This is the ERROR node at the end of the chain */
947 DEBUGP_C("%u:%u: end of table:\n", *num
, offset
);
949 __iptcc_p_del_policy(h
, *num
);
951 h
->chain_iterator_cur
= NULL
;
955 /* We know this is the start of a new chain if it's an ERROR
956 * target, or a hook entry point */
958 if (strcmp(GET_TARGET(e
)->u
.user
.name
, ERROR_TARGET
) == 0) {
959 struct chain_head
*c
=
960 iptcc_alloc_chain_head((const char *)GET_TARGET(e
)->data
, 0);
961 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num
, offset
,
967 h
->num_chains
++; /* New user defined chain */
969 __iptcc_p_add_chain(h
, c
, offset
, num
);
971 } else if ((builtin
= iptcb_ent_is_hook_entry(e
, h
)) != 0) {
972 struct chain_head
*c
=
973 iptcc_alloc_chain_head((char *)hooknames
[builtin
-1],
975 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
976 *num
, offset
, c
, &c
->rules
);
982 c
->hooknum
= builtin
;
984 __iptcc_p_add_chain(h
, c
, offset
, num
);
986 /* FIXME: this is ugly. */
989 /* has to be normal rule */
993 if (!(r
= iptcc_alloc_rule(h
->chain_iterator_cur
,
998 DEBUGP_C("%u:%u normal rule: %p: ", *num
, offset
, r
);
1002 memcpy(r
->entry
, e
, e
->next_offset
);
1003 r
->counter_map
.maptype
= COUNTER_MAP_NORMAL_MAP
;
1004 r
->counter_map
.mappos
= r
->index
;
1006 /* handling of jumps, etc. */
1007 if (!strcmp(GET_TARGET(e
)->u
.user
.name
, STANDARD_TARGET
)) {
1008 STRUCT_STANDARD_TARGET
*t
;
1010 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(e
);
1011 if (t
->target
.u
.target_size
1012 != ALIGN(sizeof(STRUCT_STANDARD_TARGET
))) {
1017 if (t
->verdict
< 0) {
1018 DEBUGP_C("standard, verdict=%d\n", t
->verdict
);
1019 r
->type
= IPTCC_R_STANDARD
;
1020 } else if (t
->verdict
== r
->offset
+e
->next_offset
) {
1021 DEBUGP_C("fallthrough\n");
1022 r
->type
= IPTCC_R_FALLTHROUGH
;
1024 DEBUGP_C("jump, target=%u\n", t
->verdict
);
1025 r
->type
= IPTCC_R_JUMP
;
1026 /* Jump target fixup has to be deferred
1027 * until second pass, since we migh not
1028 * yet have parsed the target */
1031 DEBUGP_C("module, target=%s\n", GET_TARGET(e
)->u
.user
.name
);
1032 r
->type
= IPTCC_R_MODULE
;
1035 list_add_tail(&r
->list
, &h
->chain_iterator_cur
->rules
);
1036 h
->chain_iterator_cur
->num_rules
++;
1044 /* parse an iptables blob into it's pieces */
1045 static int parse_table(struct xtc_handle
*h
)
1048 unsigned int num
= 0;
1049 struct chain_head
*c
;
1051 /* Assume that chains offsets are sorted, this verified during
1052 parsing of ruleset (in __iptcc_p_add_chain())*/
1053 h
->sorted_offsets
= 1;
1055 /* First pass: over ruleset blob */
1056 ENTRY_ITERATE(h
->entries
->entrytable
, h
->entries
->size
,
1057 cache_add_entry
, h
, &prev
, &num
);
1059 /* Build the chain index, used for chain list search speedup */
1060 if ((iptcc_chain_index_alloc(h
)) < 0)
1062 iptcc_chain_index_build(h
);
1064 /* Second pass: fixup parsed data from first pass */
1065 list_for_each_entry(c
, &h
->chains
, list
) {
1066 struct rule_head
*r
;
1067 list_for_each_entry(r
, &c
->rules
, list
) {
1068 struct chain_head
*lc
;
1069 STRUCT_STANDARD_TARGET
*t
;
1071 if (r
->type
!= IPTCC_R_JUMP
)
1074 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
1075 lc
= iptcc_find_chain_by_offset(h
, t
->verdict
);
1087 /**********************************************************************
1088 * RULESET COMPILATION (cache -> blob)
1089 **********************************************************************/
1091 /* Convenience structures */
1092 struct iptcb_chain_start
{
1094 struct ipt_error_target name
;
1096 #define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
1097 ALIGN(sizeof(struct ipt_error_target)))
1099 struct iptcb_chain_foot
{
1101 STRUCT_STANDARD_TARGET target
;
1103 #define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
1104 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
1106 struct iptcb_chain_error
{
1108 struct ipt_error_target target
;
1110 #define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
1111 ALIGN(sizeof(struct ipt_error_target)))
1115 /* compile rule from cache into blob */
1116 static inline int iptcc_compile_rule (struct xtc_handle
*h
, STRUCT_REPLACE
*repl
, struct rule_head
*r
)
1119 if (r
->type
== IPTCC_R_JUMP
) {
1120 STRUCT_STANDARD_TARGET
*t
;
1121 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
1122 /* memset for memcmp convenience on delete/replace */
1123 memset(t
->target
.u
.user
.name
, 0, FUNCTION_MAXNAMELEN
);
1124 strcpy(t
->target
.u
.user
.name
, STANDARD_TARGET
);
1125 /* Jumps can only happen to builtin chains, so we
1126 * can safely assume that they always have a header */
1127 t
->verdict
= r
->jump
->head_offset
+ IPTCB_CHAIN_START_SIZE
;
1128 } else if (r
->type
== IPTCC_R_FALLTHROUGH
) {
1129 STRUCT_STANDARD_TARGET
*t
;
1130 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
1131 t
->verdict
= r
->offset
+ r
->size
;
1134 /* copy entry from cache to blob */
1135 memcpy((char *)repl
->entries
+r
->offset
, r
->entry
, r
->size
);
1140 /* compile chain from cache into blob */
1141 static int iptcc_compile_chain(struct xtc_handle
*h
, STRUCT_REPLACE
*repl
, struct chain_head
*c
)
1144 struct rule_head
*r
;
1145 struct iptcb_chain_start
*head
;
1146 struct iptcb_chain_foot
*foot
;
1148 /* only user-defined chains have heaer */
1149 if (!iptcc_is_builtin(c
)) {
1150 /* put chain header in place */
1151 head
= (void *)repl
->entries
+ c
->head_offset
;
1152 head
->e
.target_offset
= sizeof(STRUCT_ENTRY
);
1153 head
->e
.next_offset
= IPTCB_CHAIN_START_SIZE
;
1154 strcpy(head
->name
.t
.u
.user
.name
, ERROR_TARGET
);
1155 head
->name
.t
.u
.target_size
=
1156 ALIGN(sizeof(struct ipt_error_target
));
1157 strcpy(head
->name
.error
, c
->name
);
1159 repl
->hook_entry
[c
->hooknum
-1] = c
->head_offset
;
1160 repl
->underflow
[c
->hooknum
-1] = c
->foot_offset
;
1163 /* iterate over rules */
1164 list_for_each_entry(r
, &c
->rules
, list
) {
1165 ret
= iptcc_compile_rule(h
, repl
, r
);
1170 /* put chain footer in place */
1171 foot
= (void *)repl
->entries
+ c
->foot_offset
;
1172 foot
->e
.target_offset
= sizeof(STRUCT_ENTRY
);
1173 foot
->e
.next_offset
= IPTCB_CHAIN_FOOT_SIZE
;
1174 strcpy(foot
->target
.target
.u
.user
.name
, STANDARD_TARGET
);
1175 foot
->target
.target
.u
.target_size
=
1176 ALIGN(sizeof(STRUCT_STANDARD_TARGET
));
1177 /* builtin targets have verdict, others return */
1178 if (iptcc_is_builtin(c
))
1179 foot
->target
.verdict
= c
->verdict
;
1181 foot
->target
.verdict
= RETURN
;
1182 /* set policy-counters */
1183 memcpy(&foot
->e
.counters
, &c
->counters
, sizeof(STRUCT_COUNTERS
));
1188 /* calculate offset and number for every rule in the cache */
1189 static int iptcc_compile_chain_offsets(struct xtc_handle
*h
, struct chain_head
*c
,
1190 unsigned int *offset
, unsigned int *num
)
1192 struct rule_head
*r
;
1194 c
->head_offset
= *offset
;
1195 DEBUGP("%s: chain_head %u, offset=%u\n", c
->name
, *num
, *offset
);
1197 if (!iptcc_is_builtin(c
)) {
1198 /* Chain has header */
1199 *offset
+= sizeof(STRUCT_ENTRY
)
1200 + ALIGN(sizeof(struct ipt_error_target
));
1204 list_for_each_entry(r
, &c
->rules
, list
) {
1205 DEBUGP("rule %u, offset=%u, index=%u\n", *num
, *offset
, *num
);
1206 r
->offset
= *offset
;
1212 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c
->name
, *num
,
1214 c
->foot_offset
= *offset
;
1215 c
->foot_index
= *num
;
1216 *offset
+= sizeof(STRUCT_ENTRY
)
1217 + ALIGN(sizeof(STRUCT_STANDARD_TARGET
));
1223 /* put the pieces back together again */
1224 static int iptcc_compile_table_prep(struct xtc_handle
*h
, unsigned int *size
)
1226 struct chain_head
*c
;
1227 unsigned int offset
= 0, num
= 0;
1230 /* First pass: calculate offset for every rule */
1231 list_for_each_entry(c
, &h
->chains
, list
) {
1232 ret
= iptcc_compile_chain_offsets(h
, c
, &offset
, &num
);
1237 /* Append one error rule at end of chain */
1239 offset
+= sizeof(STRUCT_ENTRY
)
1240 + ALIGN(sizeof(struct ipt_error_target
));
1242 /* ruleset size is now in offset */
1247 static int iptcc_compile_table(struct xtc_handle
*h
, STRUCT_REPLACE
*repl
)
1249 struct chain_head
*c
;
1250 struct iptcb_chain_error
*error
;
1252 /* Second pass: copy from cache to offsets, fill in jumps */
1253 list_for_each_entry(c
, &h
->chains
, list
) {
1254 int ret
= iptcc_compile_chain(h
, repl
, c
);
1259 /* Append error rule at end of chain */
1260 error
= (void *)repl
->entries
+ repl
->size
- IPTCB_CHAIN_ERROR_SIZE
;
1261 error
->entry
.target_offset
= sizeof(STRUCT_ENTRY
);
1262 error
->entry
.next_offset
= IPTCB_CHAIN_ERROR_SIZE
;
1263 error
->target
.t
.u
.user
.target_size
=
1264 ALIGN(sizeof(struct ipt_error_target
));
1265 strcpy((char *)&error
->target
.t
.u
.user
.name
, ERROR_TARGET
);
1266 strcpy((char *)&error
->target
.error
, "ERROR");
1271 /**********************************************************************
1272 * EXTERNAL API (operates on cache only)
1273 **********************************************************************/
1275 /* Allocate handle of given size */
1276 static struct xtc_handle
*
1277 alloc_handle(const char *tablename
, unsigned int size
, unsigned int num_rules
)
1280 struct xtc_handle
*h
;
1282 len
= sizeof(STRUCT_TC_HANDLE
) + size
;
1284 h
= malloc(sizeof(STRUCT_TC_HANDLE
));
1289 memset(h
, 0, sizeof(*h
));
1290 INIT_LIST_HEAD(&h
->chains
);
1291 strcpy(h
->info
.name
, tablename
);
1293 h
->entries
= malloc(sizeof(STRUCT_GET_ENTRIES
) + size
);
1295 goto out_free_handle
;
1297 strcpy(h
->entries
->name
, tablename
);
1298 h
->entries
->size
= size
;
1310 TC_INIT(const char *tablename
)
1312 struct xtc_handle
*h
;
1313 STRUCT_GETINFO info
;
1320 if (strlen(tablename
) >= TABLE_MAXNAMELEN
) {
1325 sockfd
= socket(TC_AF
, SOCK_RAW
, IPPROTO_RAW
);
1332 strcpy(info
.name
, tablename
);
1333 if (getsockopt(sockfd
, TC_IPPROTO
, SO_GET_INFO
, &info
, &s
) < 0) {
1338 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
1339 info
.valid_hooks
, info
.num_entries
, info
.size
);
1341 if ((h
= alloc_handle(info
.name
, info
.size
, info
.num_entries
))
1347 /* Initialize current state */
1351 h
->entries
->size
= h
->info
.size
;
1353 tmp
= sizeof(STRUCT_GET_ENTRIES
) + h
->info
.size
;
1355 if (getsockopt(h
->sockfd
, TC_IPPROTO
, SO_GET_ENTRIES
, h
->entries
,
1361 int fd
= open("/tmp/libiptc-so_get_entries.blob",
1364 write(fd
, h
->entries
, tmp
);
1370 if (parse_table(h
) < 0)
1377 /* A different process changed the ruleset size, retry */
1378 if (errno
== EAGAIN
)
1384 TC_FREE(struct xtc_handle
*h
)
1386 struct chain_head
*c
, *tmp
;
1391 list_for_each_entry_safe(c
, tmp
, &h
->chains
, list
) {
1392 struct rule_head
*r
, *rtmp
;
1394 list_for_each_entry_safe(r
, rtmp
, &c
->rules
, list
) {
1401 iptcc_chain_index_free(h
);
1408 print_match(const STRUCT_ENTRY_MATCH
*m
)
1410 printf("Match name: `%s'\n", m
->u
.user
.name
);
1414 static int dump_entry(STRUCT_ENTRY
*e
, struct xtc_handle
*const handle
);
1417 TC_DUMP_ENTRIES(struct xtc_handle
*const handle
)
1419 iptc_fn
= TC_DUMP_ENTRIES
;
1422 printf("libiptc v%s. %u bytes.\n",
1423 XTABLES_VERSION
, handle
->entries
->size
);
1424 printf("Table `%s'\n", handle
->info
.name
);
1425 printf("Hooks: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
1426 handle
->info
.hook_entry
[HOOK_PRE_ROUTING
],
1427 handle
->info
.hook_entry
[HOOK_LOCAL_IN
],
1428 handle
->info
.hook_entry
[HOOK_FORWARD
],
1429 handle
->info
.hook_entry
[HOOK_LOCAL_OUT
],
1430 handle
->info
.hook_entry
[HOOK_POST_ROUTING
]);
1431 printf("Underflows: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
1432 handle
->info
.underflow
[HOOK_PRE_ROUTING
],
1433 handle
->info
.underflow
[HOOK_LOCAL_IN
],
1434 handle
->info
.underflow
[HOOK_FORWARD
],
1435 handle
->info
.underflow
[HOOK_LOCAL_OUT
],
1436 handle
->info
.underflow
[HOOK_POST_ROUTING
]);
1438 ENTRY_ITERATE(handle
->entries
->entrytable
, handle
->entries
->size
,
1439 dump_entry
, handle
);
1442 /* Does this chain exist? */
1443 int TC_IS_CHAIN(const char *chain
, struct xtc_handle
*const handle
)
1445 iptc_fn
= TC_IS_CHAIN
;
1446 return iptcc_find_label(chain
, handle
) != NULL
;
1449 static void iptcc_chain_iterator_advance(struct xtc_handle
*handle
)
1451 struct chain_head
*c
= handle
->chain_iterator_cur
;
1453 if (c
->list
.next
== &handle
->chains
)
1454 handle
->chain_iterator_cur
= NULL
;
1456 handle
->chain_iterator_cur
=
1457 list_entry(c
->list
.next
, struct chain_head
, list
);
1460 /* Iterator functions to run through the chains. */
1462 TC_FIRST_CHAIN(struct xtc_handle
*handle
)
1464 struct chain_head
*c
= list_entry(handle
->chains
.next
,
1465 struct chain_head
, list
);
1467 iptc_fn
= TC_FIRST_CHAIN
;
1470 if (list_empty(&handle
->chains
)) {
1471 DEBUGP(": no chains\n");
1475 handle
->chain_iterator_cur
= c
;
1476 iptcc_chain_iterator_advance(handle
);
1478 DEBUGP(": returning `%s'\n", c
->name
);
1482 /* Iterator functions to run through the chains. Returns NULL at end. */
1484 TC_NEXT_CHAIN(struct xtc_handle
*handle
)
1486 struct chain_head
*c
= handle
->chain_iterator_cur
;
1488 iptc_fn
= TC_NEXT_CHAIN
;
1491 DEBUGP(": no more chains\n");
1495 iptcc_chain_iterator_advance(handle
);
1497 DEBUGP(": returning `%s'\n", c
->name
);
1501 /* Get first rule in the given chain: NULL for empty chain. */
1502 const STRUCT_ENTRY
*
1503 TC_FIRST_RULE(const char *chain
, struct xtc_handle
*handle
)
1505 struct chain_head
*c
;
1506 struct rule_head
*r
;
1508 iptc_fn
= TC_FIRST_RULE
;
1510 DEBUGP("first rule(%s): ", chain
);
1512 c
= iptcc_find_label(chain
, handle
);
1518 /* Empty chain: single return/policy rule */
1519 if (list_empty(&c
->rules
)) {
1520 DEBUGP_C("no rules, returning NULL\n");
1524 r
= list_entry(c
->rules
.next
, struct rule_head
, list
);
1525 handle
->rule_iterator_cur
= r
;
1526 DEBUGP_C("%p\n", r
);
1531 /* Returns NULL when rules run out. */
1532 const STRUCT_ENTRY
*
1533 TC_NEXT_RULE(const STRUCT_ENTRY
*prev
, struct xtc_handle
*handle
)
1535 struct rule_head
*r
;
1537 iptc_fn
= TC_NEXT_RULE
;
1538 DEBUGP("rule_iterator_cur=%p...", handle
->rule_iterator_cur
);
1540 if (handle
->rule_iterator_cur
== NULL
) {
1541 DEBUGP_C("returning NULL\n");
1545 r
= list_entry(handle
->rule_iterator_cur
->list
.next
,
1546 struct rule_head
, list
);
1548 iptc_fn
= TC_NEXT_RULE
;
1550 DEBUGP_C("next=%p, head=%p...", &r
->list
,
1551 &handle
->rule_iterator_cur
->chain
->rules
);
1553 if (&r
->list
== &handle
->rule_iterator_cur
->chain
->rules
) {
1554 handle
->rule_iterator_cur
= NULL
;
1555 DEBUGP_C("finished, returning NULL\n");
1559 handle
->rule_iterator_cur
= r
;
1561 /* NOTE: prev is without any influence ! */
1562 DEBUGP_C("returning rule %p\n", r
);
1566 /* How many rules in this chain? */
1568 TC_NUM_RULES(const char *chain
, struct xtc_handle
*handle
)
1570 struct chain_head
*c
;
1571 iptc_fn
= TC_NUM_RULES
;
1574 c
= iptcc_find_label(chain
, handle
);
1577 return (unsigned int)-1;
1580 return c
->num_rules
;
1583 static const STRUCT_ENTRY
*
1584 TC_GET_RULE(const char *chain
, unsigned int n
, struct xtc_handle
*handle
)
1586 struct chain_head
*c
;
1587 struct rule_head
*r
;
1589 iptc_fn
= TC_GET_RULE
;
1593 c
= iptcc_find_label(chain
, handle
);
1599 r
= iptcc_get_rule_num(c
, n
);
1605 /* Returns a pointer to the target name of this position. */
1606 static const char *standard_target_map(int verdict
)
1610 return LABEL_RETURN
;
1613 return LABEL_ACCEPT
;
1622 fprintf(stderr
, "ERROR: %d not a valid target)\n",
1631 /* Returns a pointer to the target name of this position. */
1632 const char *TC_GET_TARGET(const STRUCT_ENTRY
*ce
,
1633 struct xtc_handle
*handle
)
1635 STRUCT_ENTRY
*e
= (STRUCT_ENTRY
*)ce
;
1636 struct rule_head
*r
= container_of(e
, struct rule_head
, entry
[0]);
1638 iptc_fn
= TC_GET_TARGET
;
1642 case IPTCC_R_FALLTHROUGH
:
1646 DEBUGP("r=%p, jump=%p, name=`%s'\n", r
, r
->jump
, r
->jump
->name
);
1647 return r
->jump
->name
;
1649 case IPTCC_R_STANDARD
:
1650 spos
= *(int *)GET_TARGET(e
)->data
;
1651 DEBUGP("r=%p, spos=%d'\n", r
, spos
);
1652 return standard_target_map(spos
);
1654 case IPTCC_R_MODULE
:
1655 return GET_TARGET(e
)->u
.user
.name
;
1660 /* Is this a built-in chain? Actually returns hook + 1. */
1662 TC_BUILTIN(const char *chain
, struct xtc_handle
*const handle
)
1664 struct chain_head
*c
;
1666 iptc_fn
= TC_BUILTIN
;
1668 c
= iptcc_find_label(chain
, handle
);
1674 return iptcc_is_builtin(c
);
1677 /* Get the policy of a given built-in chain */
1679 TC_GET_POLICY(const char *chain
,
1680 STRUCT_COUNTERS
*counters
,
1681 struct xtc_handle
*handle
)
1683 struct chain_head
*c
;
1685 iptc_fn
= TC_GET_POLICY
;
1687 DEBUGP("called for chain %s\n", chain
);
1689 c
= iptcc_find_label(chain
, handle
);
1695 if (!iptcc_is_builtin(c
))
1698 *counters
= c
->counters
;
1700 return standard_target_map(c
->verdict
);
1704 iptcc_standard_map(struct rule_head
*r
, int verdict
)
1706 STRUCT_ENTRY
*e
= r
->entry
;
1707 STRUCT_STANDARD_TARGET
*t
;
1709 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(e
);
1711 if (t
->target
.u
.target_size
1712 != ALIGN(sizeof(STRUCT_STANDARD_TARGET
))) {
1716 /* memset for memcmp convenience on delete/replace */
1717 memset(t
->target
.u
.user
.name
, 0, FUNCTION_MAXNAMELEN
);
1718 strcpy(t
->target
.u
.user
.name
, STANDARD_TARGET
);
1719 t
->verdict
= verdict
;
1721 r
->type
= IPTCC_R_STANDARD
;
1727 iptcc_map_target(struct xtc_handle
*const handle
,
1728 struct rule_head
*r
)
1730 STRUCT_ENTRY
*e
= r
->entry
;
1731 STRUCT_ENTRY_TARGET
*t
= GET_TARGET(e
);
1733 /* Maybe it's empty (=> fall through) */
1734 if (strcmp(t
->u
.user
.name
, "") == 0) {
1735 r
->type
= IPTCC_R_FALLTHROUGH
;
1738 /* Maybe it's a standard target name... */
1739 else if (strcmp(t
->u
.user
.name
, LABEL_ACCEPT
) == 0)
1740 return iptcc_standard_map(r
, -NF_ACCEPT
- 1);
1741 else if (strcmp(t
->u
.user
.name
, LABEL_DROP
) == 0)
1742 return iptcc_standard_map(r
, -NF_DROP
- 1);
1743 else if (strcmp(t
->u
.user
.name
, LABEL_QUEUE
) == 0)
1744 return iptcc_standard_map(r
, -NF_QUEUE
- 1);
1745 else if (strcmp(t
->u
.user
.name
, LABEL_RETURN
) == 0)
1746 return iptcc_standard_map(r
, RETURN
);
1747 else if (TC_BUILTIN(t
->u
.user
.name
, handle
)) {
1748 /* Can't jump to builtins. */
1752 /* Maybe it's an existing chain name. */
1753 struct chain_head
*c
;
1754 DEBUGP("trying to find chain `%s': ", t
->u
.user
.name
);
1756 c
= iptcc_find_label(t
->u
.user
.name
, handle
);
1758 DEBUGP_C("found!\n");
1759 r
->type
= IPTCC_R_JUMP
;
1764 DEBUGP_C("not found :(\n");
1767 /* Must be a module? If not, kernel will reject... */
1768 /* memset to all 0 for your memcmp convenience: don't clear version */
1769 memset(t
->u
.user
.name
+ strlen(t
->u
.user
.name
),
1771 FUNCTION_MAXNAMELEN
- 1 - strlen(t
->u
.user
.name
));
1772 r
->type
= IPTCC_R_MODULE
;
1773 set_changed(handle
);
1777 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1779 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain
,
1780 const STRUCT_ENTRY
*e
,
1781 unsigned int rulenum
,
1782 struct xtc_handle
*handle
)
1784 struct chain_head
*c
;
1785 struct rule_head
*r
;
1786 struct list_head
*prev
;
1788 iptc_fn
= TC_INSERT_ENTRY
;
1790 if (!(c
= iptcc_find_label(chain
, handle
))) {
1795 /* first rulenum index = 0
1796 first c->num_rules index = 1 */
1797 if (rulenum
> c
->num_rules
) {
1802 /* If we are inserting at the end just take advantage of the
1803 double linked list, insert will happen before the entry
1805 if (rulenum
== c
->num_rules
) {
1807 } else if (rulenum
+ 1 <= c
->num_rules
/2) {
1808 r
= iptcc_get_rule_num(c
, rulenum
+ 1);
1811 r
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
1815 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1820 memcpy(r
->entry
, e
, e
->next_offset
);
1821 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1823 if (!iptcc_map_target(handle
, r
)) {
1828 list_add_tail(&r
->list
, prev
);
1831 set_changed(handle
);
1836 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1838 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain
,
1839 const STRUCT_ENTRY
*e
,
1840 unsigned int rulenum
,
1841 struct xtc_handle
*handle
)
1843 struct chain_head
*c
;
1844 struct rule_head
*r
, *old
;
1846 iptc_fn
= TC_REPLACE_ENTRY
;
1848 if (!(c
= iptcc_find_label(chain
, handle
))) {
1853 if (rulenum
>= c
->num_rules
) {
1858 /* Take advantage of the double linked list if possible. */
1859 if (rulenum
+ 1 <= c
->num_rules
/2) {
1860 old
= iptcc_get_rule_num(c
, rulenum
+ 1);
1862 old
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
1865 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1870 memcpy(r
->entry
, e
, e
->next_offset
);
1871 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1873 if (!iptcc_map_target(handle
, r
)) {
1878 list_add(&r
->list
, &old
->list
);
1879 iptcc_delete_rule(old
);
1881 set_changed(handle
);
1886 /* Append entry `fw' to chain `chain'. Equivalent to insert with
1887 rulenum = length of chain. */
1889 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain
,
1890 const STRUCT_ENTRY
*e
,
1891 struct xtc_handle
*handle
)
1893 struct chain_head
*c
;
1894 struct rule_head
*r
;
1896 iptc_fn
= TC_APPEND_ENTRY
;
1897 if (!(c
= iptcc_find_label(chain
, handle
))) {
1898 DEBUGP("unable to find chain `%s'\n", chain
);
1903 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1904 DEBUGP("unable to allocate rule for chain `%s'\n", chain
);
1909 memcpy(r
->entry
, e
, e
->next_offset
);
1910 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1912 if (!iptcc_map_target(handle
, r
)) {
1913 DEBUGP("unable to map target of rule for chain `%s'\n", chain
);
1918 list_add_tail(&r
->list
, &c
->rules
);
1921 set_changed(handle
);
1927 match_different(const STRUCT_ENTRY_MATCH
*a
,
1928 const unsigned char *a_elems
,
1929 const unsigned char *b_elems
,
1930 unsigned char **maskptr
)
1932 const STRUCT_ENTRY_MATCH
*b
;
1935 /* Offset of b is the same as a. */
1936 b
= (void *)b_elems
+ ((unsigned char *)a
- a_elems
);
1938 if (a
->u
.match_size
!= b
->u
.match_size
)
1941 if (strcmp(a
->u
.user
.name
, b
->u
.user
.name
) != 0)
1944 *maskptr
+= ALIGN(sizeof(*a
));
1946 for (i
= 0; i
< a
->u
.match_size
- ALIGN(sizeof(*a
)); i
++)
1947 if (((a
->data
[i
] ^ b
->data
[i
]) & (*maskptr
)[i
]) != 0)
1954 target_same(struct rule_head
*a
, struct rule_head
*b
,const unsigned char *mask
)
1957 STRUCT_ENTRY_TARGET
*ta
, *tb
;
1959 if (a
->type
!= b
->type
)
1962 ta
= GET_TARGET(a
->entry
);
1963 tb
= GET_TARGET(b
->entry
);
1966 case IPTCC_R_FALLTHROUGH
:
1969 return a
->jump
== b
->jump
;
1970 case IPTCC_R_STANDARD
:
1971 return ((STRUCT_STANDARD_TARGET
*)ta
)->verdict
1972 == ((STRUCT_STANDARD_TARGET
*)tb
)->verdict
;
1973 case IPTCC_R_MODULE
:
1974 if (ta
->u
.target_size
!= tb
->u
.target_size
)
1976 if (strcmp(ta
->u
.user
.name
, tb
->u
.user
.name
) != 0)
1979 for (i
= 0; i
< ta
->u
.target_size
- sizeof(*ta
); i
++)
1980 if (((ta
->data
[i
] ^ tb
->data
[i
]) & mask
[i
]) != 0)
1984 fprintf(stderr
, "ERROR: bad type %i\n", a
->type
);
1989 static unsigned char *
1990 is_same(const STRUCT_ENTRY
*a
,
1991 const STRUCT_ENTRY
*b
,
1992 unsigned char *matchmask
);
1994 /* Delete the first rule in `chain' which matches `fw'. */
1996 TC_DELETE_ENTRY(const IPT_CHAINLABEL chain
,
1997 const STRUCT_ENTRY
*origfw
,
1998 unsigned char *matchmask
,
1999 struct xtc_handle
*handle
)
2001 struct chain_head
*c
;
2002 struct rule_head
*r
, *i
;
2004 iptc_fn
= TC_DELETE_ENTRY
;
2005 if (!(c
= iptcc_find_label(chain
, handle
))) {
2010 /* Create a rule_head from origfw. */
2011 r
= iptcc_alloc_rule(c
, origfw
->next_offset
);
2017 memcpy(r
->entry
, origfw
, origfw
->next_offset
);
2018 r
->counter_map
.maptype
= COUNTER_MAP_NOMAP
;
2019 if (!iptcc_map_target(handle
, r
)) {
2020 DEBUGP("unable to map target of rule for chain `%s'\n", chain
);
2024 /* iptcc_map_target increment target chain references
2025 * since this is a fake rule only used for matching
2026 * the chain references count is decremented again.
2028 if (r
->type
== IPTCC_R_JUMP
2030 r
->jump
->references
--;
2033 list_for_each_entry(i
, &c
->rules
, list
) {
2034 unsigned char *mask
;
2036 mask
= is_same(r
->entry
, i
->entry
, matchmask
);
2040 if (!target_same(r
, i
, mask
))
2043 /* If we are about to delete the rule that is the
2044 * current iterator, move rule iterator back. next
2045 * pointer will then point to real next node */
2046 if (i
== handle
->rule_iterator_cur
) {
2047 handle
->rule_iterator_cur
=
2048 list_entry(handle
->rule_iterator_cur
->list
.prev
,
2049 struct rule_head
, list
);
2053 iptcc_delete_rule(i
);
2055 set_changed(handle
);
2066 /* Delete the rule in position `rulenum' in `chain'. */
2068 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain
,
2069 unsigned int rulenum
,
2070 struct xtc_handle
*handle
)
2072 struct chain_head
*c
;
2073 struct rule_head
*r
;
2075 iptc_fn
= TC_DELETE_NUM_ENTRY
;
2077 if (!(c
= iptcc_find_label(chain
, handle
))) {
2082 if (rulenum
>= c
->num_rules
) {
2087 /* Take advantage of the double linked list if possible. */
2088 if (rulenum
+ 1 <= c
->num_rules
/2) {
2089 r
= iptcc_get_rule_num(c
, rulenum
+ 1);
2091 r
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
2094 /* If we are about to delete the rule that is the current
2095 * iterator, move rule iterator back. next pointer will then
2096 * point to real next node */
2097 if (r
== handle
->rule_iterator_cur
) {
2098 handle
->rule_iterator_cur
=
2099 list_entry(handle
->rule_iterator_cur
->list
.prev
,
2100 struct rule_head
, list
);
2104 iptcc_delete_rule(r
);
2106 set_changed(handle
);
2111 /* Flushes the entries in the given chain (ie. empties chain). */
2113 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain
, struct xtc_handle
*handle
)
2115 struct chain_head
*c
;
2116 struct rule_head
*r
, *tmp
;
2118 iptc_fn
= TC_FLUSH_ENTRIES
;
2119 if (!(c
= iptcc_find_label(chain
, handle
))) {
2124 list_for_each_entry_safe(r
, tmp
, &c
->rules
, list
) {
2125 iptcc_delete_rule(r
);
2130 set_changed(handle
);
2135 /* Zeroes the counters in a chain. */
2137 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain
, struct xtc_handle
*handle
)
2139 struct chain_head
*c
;
2140 struct rule_head
*r
;
2142 iptc_fn
= TC_ZERO_ENTRIES
;
2143 if (!(c
= iptcc_find_label(chain
, handle
))) {
2148 if (c
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
2149 c
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
2151 list_for_each_entry(r
, &c
->rules
, list
) {
2152 if (r
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
2153 r
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
2156 set_changed(handle
);
2162 TC_READ_COUNTER(const IPT_CHAINLABEL chain
,
2163 unsigned int rulenum
,
2164 struct xtc_handle
*handle
)
2166 struct chain_head
*c
;
2167 struct rule_head
*r
;
2169 iptc_fn
= TC_READ_COUNTER
;
2172 if (!(c
= iptcc_find_label(chain
, handle
))) {
2177 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
2182 return &r
->entry
[0].counters
;
2186 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain
,
2187 unsigned int rulenum
,
2188 struct xtc_handle
*handle
)
2190 struct chain_head
*c
;
2191 struct rule_head
*r
;
2193 iptc_fn
= TC_ZERO_COUNTER
;
2196 if (!(c
= iptcc_find_label(chain
, handle
))) {
2201 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
2206 if (r
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
2207 r
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
2209 set_changed(handle
);
2215 TC_SET_COUNTER(const IPT_CHAINLABEL chain
,
2216 unsigned int rulenum
,
2217 STRUCT_COUNTERS
*counters
,
2218 struct xtc_handle
*handle
)
2220 struct chain_head
*c
;
2221 struct rule_head
*r
;
2224 iptc_fn
= TC_SET_COUNTER
;
2227 if (!(c
= iptcc_find_label(chain
, handle
))) {
2232 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
2238 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
2240 memcpy(&e
->counters
, counters
, sizeof(STRUCT_COUNTERS
));
2242 set_changed(handle
);
2247 /* Creates a new chain. */
2248 /* To create a chain, create two rules: error node and unconditional
2251 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain
, struct xtc_handle
*handle
)
2253 static struct chain_head
*c
;
2257 iptc_fn
= TC_CREATE_CHAIN
;
2259 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2261 if (iptcc_find_label(chain
, handle
)
2262 || strcmp(chain
, LABEL_DROP
) == 0
2263 || strcmp(chain
, LABEL_ACCEPT
) == 0
2264 || strcmp(chain
, LABEL_QUEUE
) == 0
2265 || strcmp(chain
, LABEL_RETURN
) == 0) {
2266 DEBUGP("Chain `%s' already exists\n", chain
);
2271 if (strlen(chain
)+1 > sizeof(IPT_CHAINLABEL
)) {
2272 DEBUGP("Chain name `%s' too long\n", chain
);
2277 c
= iptcc_alloc_chain_head(chain
, 0);
2279 DEBUGP("Cannot allocate memory for chain `%s'\n", chain
);
2284 handle
->num_chains
++; /* New user defined chain */
2286 DEBUGP("Creating chain `%s'\n", chain
);
2287 iptc_insert_chain(handle
, c
); /* Insert sorted */
2289 /* Inserting chains don't change the correctness of the chain
2290 * index (except if its smaller than index[0], but that
2291 * handled by iptc_insert_chain). It only causes longer lists
2292 * in the buckets. Thus, only rebuild chain index when the
2293 * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains.
2295 capacity
= handle
->chain_index_sz
* CHAIN_INDEX_BUCKET_LEN
;
2296 exceeded
= handle
->num_chains
- capacity
;
2297 if (exceeded
> CHAIN_INDEX_INSERT_MAX
) {
2298 debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n",
2299 capacity
, exceeded
, handle
->num_chains
);
2300 iptcc_chain_index_rebuild(handle
);
2303 set_changed(handle
);
2308 /* Get the number of references to this chain. */
2310 TC_GET_REFERENCES(unsigned int *ref
, const IPT_CHAINLABEL chain
,
2311 struct xtc_handle
*handle
)
2313 struct chain_head
*c
;
2315 iptc_fn
= TC_GET_REFERENCES
;
2316 if (!(c
= iptcc_find_label(chain
, handle
))) {
2321 *ref
= c
->references
;
2326 /* Deletes a chain. */
2328 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain
, struct xtc_handle
*handle
)
2330 unsigned int references
;
2331 struct chain_head
*c
;
2333 iptc_fn
= TC_DELETE_CHAIN
;
2335 if (!(c
= iptcc_find_label(chain
, handle
))) {
2336 DEBUGP("cannot find chain `%s'\n", chain
);
2341 if (TC_BUILTIN(chain
, handle
)) {
2342 DEBUGP("cannot remove builtin chain `%s'\n", chain
);
2347 if (!TC_GET_REFERENCES(&references
, chain
, handle
)) {
2348 DEBUGP("cannot get references on chain `%s'\n", chain
);
2352 if (references
> 0) {
2353 DEBUGP("chain `%s' still has references\n", chain
);
2359 DEBUGP("chain `%s' is not empty\n", chain
);
2364 /* If we are about to delete the chain that is the current
2365 * iterator, move chain iterator forward. */
2366 if (c
== handle
->chain_iterator_cur
)
2367 iptcc_chain_iterator_advance(handle
);
2369 handle
->num_chains
--; /* One user defined chain deleted */
2371 //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */
2372 iptcc_chain_index_delete_chain(c
, handle
);
2375 DEBUGP("chain `%s' deleted\n", chain
);
2377 set_changed(handle
);
2382 /* Renames a chain. */
2383 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname
,
2384 const IPT_CHAINLABEL newname
,
2385 struct xtc_handle
*handle
)
2387 struct chain_head
*c
;
2388 iptc_fn
= TC_RENAME_CHAIN
;
2390 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2392 if (iptcc_find_label(newname
, handle
)
2393 || strcmp(newname
, LABEL_DROP
) == 0
2394 || strcmp(newname
, LABEL_ACCEPT
) == 0
2395 || strcmp(newname
, LABEL_QUEUE
) == 0
2396 || strcmp(newname
, LABEL_RETURN
) == 0) {
2401 if (!(c
= iptcc_find_label(oldname
, handle
))
2402 || TC_BUILTIN(oldname
, handle
)) {
2407 if (strlen(newname
)+1 > sizeof(IPT_CHAINLABEL
)) {
2412 /* This only unlinks "c" from the list, thus no free(c) */
2413 iptcc_chain_index_delete_chain(c
, handle
);
2415 /* Change the name of the chain */
2416 strncpy(c
->name
, newname
, sizeof(IPT_CHAINLABEL
));
2418 /* Insert sorted into to list again */
2419 iptc_insert_chain(handle
, c
);
2421 set_changed(handle
);
2426 /* Sets the policy on a built-in chain. */
2428 TC_SET_POLICY(const IPT_CHAINLABEL chain
,
2429 const IPT_CHAINLABEL policy
,
2430 STRUCT_COUNTERS
*counters
,
2431 struct xtc_handle
*handle
)
2433 struct chain_head
*c
;
2435 iptc_fn
= TC_SET_POLICY
;
2437 if (!(c
= iptcc_find_label(chain
, handle
))) {
2438 DEBUGP("cannot find chain `%s'\n", chain
);
2443 if (!iptcc_is_builtin(c
)) {
2444 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain
);
2449 if (strcmp(policy
, LABEL_ACCEPT
) == 0)
2450 c
->verdict
= -NF_ACCEPT
- 1;
2451 else if (strcmp(policy
, LABEL_DROP
) == 0)
2452 c
->verdict
= -NF_DROP
- 1;
2459 /* set byte and packet counters */
2460 memcpy(&c
->counters
, counters
, sizeof(STRUCT_COUNTERS
));
2461 c
->counter_map
.maptype
= COUNTER_MAP_SET
;
2463 c
->counter_map
.maptype
= COUNTER_MAP_NOMAP
;
2466 set_changed(handle
);
2471 /* Without this, on gcc 2.7.2.3, we get:
2472 libiptc.c: In function `TC_COMMIT':
2473 libiptc.c:833: fixed or forbidden register was spilled.
2474 This may be due to a compiler bug or to impossible asm
2475 statements or clauses.
2478 subtract_counters(STRUCT_COUNTERS
*answer
,
2479 const STRUCT_COUNTERS
*a
,
2480 const STRUCT_COUNTERS
*b
)
2482 answer
->pcnt
= a
->pcnt
- b
->pcnt
;
2483 answer
->bcnt
= a
->bcnt
- b
->bcnt
;
2487 static void counters_nomap(STRUCT_COUNTERS_INFO
*newcounters
, unsigned int idx
)
2489 newcounters
->counters
[idx
] = ((STRUCT_COUNTERS
) { 0, 0});
2490 DEBUGP_C("NOMAP => zero\n");
2493 static void counters_normal_map(STRUCT_COUNTERS_INFO
*newcounters
,
2494 STRUCT_REPLACE
*repl
, unsigned int idx
,
2495 unsigned int mappos
)
2497 /* Original read: X.
2498 * Atomic read on replacement: X + Y.
2499 * Currently in kernel: Z.
2500 * Want in kernel: X + Y + Z.
2502 * => Add in replacement read.
2504 newcounters
->counters
[idx
] = repl
->counters
[mappos
];
2505 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos
);
2508 static void counters_map_zeroed(STRUCT_COUNTERS_INFO
*newcounters
,
2509 STRUCT_REPLACE
*repl
, unsigned int idx
,
2510 unsigned int mappos
, STRUCT_COUNTERS
*counters
)
2512 /* Original read: X.
2513 * Atomic read on replacement: X + Y.
2514 * Currently in kernel: Z.
2515 * Want in kernel: Y + Z.
2517 * => Add in (replacement read - original read).
2519 subtract_counters(&newcounters
->counters
[idx
],
2520 &repl
->counters
[mappos
],
2522 DEBUGP_C("ZEROED => mappos %u\n", mappos
);
2525 static void counters_map_set(STRUCT_COUNTERS_INFO
*newcounters
,
2526 unsigned int idx
, STRUCT_COUNTERS
*counters
)
2528 /* Want to set counter (iptables-restore) */
2530 memcpy(&newcounters
->counters
[idx
], counters
,
2531 sizeof(STRUCT_COUNTERS
));
2538 TC_COMMIT(struct xtc_handle
*handle
)
2540 /* Replace, then map back the counters. */
2541 STRUCT_REPLACE
*repl
;
2542 STRUCT_COUNTERS_INFO
*newcounters
;
2543 struct chain_head
*c
;
2547 unsigned int new_size
;
2549 iptc_fn
= TC_COMMIT
;
2552 /* Don't commit if nothing changed. */
2553 if (!handle
->changed
)
2556 new_number
= iptcc_compile_table_prep(handle
, &new_size
);
2557 if (new_number
< 0) {
2562 repl
= malloc(sizeof(*repl
) + new_size
);
2567 memset(repl
, 0, sizeof(*repl
) + new_size
);
2570 TC_DUMP_ENTRIES(*handle
);
2573 counterlen
= sizeof(STRUCT_COUNTERS_INFO
)
2574 + sizeof(STRUCT_COUNTERS
) * new_number
;
2576 /* These are the old counters we will get from kernel */
2577 repl
->counters
= malloc(sizeof(STRUCT_COUNTERS
)
2578 * handle
->info
.num_entries
);
2579 if (!repl
->counters
) {
2583 /* These are the counters we're going to put back, later. */
2584 newcounters
= malloc(counterlen
);
2587 goto out_free_repl_counters
;
2589 memset(newcounters
, 0, counterlen
);
2591 strcpy(repl
->name
, handle
->info
.name
);
2592 repl
->num_entries
= new_number
;
2593 repl
->size
= new_size
;
2595 repl
->num_counters
= handle
->info
.num_entries
;
2596 repl
->valid_hooks
= handle
->info
.valid_hooks
;
2598 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2599 repl
->num_entries
, repl
->size
, repl
->num_counters
);
2601 ret
= iptcc_compile_table(handle
, repl
);
2604 goto out_free_newcounters
;
2610 int fd
= open("/tmp/libiptc-so_set_replace.blob",
2613 write(fd
, repl
, sizeof(*repl
) + repl
->size
);
2619 ret
= setsockopt(handle
->sockfd
, TC_IPPROTO
, SO_SET_REPLACE
, repl
,
2620 sizeof(*repl
) + repl
->size
);
2622 goto out_free_newcounters
;
2624 /* Put counters back. */
2625 strcpy(newcounters
->name
, handle
->info
.name
);
2626 newcounters
->num_counters
= new_number
;
2628 list_for_each_entry(c
, &handle
->chains
, list
) {
2629 struct rule_head
*r
;
2631 /* Builtin chains have their own counters */
2632 if (iptcc_is_builtin(c
)) {
2633 DEBUGP("counter for chain-index %u: ", c
->foot_index
);
2634 switch(c
->counter_map
.maptype
) {
2635 case COUNTER_MAP_NOMAP
:
2636 counters_nomap(newcounters
, c
->foot_index
);
2638 case COUNTER_MAP_NORMAL_MAP
:
2639 counters_normal_map(newcounters
, repl
,
2641 c
->counter_map
.mappos
);
2643 case COUNTER_MAP_ZEROED
:
2644 counters_map_zeroed(newcounters
, repl
,
2646 c
->counter_map
.mappos
,
2649 case COUNTER_MAP_SET
:
2650 counters_map_set(newcounters
, c
->foot_index
,
2656 list_for_each_entry(r
, &c
->rules
, list
) {
2657 DEBUGP("counter for index %u: ", r
->index
);
2658 switch (r
->counter_map
.maptype
) {
2659 case COUNTER_MAP_NOMAP
:
2660 counters_nomap(newcounters
, r
->index
);
2663 case COUNTER_MAP_NORMAL_MAP
:
2664 counters_normal_map(newcounters
, repl
,
2666 r
->counter_map
.mappos
);
2669 case COUNTER_MAP_ZEROED
:
2670 counters_map_zeroed(newcounters
, repl
,
2672 r
->counter_map
.mappos
,
2673 &r
->entry
->counters
);
2676 case COUNTER_MAP_SET
:
2677 counters_map_set(newcounters
, r
->index
,
2678 &r
->entry
->counters
);
2686 int fd
= open("/tmp/libiptc-so_set_add_counters.blob",
2689 write(fd
, newcounters
, counterlen
);
2695 ret
= setsockopt(handle
->sockfd
, TC_IPPROTO
, SO_SET_ADD_COUNTERS
,
2696 newcounters
, counterlen
);
2698 goto out_free_newcounters
;
2700 free(repl
->counters
);
2707 out_free_newcounters
:
2709 out_free_repl_counters
:
2710 free(repl
->counters
);
2717 /* Translates errno numbers into more human-readable form than strerror. */
2719 TC_STRERROR(int err
)
2722 struct table_struct
{
2725 const char *message
;
2727 { { TC_INIT
, EPERM
, "Permission denied (you must be root)" },
2728 { TC_INIT
, EINVAL
, "Module is wrong version" },
2730 "Table does not exist (do you need to insmod?)" },
2731 { TC_DELETE_CHAIN
, ENOTEMPTY
, "Chain is not empty" },
2732 { TC_DELETE_CHAIN
, EINVAL
, "Can't delete built-in chain" },
2733 { TC_DELETE_CHAIN
, EMLINK
,
2734 "Can't delete chain with references left" },
2735 { TC_CREATE_CHAIN
, EEXIST
, "Chain already exists" },
2736 { TC_INSERT_ENTRY
, E2BIG
, "Index of insertion too big" },
2737 { TC_REPLACE_ENTRY
, E2BIG
, "Index of replacement too big" },
2738 { TC_DELETE_NUM_ENTRY
, E2BIG
, "Index of deletion too big" },
2739 { TC_READ_COUNTER
, E2BIG
, "Index of counter too big" },
2740 { TC_ZERO_COUNTER
, E2BIG
, "Index of counter too big" },
2741 { TC_INSERT_ENTRY
, ELOOP
, "Loop found in table" },
2742 { TC_INSERT_ENTRY
, EINVAL
, "Target problem" },
2743 /* ENOENT for DELETE probably means no matching rule */
2744 { TC_DELETE_ENTRY
, ENOENT
,
2745 "Bad rule (does a matching rule exist in that chain?)" },
2746 { TC_SET_POLICY
, ENOENT
,
2747 "Bad built-in chain name" },
2748 { TC_SET_POLICY
, EINVAL
,
2749 "Bad policy name" },
2751 { NULL
, 0, "Incompatible with this kernel" },
2752 { NULL
, ENOPROTOOPT
, "iptables who? (do you need to insmod?)" },
2753 { NULL
, ENOSYS
, "Will be implemented real soon. I promise ;)" },
2754 { NULL
, ENOMEM
, "Memory allocation problem" },
2755 { NULL
, ENOENT
, "No chain/target/match by that name" },
2758 for (i
= 0; i
< sizeof(table
)/sizeof(struct table_struct
); i
++) {
2759 if ((!table
[i
].fn
|| table
[i
].fn
== iptc_fn
)
2760 && table
[i
].err
== err
)
2761 return table
[i
].message
;
2764 return strerror(err
);