1 /* Library which manipulates firewall rules. Version $Revision: 6665 $ */
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 * - futher performance work: total reimplementation of libiptc.
23 * - libiptc now has a real internal (linked-list) represntation of the
24 * ruleset and a parser/compiler from/to this internal representation
25 * - again sponsored by Astaro AG (http://www.astaro.com/)
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include "linux_list.h"
32 //#define IPTC_DEBUG2 1
36 #define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
37 #define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
39 #define DEBUGP(x, args...)
40 #define DEBUGP_C(x, args...)
44 #define IPT_LIB_DIR "/usr/local/lib/iptables"
47 static int sockfd
= -1;
48 static int sockfd_use
= 0;
49 static void *iptc_fn
= NULL
;
51 static const char *hooknames
[]
52 = { [HOOK_PRE_ROUTING
] "PREROUTING",
53 [HOOK_LOCAL_IN
] "INPUT",
54 [HOOK_FORWARD
] "FORWARD",
55 [HOOK_LOCAL_OUT
] "OUTPUT",
56 [HOOK_POST_ROUTING
] "POSTROUTING",
58 [HOOK_DROPPING
] "DROPPING"
62 /* Convenience structures */
63 struct ipt_error_target
65 STRUCT_ENTRY_TARGET t
;
66 char error
[TABLE_MAXNAMELEN
];
76 COUNTER_MAP_NORMAL_MAP
,
83 enum iptcc_rule_type
{
84 IPTCC_R_STANDARD
, /* standard target (ACCEPT, ...) */
85 IPTCC_R_MODULE
, /* extension module (SNAT, ...) */
86 IPTCC_R_FALLTHROUGH
, /* fallthrough rule */
87 IPTCC_R_JUMP
, /* jump to other chain */
92 struct list_head list
;
93 struct chain_head
*chain
;
94 struct counter_map counter_map
;
96 unsigned int index
; /* index (needed for counter_map) */
97 unsigned int offset
; /* offset in rule blob */
99 enum iptcc_rule_type type
;
100 struct chain_head
*jump
; /* jump target, if IPTCC_R_JUMP */
102 unsigned int size
; /* size of entry data */
103 STRUCT_ENTRY entry
[0];
108 struct list_head list
;
109 char name
[TABLE_MAXNAMELEN
];
110 unsigned int hooknum
; /* hook number+1 if builtin */
111 unsigned int references
; /* how many jumps reference us */
112 int verdict
; /* verdict if builtin */
114 STRUCT_COUNTERS counters
; /* per-chain counters */
115 struct counter_map counter_map
;
117 unsigned int num_rules
; /* number of rules in list */
118 struct list_head rules
; /* list of rules */
120 unsigned int index
; /* index (needed for jump resolval) */
121 unsigned int head_offset
; /* offset in rule blob */
122 unsigned int foot_index
; /* index (needed for counter_map) */
123 unsigned int foot_offset
; /* offset in rule blob */
128 int changed
; /* Have changes been made? */
130 struct list_head chains
;
132 struct chain_head
*chain_iterator_cur
;
133 struct rule_head
*rule_iterator_cur
;
136 STRUCT_GET_ENTRIES
*entries
;
139 /* allocate a new chain head for the cache */
140 static struct chain_head
*iptcc_alloc_chain_head(const char *name
, int hooknum
)
142 struct chain_head
*c
= malloc(sizeof(*c
));
145 memset(c
, 0, sizeof(*c
));
147 strncpy(c
->name
, name
, TABLE_MAXNAMELEN
);
148 c
->hooknum
= hooknum
;
149 INIT_LIST_HEAD(&c
->rules
);
154 /* allocate and initialize a new rule for the cache */
155 static struct rule_head
*iptcc_alloc_rule(struct chain_head
*c
, unsigned int size
)
157 struct rule_head
*r
= malloc(sizeof(*r
)+size
);
160 memset(r
, 0, sizeof(*r
));
168 /* notify us that the ruleset has been modified by the user */
170 set_changed(TC_HANDLE_T h
)
176 static void do_check(TC_HANDLE_T h
, unsigned int line
);
177 #define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
183 /**********************************************************************
184 * iptc blob utility functions (iptcb_*)
185 **********************************************************************/
188 iptcb_get_number(const STRUCT_ENTRY
*i
,
189 const STRUCT_ENTRY
*seek
,
199 iptcb_get_entry_n(STRUCT_ENTRY
*i
,
204 if (*pos
== number
) {
212 static inline STRUCT_ENTRY
*
213 iptcb_get_entry(TC_HANDLE_T h
, unsigned int offset
)
215 return (STRUCT_ENTRY
*)((char *)h
->entries
->entrytable
+ offset
);
219 iptcb_entry2index(const TC_HANDLE_T h
, const STRUCT_ENTRY
*seek
)
221 unsigned int pos
= 0;
223 if (ENTRY_ITERATE(h
->entries
->entrytable
, h
->entries
->size
,
224 iptcb_get_number
, seek
, &pos
) == 0) {
225 fprintf(stderr
, "ERROR: offset %u not an entry!\n",
226 (unsigned int)((char *)seek
- (char *)h
->entries
->entrytable
));
232 static inline STRUCT_ENTRY
*
233 iptcb_offset2entry(TC_HANDLE_T h
, unsigned int offset
)
235 return (STRUCT_ENTRY
*) ((void *)h
->entries
->entrytable
+offset
);
239 static inline unsigned long
240 iptcb_entry2offset(const TC_HANDLE_T h
, const STRUCT_ENTRY
*e
)
242 return (void *)e
- (void *)h
->entries
->entrytable
;
245 static inline unsigned int
246 iptcb_offset2index(const TC_HANDLE_T h
, unsigned int offset
)
248 return iptcb_entry2index(h
, iptcb_offset2entry(h
, offset
));
251 /* Returns 0 if not hook entry, else hooknumber + 1 */
252 static inline unsigned int
253 iptcb_ent_is_hook_entry(STRUCT_ENTRY
*e
, TC_HANDLE_T h
)
257 for (i
= 0; i
< NUMHOOKS
; i
++) {
258 if ((h
->info
.valid_hooks
& (1 << i
))
259 && iptcb_get_entry(h
, h
->info
.hook_entry
[i
]) == e
)
266 /**********************************************************************
267 * iptc cache utility functions (iptcc_*)
268 **********************************************************************/
270 /* Is the given chain builtin (1) or user-defined (0) */
271 static unsigned int iptcc_is_builtin(struct chain_head
*c
)
273 return (c
->hooknum
? 1 : 0);
276 /* Get a specific rule within a chain */
277 static struct rule_head
*iptcc_get_rule_num(struct chain_head
*c
,
278 unsigned int rulenum
)
281 unsigned int num
= 0;
283 list_for_each_entry(r
, &c
->rules
, list
) {
291 /* Get a specific rule within a chain backwards */
292 static struct rule_head
*iptcc_get_rule_num_reverse(struct chain_head
*c
,
293 unsigned int rulenum
)
296 unsigned int num
= 0;
298 list_for_each_entry_reverse(r
, &c
->rules
, list
) {
306 /* Returns chain head if found, otherwise NULL. */
307 static struct chain_head
*
308 iptcc_find_chain_by_offset(TC_HANDLE_T handle
, unsigned int offset
)
310 struct list_head
*pos
;
312 if (list_empty(&handle
->chains
))
315 list_for_each(pos
, &handle
->chains
) {
316 struct chain_head
*c
= list_entry(pos
, struct chain_head
, list
);
317 if (offset
>= c
->head_offset
&& offset
<= c
->foot_offset
)
323 /* Returns chain head if found, otherwise NULL. */
324 static struct chain_head
*
325 iptcc_find_label(const char *name
, TC_HANDLE_T handle
)
327 struct list_head
*pos
;
329 if (list_empty(&handle
->chains
))
332 list_for_each(pos
, &handle
->chains
) {
333 struct chain_head
*c
= list_entry(pos
, struct chain_head
, list
);
334 if (!strcmp(c
->name
, name
))
341 /* called when rule is to be removed from cache */
342 static void iptcc_delete_rule(struct rule_head
*r
)
344 DEBUGP("deleting rule %p (offset %u)\n", r
, r
->offset
);
345 /* clean up reference count of called chain */
346 if (r
->type
== IPTCC_R_JUMP
348 r
->jump
->references
--;
355 /**********************************************************************
356 * RULESET PARSER (blob -> cache)
357 **********************************************************************/
359 /* Delete policy rule of previous chain, since cache doesn't contain
360 * chain policy rules.
361 * WARNING: This function has ugly design and relies on a lot of context, only
362 * to be called from specific places within the parser */
363 static int __iptcc_p_del_policy(TC_HANDLE_T h
, unsigned int num
)
365 if (h
->chain_iterator_cur
) {
366 /* policy rule is last rule */
367 struct rule_head
*pr
= (struct rule_head
*)
368 h
->chain_iterator_cur
->rules
.prev
;
371 h
->chain_iterator_cur
->verdict
=
372 *(int *)GET_TARGET(pr
->entry
)->data
;
374 /* save counter and counter_map information */
375 h
->chain_iterator_cur
->counter_map
.maptype
=
376 COUNTER_MAP_NORMAL_MAP
;
377 h
->chain_iterator_cur
->counter_map
.mappos
= num
-1;
378 memcpy(&h
->chain_iterator_cur
->counters
, &pr
->entry
->counters
,
379 sizeof(h
->chain_iterator_cur
->counters
));
381 /* foot_offset points to verdict rule */
382 h
->chain_iterator_cur
->foot_index
= num
;
383 h
->chain_iterator_cur
->foot_offset
= pr
->offset
;
385 /* delete rule from cache */
386 iptcc_delete_rule(pr
);
387 h
->chain_iterator_cur
->num_rules
--;
394 /* alphabetically insert a chain into the list */
395 static inline void iptc_insert_chain(TC_HANDLE_T h
, struct chain_head
*c
)
397 struct chain_head
*tmp
;
399 /* sort only user defined chains */
401 list_for_each_entry(tmp
, &h
->chains
, list
) {
402 if (!tmp
->hooknum
&& strcmp(c
->name
, tmp
->name
) <= 0) {
403 list_add(&c
->list
, tmp
->list
.prev
);
409 /* survived till end of list: add at tail */
410 list_add_tail(&c
->list
, &h
->chains
);
413 /* Another ugly helper function split out of cache_add_entry to make it less
415 static void __iptcc_p_add_chain(TC_HANDLE_T h
, struct chain_head
*c
,
416 unsigned int offset
, unsigned int *num
)
418 __iptcc_p_del_policy(h
, *num
);
420 c
->head_offset
= offset
;
423 iptc_insert_chain(h
, c
);
425 h
->chain_iterator_cur
= c
;
428 /* main parser function: add an entry from the blob to the cache */
429 static int cache_add_entry(STRUCT_ENTRY
*e
,
434 unsigned int builtin
;
435 unsigned int offset
= (char *)e
- (char *)h
->entries
->entrytable
;
437 DEBUGP("entering...");
439 /* Last entry ("policy rule"). End it.*/
440 if (iptcb_entry2offset(h
,e
) + e
->next_offset
== h
->entries
->size
) {
441 /* This is the ERROR node at the end of the chain */
442 DEBUGP_C("%u:%u: end of table:\n", *num
, offset
);
444 __iptcc_p_del_policy(h
, *num
);
446 h
->chain_iterator_cur
= NULL
;
450 /* We know this is the start of a new chain if it's an ERROR
451 * target, or a hook entry point */
453 if (strcmp(GET_TARGET(e
)->u
.user
.name
, ERROR_TARGET
) == 0) {
454 struct chain_head
*c
=
455 iptcc_alloc_chain_head((const char *)GET_TARGET(e
)->data
, 0);
456 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num
, offset
,
463 __iptcc_p_add_chain(h
, c
, offset
, num
);
465 } else if ((builtin
= iptcb_ent_is_hook_entry(e
, h
)) != 0) {
466 struct chain_head
*c
=
467 iptcc_alloc_chain_head((char *)hooknames
[builtin
-1],
469 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
470 *num
, offset
, c
, &c
->rules
);
476 c
->hooknum
= builtin
;
478 __iptcc_p_add_chain(h
, c
, offset
, num
);
480 /* FIXME: this is ugly. */
483 /* has to be normal rule */
487 if (!(r
= iptcc_alloc_rule(h
->chain_iterator_cur
,
492 DEBUGP_C("%u:%u normal rule: %p: ", *num
, offset
, r
);
496 memcpy(r
->entry
, e
, e
->next_offset
);
497 r
->counter_map
.maptype
= COUNTER_MAP_NORMAL_MAP
;
498 r
->counter_map
.mappos
= r
->index
;
500 /* handling of jumps, etc. */
501 if (!strcmp(GET_TARGET(e
)->u
.user
.name
, STANDARD_TARGET
)) {
502 STRUCT_STANDARD_TARGET
*t
;
504 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(e
);
505 if (t
->target
.u
.target_size
506 != ALIGN(sizeof(STRUCT_STANDARD_TARGET
))) {
511 if (t
->verdict
< 0) {
512 DEBUGP_C("standard, verdict=%d\n", t
->verdict
);
513 r
->type
= IPTCC_R_STANDARD
;
514 } else if (t
->verdict
== r
->offset
+e
->next_offset
) {
515 DEBUGP_C("fallthrough\n");
516 r
->type
= IPTCC_R_FALLTHROUGH
;
518 DEBUGP_C("jump, target=%u\n", t
->verdict
);
519 r
->type
= IPTCC_R_JUMP
;
520 /* Jump target fixup has to be deferred
521 * until second pass, since we migh not
522 * yet have parsed the target */
525 DEBUGP_C("module, target=%s\n", GET_TARGET(e
)->u
.user
.name
);
526 r
->type
= IPTCC_R_MODULE
;
529 list_add_tail(&r
->list
, &h
->chain_iterator_cur
->rules
);
530 h
->chain_iterator_cur
->num_rules
++;
538 /* parse an iptables blob into it's pieces */
539 static int parse_table(TC_HANDLE_T h
)
542 unsigned int num
= 0;
543 struct chain_head
*c
;
545 /* First pass: over ruleset blob */
546 ENTRY_ITERATE(h
->entries
->entrytable
, h
->entries
->size
,
547 cache_add_entry
, h
, &prev
, &num
);
549 /* Second pass: fixup parsed data from first pass */
550 list_for_each_entry(c
, &h
->chains
, list
) {
552 list_for_each_entry(r
, &c
->rules
, list
) {
553 struct chain_head
*c
;
554 STRUCT_STANDARD_TARGET
*t
;
556 if (r
->type
!= IPTCC_R_JUMP
)
559 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
560 c
= iptcc_find_chain_by_offset(h
, t
->verdict
);
568 /* FIXME: sort chains */
574 /**********************************************************************
575 * RULESET COMPILATION (cache -> blob)
576 **********************************************************************/
578 /* Convenience structures */
579 struct iptcb_chain_start
{
581 struct ipt_error_target name
;
583 #define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
584 ALIGN(sizeof(struct ipt_error_target)))
586 struct iptcb_chain_foot
{
588 STRUCT_STANDARD_TARGET target
;
590 #define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
591 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
593 struct iptcb_chain_error
{
595 struct ipt_error_target target
;
597 #define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
598 ALIGN(sizeof(struct ipt_error_target)))
602 /* compile rule from cache into blob */
603 static inline int iptcc_compile_rule (TC_HANDLE_T h
, STRUCT_REPLACE
*repl
, struct rule_head
*r
)
606 if (r
->type
== IPTCC_R_JUMP
) {
607 STRUCT_STANDARD_TARGET
*t
;
608 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
609 /* memset for memcmp convenience on delete/replace */
610 memset(t
->target
.u
.user
.name
, 0, FUNCTION_MAXNAMELEN
);
611 strcpy(t
->target
.u
.user
.name
, STANDARD_TARGET
);
612 /* Jumps can only happen to builtin chains, so we
613 * can safely assume that they always have a header */
614 t
->verdict
= r
->jump
->head_offset
+ IPTCB_CHAIN_START_SIZE
;
615 } else if (r
->type
== IPTCC_R_FALLTHROUGH
) {
616 STRUCT_STANDARD_TARGET
*t
;
617 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(r
->entry
);
618 t
->verdict
= r
->offset
+ r
->size
;
621 /* copy entry from cache to blob */
622 memcpy((char *)repl
->entries
+r
->offset
, r
->entry
, r
->size
);
627 /* compile chain from cache into blob */
628 static int iptcc_compile_chain(TC_HANDLE_T h
, STRUCT_REPLACE
*repl
, struct chain_head
*c
)
632 struct iptcb_chain_start
*head
;
633 struct iptcb_chain_foot
*foot
;
635 /* only user-defined chains have heaer */
636 if (!iptcc_is_builtin(c
)) {
637 /* put chain header in place */
638 head
= (void *)repl
->entries
+ c
->head_offset
;
639 head
->e
.target_offset
= sizeof(STRUCT_ENTRY
);
640 head
->e
.next_offset
= IPTCB_CHAIN_START_SIZE
;
641 strcpy(head
->name
.t
.u
.user
.name
, ERROR_TARGET
);
642 head
->name
.t
.u
.target_size
=
643 ALIGN(sizeof(struct ipt_error_target
));
644 strcpy(head
->name
.error
, c
->name
);
646 repl
->hook_entry
[c
->hooknum
-1] = c
->head_offset
;
647 repl
->underflow
[c
->hooknum
-1] = c
->foot_offset
;
650 /* iterate over rules */
651 list_for_each_entry(r
, &c
->rules
, list
) {
652 ret
= iptcc_compile_rule(h
, repl
, r
);
657 /* put chain footer in place */
658 foot
= (void *)repl
->entries
+ c
->foot_offset
;
659 foot
->e
.target_offset
= sizeof(STRUCT_ENTRY
);
660 foot
->e
.next_offset
= IPTCB_CHAIN_FOOT_SIZE
;
661 strcpy(foot
->target
.target
.u
.user
.name
, STANDARD_TARGET
);
662 foot
->target
.target
.u
.target_size
=
663 ALIGN(sizeof(STRUCT_STANDARD_TARGET
));
664 /* builtin targets have verdict, others return */
665 if (iptcc_is_builtin(c
))
666 foot
->target
.verdict
= c
->verdict
;
668 foot
->target
.verdict
= RETURN
;
669 /* set policy-counters */
670 memcpy(&foot
->e
.counters
, &c
->counters
, sizeof(STRUCT_COUNTERS
));
675 /* calculate offset and number for every rule in the cache */
676 static int iptcc_compile_chain_offsets(TC_HANDLE_T h
, struct chain_head
*c
,
677 unsigned int *offset
, unsigned int *num
)
681 c
->head_offset
= *offset
;
682 DEBUGP("%s: chain_head %u, offset=%u\n", c
->name
, *num
, *offset
);
684 if (!iptcc_is_builtin(c
)) {
685 /* Chain has header */
686 *offset
+= sizeof(STRUCT_ENTRY
)
687 + ALIGN(sizeof(struct ipt_error_target
));
691 list_for_each_entry(r
, &c
->rules
, list
) {
692 DEBUGP("rule %u, offset=%u, index=%u\n", *num
, *offset
, *num
);
699 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c
->name
, *num
,
701 c
->foot_offset
= *offset
;
702 c
->foot_index
= *num
;
703 *offset
+= sizeof(STRUCT_ENTRY
)
704 + ALIGN(sizeof(STRUCT_STANDARD_TARGET
));
710 /* put the pieces back together again */
711 static int iptcc_compile_table_prep(TC_HANDLE_T h
, unsigned int *size
)
713 struct chain_head
*c
;
714 unsigned int offset
= 0, num
= 0;
717 /* First pass: calculate offset for every rule */
718 list_for_each_entry(c
, &h
->chains
, list
) {
719 ret
= iptcc_compile_chain_offsets(h
, c
, &offset
, &num
);
724 /* Append one error rule at end of chain */
726 offset
+= sizeof(STRUCT_ENTRY
)
727 + ALIGN(sizeof(struct ipt_error_target
));
729 /* ruleset size is now in offset */
734 static int iptcc_compile_table(TC_HANDLE_T h
, STRUCT_REPLACE
*repl
)
736 struct chain_head
*c
;
737 struct iptcb_chain_error
*error
;
739 /* Second pass: copy from cache to offsets, fill in jumps */
740 list_for_each_entry(c
, &h
->chains
, list
) {
741 int ret
= iptcc_compile_chain(h
, repl
, c
);
746 /* Append error rule at end of chain */
747 error
= (void *)repl
->entries
+ repl
->size
- IPTCB_CHAIN_ERROR_SIZE
;
748 error
->entry
.target_offset
= sizeof(STRUCT_ENTRY
);
749 error
->entry
.next_offset
= IPTCB_CHAIN_ERROR_SIZE
;
750 error
->target
.t
.u
.user
.target_size
=
751 ALIGN(sizeof(struct ipt_error_target
));
752 strcpy((char *)&error
->target
.t
.u
.user
.name
, ERROR_TARGET
);
753 strcpy((char *)&error
->target
.error
, "ERROR");
758 /**********************************************************************
759 * EXTERNAL API (operates on cache only)
760 **********************************************************************/
762 /* Allocate handle of given size */
764 alloc_handle(const char *tablename
, unsigned int size
, unsigned int num_rules
)
769 len
= sizeof(STRUCT_TC_HANDLE
) + size
;
771 h
= malloc(sizeof(STRUCT_TC_HANDLE
));
776 memset(h
, 0, sizeof(*h
));
777 INIT_LIST_HEAD(&h
->chains
);
778 strcpy(h
->info
.name
, tablename
);
780 h
->entries
= malloc(sizeof(STRUCT_GET_ENTRIES
) + size
);
782 goto out_free_handle
;
784 strcpy(h
->entries
->name
, tablename
);
785 h
->entries
->size
= size
;
797 TC_INIT(const char *tablename
)
806 if (strlen(tablename
) >= TABLE_MAXNAMELEN
) {
811 if (sockfd_use
== 0) {
812 sockfd
= socket(TC_AF
, SOCK_RAW
, IPPROTO_RAW
);
820 strcpy(info
.name
, tablename
);
821 if (getsockopt(sockfd
, TC_IPPROTO
, SO_GET_INFO
, &info
, &s
) < 0) {
822 if (--sockfd_use
== 0) {
829 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
830 info
.valid_hooks
, info
.num_entries
, info
.size
);
832 if ((h
= alloc_handle(info
.name
, info
.size
, info
.num_entries
))
834 if (--sockfd_use
== 0) {
841 /* Initialize current state */
844 h
->entries
->size
= h
->info
.size
;
846 tmp
= sizeof(STRUCT_GET_ENTRIES
) + h
->info
.size
;
848 if (getsockopt(sockfd
, TC_IPPROTO
, SO_GET_ENTRIES
, h
->entries
,
854 int fd
= open("/tmp/libiptc-so_get_entries.blob",
857 write(fd
, h
->entries
, tmp
);
863 if (parse_table(h
) < 0)
869 if (--sockfd_use
== 0) {
878 TC_FREE(TC_HANDLE_T
*h
)
880 struct chain_head
*c
, *tmp
;
883 if (--sockfd_use
== 0) {
888 list_for_each_entry_safe(c
, tmp
, &(*h
)->chains
, list
) {
889 struct rule_head
*r
, *rtmp
;
891 list_for_each_entry_safe(r
, rtmp
, &c
->rules
, list
) {
905 print_match(const STRUCT_ENTRY_MATCH
*m
)
907 printf("Match name: `%s'\n", m
->u
.user
.name
);
912 static int dump_entry(STRUCT_ENTRY
*e
, const TC_HANDLE_T handle
);
916 TC_DUMP_ENTRIES(const TC_HANDLE_T handle
)
918 iptc_fn
= TC_DUMP_ENTRIES
;
921 printf("libiptc v%s. %u bytes.\n",
922 IPTABLES_VERSION
, handle
->entries
->size
);
923 printf("Table `%s'\n", handle
->info
.name
);
924 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
925 handle
->info
.hook_entry
[HOOK_PRE_ROUTING
],
926 handle
->info
.hook_entry
[HOOK_LOCAL_IN
],
927 handle
->info
.hook_entry
[HOOK_FORWARD
],
928 handle
->info
.hook_entry
[HOOK_LOCAL_OUT
],
929 handle
->info
.hook_entry
[HOOK_POST_ROUTING
]);
930 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
931 handle
->info
.underflow
[HOOK_PRE_ROUTING
],
932 handle
->info
.underflow
[HOOK_LOCAL_IN
],
933 handle
->info
.underflow
[HOOK_FORWARD
],
934 handle
->info
.underflow
[HOOK_LOCAL_OUT
],
935 handle
->info
.underflow
[HOOK_POST_ROUTING
]);
937 ENTRY_ITERATE(handle
->entries
->entrytable
, handle
->entries
->size
,
942 /* Does this chain exist? */
943 int TC_IS_CHAIN(const char *chain
, const TC_HANDLE_T handle
)
945 iptc_fn
= TC_IS_CHAIN
;
946 return iptcc_find_label(chain
, handle
) != NULL
;
949 static void iptcc_chain_iterator_advance(TC_HANDLE_T handle
)
951 struct chain_head
*c
= handle
->chain_iterator_cur
;
953 if (c
->list
.next
== &handle
->chains
)
954 handle
->chain_iterator_cur
= NULL
;
956 handle
->chain_iterator_cur
=
957 list_entry(c
->list
.next
, struct chain_head
, list
);
960 /* Iterator functions to run through the chains. */
962 TC_FIRST_CHAIN(TC_HANDLE_T
*handle
)
964 struct chain_head
*c
= list_entry((*handle
)->chains
.next
,
965 struct chain_head
, list
);
967 iptc_fn
= TC_FIRST_CHAIN
;
970 if (list_empty(&(*handle
)->chains
)) {
971 DEBUGP(": no chains\n");
975 (*handle
)->chain_iterator_cur
= c
;
976 iptcc_chain_iterator_advance(*handle
);
978 DEBUGP(": returning `%s'\n", c
->name
);
982 /* Iterator functions to run through the chains. Returns NULL at end. */
984 TC_NEXT_CHAIN(TC_HANDLE_T
*handle
)
986 struct chain_head
*c
= (*handle
)->chain_iterator_cur
;
988 iptc_fn
= TC_NEXT_CHAIN
;
991 DEBUGP(": no more chains\n");
995 iptcc_chain_iterator_advance(*handle
);
997 DEBUGP(": returning `%s'\n", c
->name
);
1001 /* Get first rule in the given chain: NULL for empty chain. */
1002 const STRUCT_ENTRY
*
1003 TC_FIRST_RULE(const char *chain
, TC_HANDLE_T
*handle
)
1005 struct chain_head
*c
;
1006 struct rule_head
*r
;
1008 iptc_fn
= TC_FIRST_RULE
;
1010 DEBUGP("first rule(%s): ", chain
);
1012 c
= iptcc_find_label(chain
, *handle
);
1018 /* Empty chain: single return/policy rule */
1019 if (list_empty(&c
->rules
)) {
1020 DEBUGP_C("no rules, returning NULL\n");
1024 r
= list_entry(c
->rules
.next
, struct rule_head
, list
);
1025 (*handle
)->rule_iterator_cur
= r
;
1026 DEBUGP_C("%p\n", r
);
1031 /* Returns NULL when rules run out. */
1032 const STRUCT_ENTRY
*
1033 TC_NEXT_RULE(const STRUCT_ENTRY
*prev
, TC_HANDLE_T
*handle
)
1035 struct rule_head
*r
;
1037 iptc_fn
= TC_NEXT_RULE
;
1038 DEBUGP("rule_iterator_cur=%p...", (*handle
)->rule_iterator_cur
);
1040 if (!(*handle
)->rule_iterator_cur
) {
1041 DEBUGP_C("returning NULL\n");
1045 r
= list_entry((*handle
)->rule_iterator_cur
->list
.next
,
1046 struct rule_head
, list
);
1048 iptc_fn
= TC_NEXT_RULE
;
1050 DEBUGP_C("next=%p, head=%p...", &r
->list
,
1051 &(*handle
)->rule_iterator_cur
->chain
->rules
);
1053 if (&r
->list
== &(*handle
)->rule_iterator_cur
->chain
->rules
) {
1054 (*handle
)->rule_iterator_cur
= NULL
;
1055 DEBUGP_C("finished, returning NULL\n");
1059 (*handle
)->rule_iterator_cur
= r
;
1061 /* NOTE: prev is without any influence ! */
1062 DEBUGP_C("returning rule %p\n", r
);
1066 /* How many rules in this chain? */
1068 TC_NUM_RULES(const char *chain
, TC_HANDLE_T
*handle
)
1070 struct chain_head
*c
;
1071 iptc_fn
= TC_NUM_RULES
;
1074 c
= iptcc_find_label(chain
, *handle
);
1077 return (unsigned int)-1;
1080 return c
->num_rules
;
1083 const STRUCT_ENTRY
*TC_GET_RULE(const char *chain
,
1085 TC_HANDLE_T
*handle
)
1087 struct chain_head
*c
;
1088 struct rule_head
*r
;
1090 iptc_fn
= TC_GET_RULE
;
1094 c
= iptcc_find_label(chain
, *handle
);
1100 r
= iptcc_get_rule_num(c
, n
);
1106 /* Returns a pointer to the target name of this position. */
1107 const char *standard_target_map(int verdict
)
1111 return LABEL_RETURN
;
1114 return LABEL_ACCEPT
;
1123 fprintf(stderr
, "ERROR: %d not a valid target)\n",
1132 /* Returns a pointer to the target name of this position. */
1133 const char *TC_GET_TARGET(const STRUCT_ENTRY
*ce
,
1134 TC_HANDLE_T
*handle
)
1136 STRUCT_ENTRY
*e
= (STRUCT_ENTRY
*)ce
;
1137 struct rule_head
*r
= container_of(e
, struct rule_head
, entry
[0]);
1139 iptc_fn
= TC_GET_TARGET
;
1143 case IPTCC_R_FALLTHROUGH
:
1147 DEBUGP("r=%p, jump=%p, name=`%s'\n", r
, r
->jump
, r
->jump
->name
);
1148 return r
->jump
->name
;
1150 case IPTCC_R_STANDARD
:
1151 spos
= *(int *)GET_TARGET(e
)->data
;
1152 DEBUGP("r=%p, spos=%d'\n", r
, spos
);
1153 return standard_target_map(spos
);
1155 case IPTCC_R_MODULE
:
1156 return GET_TARGET(e
)->u
.user
.name
;
1161 /* Is this a built-in chain? Actually returns hook + 1. */
1163 TC_BUILTIN(const char *chain
, const TC_HANDLE_T handle
)
1165 struct chain_head
*c
;
1167 iptc_fn
= TC_BUILTIN
;
1169 c
= iptcc_find_label(chain
, handle
);
1175 return iptcc_is_builtin(c
);
1178 /* Get the policy of a given built-in chain */
1180 TC_GET_POLICY(const char *chain
,
1181 STRUCT_COUNTERS
*counters
,
1182 TC_HANDLE_T
*handle
)
1184 struct chain_head
*c
;
1186 iptc_fn
= TC_GET_POLICY
;
1188 DEBUGP("called for chain %s\n", chain
);
1190 c
= iptcc_find_label(chain
, *handle
);
1196 if (!iptcc_is_builtin(c
))
1199 *counters
= c
->counters
;
1201 return standard_target_map(c
->verdict
);
1205 iptcc_standard_map(struct rule_head
*r
, int verdict
)
1207 STRUCT_ENTRY
*e
= r
->entry
;
1208 STRUCT_STANDARD_TARGET
*t
;
1210 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(e
);
1212 if (t
->target
.u
.target_size
1213 != ALIGN(sizeof(STRUCT_STANDARD_TARGET
))) {
1217 /* memset for memcmp convenience on delete/replace */
1218 memset(t
->target
.u
.user
.name
, 0, FUNCTION_MAXNAMELEN
);
1219 strcpy(t
->target
.u
.user
.name
, STANDARD_TARGET
);
1220 t
->verdict
= verdict
;
1222 r
->type
= IPTCC_R_STANDARD
;
1228 iptcc_map_target(const TC_HANDLE_T handle
,
1229 struct rule_head
*r
)
1231 STRUCT_ENTRY
*e
= r
->entry
;
1232 STRUCT_ENTRY_TARGET
*t
= GET_TARGET(e
);
1234 /* Maybe it's empty (=> fall through) */
1235 if (strcmp(t
->u
.user
.name
, "") == 0) {
1236 r
->type
= IPTCC_R_FALLTHROUGH
;
1239 /* Maybe it's a standard target name... */
1240 else if (strcmp(t
->u
.user
.name
, LABEL_ACCEPT
) == 0)
1241 return iptcc_standard_map(r
, -NF_ACCEPT
- 1);
1242 else if (strcmp(t
->u
.user
.name
, LABEL_DROP
) == 0)
1243 return iptcc_standard_map(r
, -NF_DROP
- 1);
1244 else if (strcmp(t
->u
.user
.name
, LABEL_QUEUE
) == 0)
1245 return iptcc_standard_map(r
, -NF_QUEUE
- 1);
1246 else if (strcmp(t
->u
.user
.name
, LABEL_RETURN
) == 0)
1247 return iptcc_standard_map(r
, RETURN
);
1248 else if (TC_BUILTIN(t
->u
.user
.name
, handle
)) {
1249 /* Can't jump to builtins. */
1253 /* Maybe it's an existing chain name. */
1254 struct chain_head
*c
;
1255 DEBUGP("trying to find chain `%s': ", t
->u
.user
.name
);
1257 c
= iptcc_find_label(t
->u
.user
.name
, handle
);
1259 DEBUGP_C("found!\n");
1260 r
->type
= IPTCC_R_JUMP
;
1265 DEBUGP_C("not found :(\n");
1268 /* Must be a module? If not, kernel will reject... */
1269 /* memset to all 0 for your memcmp convenience: don't clear version */
1270 memset(t
->u
.user
.name
+ strlen(t
->u
.user
.name
),
1272 FUNCTION_MAXNAMELEN
- 1 - strlen(t
->u
.user
.name
));
1273 r
->type
= IPTCC_R_MODULE
;
1274 set_changed(handle
);
1278 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1280 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain
,
1281 const STRUCT_ENTRY
*e
,
1282 unsigned int rulenum
,
1283 TC_HANDLE_T
*handle
)
1285 struct chain_head
*c
;
1286 struct rule_head
*r
;
1287 struct list_head
*prev
;
1289 iptc_fn
= TC_INSERT_ENTRY
;
1291 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1296 /* first rulenum index = 0
1297 first c->num_rules index = 1 */
1298 if (rulenum
> c
->num_rules
) {
1303 /* If we are inserting at the end just take advantage of the
1304 double linked list, insert will happen before the entry
1306 if (rulenum
== c
->num_rules
) {
1308 } else if (rulenum
+ 1 <= c
->num_rules
/2) {
1309 r
= iptcc_get_rule_num(c
, rulenum
+ 1);
1312 r
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
1316 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1321 memcpy(r
->entry
, e
, e
->next_offset
);
1322 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1324 if (!iptcc_map_target(*handle
, r
)) {
1329 list_add_tail(&r
->list
, prev
);
1332 set_changed(*handle
);
1337 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1339 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain
,
1340 const STRUCT_ENTRY
*e
,
1341 unsigned int rulenum
,
1342 TC_HANDLE_T
*handle
)
1344 struct chain_head
*c
;
1345 struct rule_head
*r
, *old
;
1347 iptc_fn
= TC_REPLACE_ENTRY
;
1349 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1354 if (rulenum
>= c
->num_rules
) {
1359 /* Take advantage of the double linked list if possible. */
1360 if (rulenum
+ 1 <= c
->num_rules
/2) {
1361 old
= iptcc_get_rule_num(c
, rulenum
+ 1);
1363 old
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
1366 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1371 memcpy(r
->entry
, e
, e
->next_offset
);
1372 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1374 if (!iptcc_map_target(*handle
, r
)) {
1379 list_add(&r
->list
, &old
->list
);
1380 iptcc_delete_rule(old
);
1382 set_changed(*handle
);
1387 /* Append entry `fw' to chain `chain'. Equivalent to insert with
1388 rulenum = length of chain. */
1390 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain
,
1391 const STRUCT_ENTRY
*e
,
1392 TC_HANDLE_T
*handle
)
1394 struct chain_head
*c
;
1395 struct rule_head
*r
;
1397 iptc_fn
= TC_APPEND_ENTRY
;
1398 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1399 DEBUGP("unable to find chain `%s'\n", chain
);
1404 if (!(r
= iptcc_alloc_rule(c
, e
->next_offset
))) {
1405 DEBUGP("unable to allocate rule for chain `%s'\n", chain
);
1410 memcpy(r
->entry
, e
, e
->next_offset
);
1411 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1413 if (!iptcc_map_target(*handle
, r
)) {
1414 DEBUGP("unable to map target of rule for chain `%s'\n", chain
);
1419 list_add_tail(&r
->list
, &c
->rules
);
1422 set_changed(*handle
);
1428 match_different(const STRUCT_ENTRY_MATCH
*a
,
1429 const unsigned char *a_elems
,
1430 const unsigned char *b_elems
,
1431 unsigned char **maskptr
)
1433 const STRUCT_ENTRY_MATCH
*b
;
1436 /* Offset of b is the same as a. */
1437 b
= (void *)b_elems
+ ((unsigned char *)a
- a_elems
);
1439 if (a
->u
.match_size
!= b
->u
.match_size
)
1442 if (strcmp(a
->u
.user
.name
, b
->u
.user
.name
) != 0)
1445 *maskptr
+= ALIGN(sizeof(*a
));
1447 for (i
= 0; i
< a
->u
.match_size
- ALIGN(sizeof(*a
)); i
++)
1448 if (((a
->data
[i
] ^ b
->data
[i
]) & (*maskptr
)[i
]) != 0)
1455 target_same(struct rule_head
*a
, struct rule_head
*b
,const unsigned char *mask
)
1458 STRUCT_ENTRY_TARGET
*ta
, *tb
;
1460 if (a
->type
!= b
->type
)
1463 ta
= GET_TARGET(a
->entry
);
1464 tb
= GET_TARGET(b
->entry
);
1467 case IPTCC_R_FALLTHROUGH
:
1470 return a
->jump
== b
->jump
;
1471 case IPTCC_R_STANDARD
:
1472 return ((STRUCT_STANDARD_TARGET
*)ta
)->verdict
1473 == ((STRUCT_STANDARD_TARGET
*)tb
)->verdict
;
1474 case IPTCC_R_MODULE
:
1475 if (ta
->u
.target_size
!= tb
->u
.target_size
)
1477 if (strcmp(ta
->u
.user
.name
, tb
->u
.user
.name
) != 0)
1480 for (i
= 0; i
< ta
->u
.target_size
- sizeof(*ta
); i
++)
1481 if (((ta
->data
[i
] ^ tb
->data
[i
]) & mask
[i
]) != 0)
1485 fprintf(stderr
, "ERROR: bad type %i\n", a
->type
);
1490 static unsigned char *
1491 is_same(const STRUCT_ENTRY
*a
,
1492 const STRUCT_ENTRY
*b
,
1493 unsigned char *matchmask
);
1495 /* Delete the first rule in `chain' which matches `fw'. */
1497 TC_DELETE_ENTRY(const IPT_CHAINLABEL chain
,
1498 const STRUCT_ENTRY
*origfw
,
1499 unsigned char *matchmask
,
1500 TC_HANDLE_T
*handle
)
1502 struct chain_head
*c
;
1503 struct rule_head
*r
, *i
;
1505 iptc_fn
= TC_DELETE_ENTRY
;
1506 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1511 /* Create a rule_head from origfw. */
1512 r
= iptcc_alloc_rule(c
, origfw
->next_offset
);
1518 memcpy(r
->entry
, origfw
, origfw
->next_offset
);
1519 r
->counter_map
.maptype
= COUNTER_MAP_NOMAP
;
1520 if (!iptcc_map_target(*handle
, r
)) {
1521 DEBUGP("unable to map target of rule for chain `%s'\n", chain
);
1525 /* iptcc_map_target increment target chain references
1526 * since this is a fake rule only used for matching
1527 * the chain references count is decremented again.
1529 if (r
->type
== IPTCC_R_JUMP
1531 r
->jump
->references
--;
1534 list_for_each_entry(i
, &c
->rules
, list
) {
1535 unsigned char *mask
;
1537 mask
= is_same(r
->entry
, i
->entry
, matchmask
);
1541 if (!target_same(r
, i
, mask
))
1544 /* If we are about to delete the rule that is the
1545 * current iterator, move rule iterator back. next
1546 * pointer will then point to real next node */
1547 if (i
== (*handle
)->rule_iterator_cur
) {
1548 (*handle
)->rule_iterator_cur
=
1549 list_entry((*handle
)->rule_iterator_cur
->list
.prev
,
1550 struct rule_head
, list
);
1554 iptcc_delete_rule(i
);
1556 set_changed(*handle
);
1567 /* Delete the rule in position `rulenum' in `chain'. */
1569 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain
,
1570 unsigned int rulenum
,
1571 TC_HANDLE_T
*handle
)
1573 struct chain_head
*c
;
1574 struct rule_head
*r
;
1576 iptc_fn
= TC_DELETE_NUM_ENTRY
;
1578 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1583 if (rulenum
>= c
->num_rules
) {
1588 /* Take advantage of the double linked list if possible. */
1589 if (rulenum
+ 1 <= c
->num_rules
/2) {
1590 r
= iptcc_get_rule_num(c
, rulenum
+ 1);
1592 r
= iptcc_get_rule_num_reverse(c
, c
->num_rules
- rulenum
);
1595 /* If we are about to delete the rule that is the current
1596 * iterator, move rule iterator back. next pointer will then
1597 * point to real next node */
1598 if (r
== (*handle
)->rule_iterator_cur
) {
1599 (*handle
)->rule_iterator_cur
=
1600 list_entry((*handle
)->rule_iterator_cur
->list
.prev
,
1601 struct rule_head
, list
);
1605 iptcc_delete_rule(r
);
1607 set_changed(*handle
);
1612 /* Check the packet `fw' on chain `chain'. Returns the verdict, or
1613 NULL and sets errno. */
1615 TC_CHECK_PACKET(const IPT_CHAINLABEL chain
,
1616 STRUCT_ENTRY
*entry
,
1617 TC_HANDLE_T
*handle
)
1619 iptc_fn
= TC_CHECK_PACKET
;
1624 /* Flushes the entries in the given chain (ie. empties chain). */
1626 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain
, TC_HANDLE_T
*handle
)
1628 struct chain_head
*c
;
1629 struct rule_head
*r
, *tmp
;
1631 iptc_fn
= TC_FLUSH_ENTRIES
;
1632 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1637 list_for_each_entry_safe(r
, tmp
, &c
->rules
, list
) {
1638 iptcc_delete_rule(r
);
1643 set_changed(*handle
);
1648 /* Zeroes the counters in a chain. */
1650 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain
, TC_HANDLE_T
*handle
)
1652 struct chain_head
*c
;
1653 struct rule_head
*r
;
1655 iptc_fn
= TC_ZERO_ENTRIES
;
1656 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1661 if (c
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
1662 c
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
1664 list_for_each_entry(r
, &c
->rules
, list
) {
1665 if (r
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
1666 r
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
1669 set_changed(*handle
);
1675 TC_READ_COUNTER(const IPT_CHAINLABEL chain
,
1676 unsigned int rulenum
,
1677 TC_HANDLE_T
*handle
)
1679 struct chain_head
*c
;
1680 struct rule_head
*r
;
1682 iptc_fn
= TC_READ_COUNTER
;
1685 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1690 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
1695 return &r
->entry
[0].counters
;
1699 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain
,
1700 unsigned int rulenum
,
1701 TC_HANDLE_T
*handle
)
1703 struct chain_head
*c
;
1704 struct rule_head
*r
;
1706 iptc_fn
= TC_ZERO_COUNTER
;
1709 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1714 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
1719 if (r
->counter_map
.maptype
== COUNTER_MAP_NORMAL_MAP
)
1720 r
->counter_map
.maptype
= COUNTER_MAP_ZEROED
;
1722 set_changed(*handle
);
1728 TC_SET_COUNTER(const IPT_CHAINLABEL chain
,
1729 unsigned int rulenum
,
1730 STRUCT_COUNTERS
*counters
,
1731 TC_HANDLE_T
*handle
)
1733 struct chain_head
*c
;
1734 struct rule_head
*r
;
1737 iptc_fn
= TC_SET_COUNTER
;
1740 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1745 if (!(r
= iptcc_get_rule_num(c
, rulenum
))) {
1751 r
->counter_map
.maptype
= COUNTER_MAP_SET
;
1753 memcpy(&e
->counters
, counters
, sizeof(STRUCT_COUNTERS
));
1755 set_changed(*handle
);
1760 /* Creates a new chain. */
1761 /* To create a chain, create two rules: error node and unconditional
1764 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain
, TC_HANDLE_T
*handle
)
1766 static struct chain_head
*c
;
1768 iptc_fn
= TC_CREATE_CHAIN
;
1770 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1772 if (iptcc_find_label(chain
, *handle
)
1773 || strcmp(chain
, LABEL_DROP
) == 0
1774 || strcmp(chain
, LABEL_ACCEPT
) == 0
1775 || strcmp(chain
, LABEL_QUEUE
) == 0
1776 || strcmp(chain
, LABEL_RETURN
) == 0) {
1777 DEBUGP("Chain `%s' already exists\n", chain
);
1782 if (strlen(chain
)+1 > sizeof(IPT_CHAINLABEL
)) {
1783 DEBUGP("Chain name `%s' too long\n", chain
);
1788 c
= iptcc_alloc_chain_head(chain
, 0);
1790 DEBUGP("Cannot allocate memory for chain `%s'\n", chain
);
1796 DEBUGP("Creating chain `%s'\n", chain
);
1797 list_add_tail(&c
->list
, &(*handle
)->chains
);
1799 set_changed(*handle
);
1804 /* Get the number of references to this chain. */
1806 TC_GET_REFERENCES(unsigned int *ref
, const IPT_CHAINLABEL chain
,
1807 TC_HANDLE_T
*handle
)
1809 struct chain_head
*c
;
1811 iptc_fn
= TC_GET_REFERENCES
;
1812 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1817 *ref
= c
->references
;
1822 /* Deletes a chain. */
1824 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain
, TC_HANDLE_T
*handle
)
1826 unsigned int references
;
1827 struct chain_head
*c
;
1829 iptc_fn
= TC_DELETE_CHAIN
;
1831 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1832 DEBUGP("cannot find chain `%s'\n", chain
);
1837 if (TC_BUILTIN(chain
, *handle
)) {
1838 DEBUGP("cannot remove builtin chain `%s'\n", chain
);
1843 if (!TC_GET_REFERENCES(&references
, chain
, handle
)) {
1844 DEBUGP("cannot get references on chain `%s'\n", chain
);
1848 if (references
> 0) {
1849 DEBUGP("chain `%s' still has references\n", chain
);
1855 DEBUGP("chain `%s' is not empty\n", chain
);
1860 /* If we are about to delete the chain that is the current
1861 * iterator, move chain iterator firward. */
1862 if (c
== (*handle
)->chain_iterator_cur
)
1863 iptcc_chain_iterator_advance(*handle
);
1868 DEBUGP("chain `%s' deleted\n", chain
);
1870 set_changed(*handle
);
1875 /* Renames a chain. */
1876 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname
,
1877 const IPT_CHAINLABEL newname
,
1878 TC_HANDLE_T
*handle
)
1880 struct chain_head
*c
;
1881 iptc_fn
= TC_RENAME_CHAIN
;
1883 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1885 if (iptcc_find_label(newname
, *handle
)
1886 || strcmp(newname
, LABEL_DROP
) == 0
1887 || strcmp(newname
, LABEL_ACCEPT
) == 0
1888 || strcmp(newname
, LABEL_QUEUE
) == 0
1889 || strcmp(newname
, LABEL_RETURN
) == 0) {
1894 if (!(c
= iptcc_find_label(oldname
, *handle
))
1895 || TC_BUILTIN(oldname
, *handle
)) {
1900 if (strlen(newname
)+1 > sizeof(IPT_CHAINLABEL
)) {
1905 strncpy(c
->name
, newname
, sizeof(IPT_CHAINLABEL
));
1907 set_changed(*handle
);
1912 /* Sets the policy on a built-in chain. */
1914 TC_SET_POLICY(const IPT_CHAINLABEL chain
,
1915 const IPT_CHAINLABEL policy
,
1916 STRUCT_COUNTERS
*counters
,
1917 TC_HANDLE_T
*handle
)
1919 struct chain_head
*c
;
1921 iptc_fn
= TC_SET_POLICY
;
1923 if (!(c
= iptcc_find_label(chain
, *handle
))) {
1924 DEBUGP("cannot find chain `%s'\n", chain
);
1929 if (!iptcc_is_builtin(c
)) {
1930 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain
);
1935 if (strcmp(policy
, LABEL_ACCEPT
) == 0)
1936 c
->verdict
= -NF_ACCEPT
- 1;
1937 else if (strcmp(policy
, LABEL_DROP
) == 0)
1938 c
->verdict
= -NF_DROP
- 1;
1945 /* set byte and packet counters */
1946 memcpy(&c
->counters
, counters
, sizeof(STRUCT_COUNTERS
));
1947 c
->counter_map
.maptype
= COUNTER_MAP_SET
;
1949 c
->counter_map
.maptype
= COUNTER_MAP_NOMAP
;
1952 set_changed(*handle
);
1957 /* Without this, on gcc 2.7.2.3, we get:
1958 libiptc.c: In function `TC_COMMIT':
1959 libiptc.c:833: fixed or forbidden register was spilled.
1960 This may be due to a compiler bug or to impossible asm
1961 statements or clauses.
1964 subtract_counters(STRUCT_COUNTERS
*answer
,
1965 const STRUCT_COUNTERS
*a
,
1966 const STRUCT_COUNTERS
*b
)
1968 answer
->pcnt
= a
->pcnt
- b
->pcnt
;
1969 answer
->bcnt
= a
->bcnt
- b
->bcnt
;
1973 static void counters_nomap(STRUCT_COUNTERS_INFO
*newcounters
,
1976 newcounters
->counters
[index
] = ((STRUCT_COUNTERS
) { 0, 0});
1977 DEBUGP_C("NOMAP => zero\n");
1980 static void counters_normal_map(STRUCT_COUNTERS_INFO
*newcounters
,
1981 STRUCT_REPLACE
*repl
,
1983 unsigned int mappos
)
1985 /* Original read: X.
1986 * Atomic read on replacement: X + Y.
1987 * Currently in kernel: Z.
1988 * Want in kernel: X + Y + Z.
1990 * => Add in replacement read.
1992 newcounters
->counters
[index
] = repl
->counters
[mappos
];
1993 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos
);
1996 static void counters_map_zeroed(STRUCT_COUNTERS_INFO
*newcounters
,
1997 STRUCT_REPLACE
*repl
,
1999 unsigned int mappos
,
2000 STRUCT_COUNTERS
*counters
)
2002 /* Original read: X.
2003 * Atomic read on replacement: X + Y.
2004 * Currently in kernel: Z.
2005 * Want in kernel: Y + Z.
2007 * => Add in (replacement read - original read).
2009 subtract_counters(&newcounters
->counters
[index
],
2010 &repl
->counters
[mappos
],
2012 DEBUGP_C("ZEROED => mappos %u\n", mappos
);
2015 static void counters_map_set(STRUCT_COUNTERS_INFO
*newcounters
,
2017 STRUCT_COUNTERS
*counters
)
2019 /* Want to set counter (iptables-restore) */
2021 memcpy(&newcounters
->counters
[index
], counters
,
2022 sizeof(STRUCT_COUNTERS
));
2029 TC_COMMIT(TC_HANDLE_T
*handle
)
2031 /* Replace, then map back the counters. */
2032 STRUCT_REPLACE
*repl
;
2033 STRUCT_COUNTERS_INFO
*newcounters
;
2034 struct chain_head
*c
;
2038 unsigned int new_size
;
2040 iptc_fn
= TC_COMMIT
;
2043 /* Don't commit if nothing changed. */
2044 if (!(*handle
)->changed
)
2047 new_number
= iptcc_compile_table_prep(*handle
, &new_size
);
2048 if (new_number
< 0) {
2053 repl
= malloc(sizeof(*repl
) + new_size
);
2058 memset(repl
, 0, sizeof(*repl
) + new_size
);
2061 TC_DUMP_ENTRIES(*handle
);
2064 counterlen
= sizeof(STRUCT_COUNTERS_INFO
)
2065 + sizeof(STRUCT_COUNTERS
) * new_number
;
2067 /* These are the old counters we will get from kernel */
2068 repl
->counters
= malloc(sizeof(STRUCT_COUNTERS
)
2069 * (*handle
)->info
.num_entries
);
2070 if (!repl
->counters
) {
2074 /* These are the counters we're going to put back, later. */
2075 newcounters
= malloc(counterlen
);
2078 goto out_free_repl_counters
;
2080 memset(newcounters
, 0, counterlen
);
2082 strcpy(repl
->name
, (*handle
)->info
.name
);
2083 repl
->num_entries
= new_number
;
2084 repl
->size
= new_size
;
2086 repl
->num_counters
= (*handle
)->info
.num_entries
;
2087 repl
->valid_hooks
= (*handle
)->info
.valid_hooks
;
2089 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2090 repl
->num_entries
, repl
->size
, repl
->num_counters
);
2092 ret
= iptcc_compile_table(*handle
, repl
);
2095 goto out_free_newcounters
;
2101 int fd
= open("/tmp/libiptc-so_set_replace.blob",
2104 write(fd
, repl
, sizeof(*repl
) + repl
->size
);
2110 ret
= setsockopt(sockfd
, TC_IPPROTO
, SO_SET_REPLACE
, repl
,
2111 sizeof(*repl
) + repl
->size
);
2113 goto out_free_newcounters
;
2115 /* Put counters back. */
2116 strcpy(newcounters
->name
, (*handle
)->info
.name
);
2117 newcounters
->num_counters
= new_number
;
2119 list_for_each_entry(c
, &(*handle
)->chains
, list
) {
2120 struct rule_head
*r
;
2122 /* Builtin chains have their own counters */
2123 if (iptcc_is_builtin(c
)) {
2124 DEBUGP("counter for chain-index %u: ", c
->foot_index
);
2125 switch(c
->counter_map
.maptype
) {
2126 case COUNTER_MAP_NOMAP
:
2127 counters_nomap(newcounters
, c
->foot_index
);
2129 case COUNTER_MAP_NORMAL_MAP
:
2130 counters_normal_map(newcounters
, repl
,
2132 c
->counter_map
.mappos
);
2134 case COUNTER_MAP_ZEROED
:
2135 counters_map_zeroed(newcounters
, repl
,
2137 c
->counter_map
.mappos
,
2140 case COUNTER_MAP_SET
:
2141 counters_map_set(newcounters
, c
->foot_index
,
2147 list_for_each_entry(r
, &c
->rules
, list
) {
2148 DEBUGP("counter for index %u: ", r
->index
);
2149 switch (r
->counter_map
.maptype
) {
2150 case COUNTER_MAP_NOMAP
:
2151 counters_nomap(newcounters
, r
->index
);
2154 case COUNTER_MAP_NORMAL_MAP
:
2155 counters_normal_map(newcounters
, repl
,
2157 r
->counter_map
.mappos
);
2160 case COUNTER_MAP_ZEROED
:
2161 counters_map_zeroed(newcounters
, repl
,
2163 r
->counter_map
.mappos
,
2164 &r
->entry
->counters
);
2167 case COUNTER_MAP_SET
:
2168 counters_map_set(newcounters
, r
->index
,
2169 &r
->entry
->counters
);
2176 #ifdef KERNEL_64_USERSPACE_32
2178 /* Kernel will think that pointer should be 64-bits, and get
2179 padding. So we accomodate here (assumption: alignment of
2180 `counters' is on 64-bit boundary). */
2181 u_int64_t
*kernptr
= (u_int64_t
*)&newcounters
->counters
;
2182 if ((unsigned long)&newcounters
->counters
% 8 != 0) {
2184 "counters alignment incorrect! Mail rusty!\n");
2187 *kernptr
= newcounters
->counters
;
2189 #endif /* KERNEL_64_USERSPACE_32 */
2193 int fd
= open("/tmp/libiptc-so_set_add_counters.blob",
2196 write(fd
, newcounters
, counterlen
);
2202 ret
= setsockopt(sockfd
, TC_IPPROTO
, SO_SET_ADD_COUNTERS
,
2203 newcounters
, counterlen
);
2205 goto out_free_newcounters
;
2207 free(repl
->counters
);
2215 out_free_newcounters
:
2217 out_free_repl_counters
:
2218 free(repl
->counters
);
2225 /* Get raw socket. */
2232 /* Translates errno numbers into more human-readable form than strerror. */
2234 TC_STRERROR(int err
)
2237 struct table_struct
{
2240 const char *message
;
2242 { { TC_INIT
, EPERM
, "Permission denied (you must be root)" },
2243 { TC_INIT
, EINVAL
, "Module is wrong version" },
2245 "Table does not exist (do you need to insmod?)" },
2246 { TC_DELETE_CHAIN
, ENOTEMPTY
, "Chain is not empty" },
2247 { TC_DELETE_CHAIN
, EINVAL
, "Can't delete built-in chain" },
2248 { TC_DELETE_CHAIN
, EMLINK
,
2249 "Can't delete chain with references left" },
2250 { TC_CREATE_CHAIN
, EEXIST
, "Chain already exists" },
2251 { TC_INSERT_ENTRY
, E2BIG
, "Index of insertion too big" },
2252 { TC_REPLACE_ENTRY
, E2BIG
, "Index of replacement too big" },
2253 { TC_DELETE_NUM_ENTRY
, E2BIG
, "Index of deletion too big" },
2254 { TC_READ_COUNTER
, E2BIG
, "Index of counter too big" },
2255 { TC_ZERO_COUNTER
, E2BIG
, "Index of counter too big" },
2256 { TC_INSERT_ENTRY
, ELOOP
, "Loop found in table" },
2257 { TC_INSERT_ENTRY
, EINVAL
, "Target problem" },
2258 /* EINVAL for CHECK probably means bad interface. */
2259 { TC_CHECK_PACKET
, EINVAL
,
2260 "Bad arguments (does that interface exist?)" },
2261 { TC_CHECK_PACKET
, ENOSYS
,
2262 "Checking will most likely never get implemented" },
2263 /* ENOENT for DELETE probably means no matching rule */
2264 { TC_DELETE_ENTRY
, ENOENT
,
2265 "Bad rule (does a matching rule exist in that chain?)" },
2266 { TC_SET_POLICY
, ENOENT
,
2267 "Bad built-in chain name" },
2268 { TC_SET_POLICY
, EINVAL
,
2269 "Bad policy name" },
2271 { NULL
, 0, "Incompatible with this kernel" },
2272 { NULL
, ENOPROTOOPT
, "iptables who? (do you need to insmod?)" },
2273 { NULL
, ENOSYS
, "Will be implemented real soon. I promise ;)" },
2274 { NULL
, ENOMEM
, "Memory allocation problem" },
2275 { NULL
, ENOENT
, "No chain/target/match by that name" },
2278 for (i
= 0; i
< sizeof(table
)/sizeof(struct table_struct
); i
++) {
2279 if ((!table
[i
].fn
|| table
[i
].fn
== iptc_fn
)
2280 && table
[i
].err
== err
)
2281 return table
[i
].message
;
2284 return strerror(err
);