1 /* Library which manipulates firewall rules. Version $Revision: 1.41 $ */
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-2003 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 * - speed 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 * 2003-Jun-30: Harald Welte <laforge@netfilter.org>:
22 * - reimplementation from scratch. *sigh*. I hope nobody has to touch
23 * this code ever again.
25 #include "linux_listhelp.h"
28 #define IPT_LIB_DIR "/usr/lib/iptables"
31 static int sockfd = -1;
32 static void *iptc_fn = NULL;
34 static const char *hooknames[]
35 = { [HOOK_PRE_ROUTING] "PREROUTING",
36 [HOOK_LOCAL_IN] "INPUT",
37 [HOOK_FORWARD] "FORWARD",
38 [HOOK_LOCAL_OUT] "OUTPUT",
39 [HOOK_POST_ROUTING] "POSTROUTING",
41 [HOOK_DROPPING] "DROPPING"
49 COUNTER_MAP_NORMAL_MAP,
56 /* Convenience structures */
57 struct ipt_error_target
59 STRUCT_ENTRY_TARGET t;
60 char error[TABLE_MAXNAMELEN];
65 struct list_head list; /* list of rules in chain */
67 struct chain_head *chain; /* we're part of this chain */
69 struct chain_head *jumpto; /* target of this rule, in case
72 struct counter_map counter_map;
74 unsigned int size; /* size of rule */
75 STRUCT_ENTRY *entry_blob; /* pointer to entry in blob */
76 STRUCT_ENTRY entry[0];
81 struct list_head list;
83 char name[TABLE_MAXNAMELEN];
85 struct list_head rules;
86 struct rule_head *firstrule; /* first (ERROR) rule */
87 struct rule_head *lastrule; /* last (RETURN) rule */
92 /* Have changes been made? */
95 /* linked list of chains in this table */
96 struct list_head chains;
98 /* current position of first_chain() / next_chain() */
99 struct chain_head *chain_iterator_cur;
101 /* current position of first_rule() / next_rule() */
102 struct rule_head *rule_iterator_cur;
104 /* the structure we receive from getsockopt() */
107 /* Array of hook names */
108 const char **hooknames;
110 /* Size in here reflects original state. */
113 /* Cached position of chain heads (NULL = no cache). */
114 unsigned int cache_num_chains;
115 unsigned int cache_num_builtins;
116 struct chain_cache *cache_chain_heads;
118 /* Chain iterator: current chain cache entry. */
119 struct chain_cache *cache_chain_iteration;
121 /* Rule iterator: terminal rule */
122 STRUCT_ENTRY *cache_rule_end;
124 /* Number in here reflects current state. */
125 unsigned int new_number;
127 STRUCT_GET_ENTRIES entries;
131 set_changed(TC_HANDLE_T h)
137 static void do_check(TC_HANDLE_T h, unsigned int line);
138 #define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
143 static struct rule_head *ruleh_alloc(unsigned int size)
145 struct rule_head *ruleh = malloc(sizeof(*ruleh)+size);
149 memset(ruleh, 0, sizeof(*ruleh)+size);
155 static void ruleh_free(struct rule_head *ruleh)
157 list_del(&ruleh->list);
161 static struct chain_head *chainh_alloc(TC_HANDLE_T h, const char *name)
163 struct chain_head *chainh = malloc(sizeof(*chainh));
167 memset(chainh, 0, sizeof(*chainh));
168 strncpy(chainh->name, name, sizeof(&chainh->name));
169 list_append(&chainh->list, &h->chains);
175 chainh_clean(struct chain_head *chainh)
178 struct list_head *cur_item, *item2;
180 list_for_each_safe(cur_item, item2, &chainh->rules) {
181 struct rule_head *ruleh = list_entry(cur_item,
189 chainh_free(struct chain_head *chainh)
191 chainh_clean(chainh);
192 list_del(&chainh->list);
195 static struct chain_head *
196 chainh_find(TC_HANDLE_T h, const IPT_CHAINLABEL name)
198 struct list_head *cur;
200 list_for_each(cur, &h->chains) {
201 struct chain_head *ch = list_entry(cur, struct chain_head,
203 if (!strcmp(name, ch->name))
209 /* Returns chain head if found, otherwise NULL. */
210 static struct chain_head *
211 find_label(const char *name, TC_HANDLE_T handle)
213 return chainh_find(handle, name);
218 * functions that directly operate on the blob
221 static inline unsigned long
222 entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
224 return (void *)e - (void *)h->entries.entrytable;
227 static inline STRUCT_ENTRY *
228 get_entry(TC_HANDLE_T h, unsigned int offset)
230 return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
233 /* needed by entry2index */
235 get_number(const STRUCT_ENTRY *i,
236 const STRUCT_ENTRY *seek,
246 entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
248 unsigned int pos = 0;
250 if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
251 get_number, seek, &pos) == 0) {
252 fprintf(stderr, "ERROR: offset %i not an entry!\n",
253 (char *)seek - (char *)h->entries.entrytable);
260 get_entry_n(STRUCT_ENTRY *i,
265 if (*pos == number) {
273 static STRUCT_ENTRY *
274 index2entry(TC_HANDLE_T h, unsigned int index)
276 unsigned int pos = 0;
277 STRUCT_ENTRY *ret = NULL;
279 ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
280 get_entry_n, index, &pos, &ret);
285 static inline unsigned long
286 index2offset(TC_HANDLE_T h, unsigned int index)
288 return entry2offset(h, index2entry(h, index));
292 get_errorlabel(TC_HANDLE_T h, unsigned int offset)
296 e = get_entry(h, offset);
297 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) {
298 fprintf(stderr, "ERROR: offset %u not an error node!\n",
303 return (char *)GET_TARGET(e)->data;
307 static inline STRUCT_ENTRY *
308 offset2entry(TC_HANDLE_T h, unsigned int offset)
310 return (STRUCT_ENTRY *) ((void *)h->entries.entrytable+offset);
313 static inline unsigned int
314 offset2index(const TC_HANDLE_T h, unsigned int offset)
316 return entry2index(h, offset2entry(h, offset));
322 /* Allocate handle of given size */
324 alloc_tc_handle(const char *tablename, unsigned int size,
325 unsigned int num_rules)
330 len = sizeof(STRUCT_TC_HANDLE)
332 + num_rules * sizeof(struct counter_map);
334 if ((h = malloc(len)) == NULL) {
341 strcpy(h->info.name, tablename);
342 strcpy(h->entries.name, tablename);
343 INIT_LIST_HEAD(&h->chains);
348 /* get the name of the chain that we jump to */
350 parse_jumptarget(const STRUCT_ENTRY *e, TC_HANDLE_T h)
352 STRUCT_ENTRY *jumpto;
355 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) {
356 /* called for non-standard target */
359 /* Standard target: evaluate */
360 spos = *(int *)GET_TARGET(e)->data;
365 jumpto = get_entry(h, spos);
367 /* Fall through rule */
368 if (jumpto == (void *)e + e->next_offset)
371 /* Must point to head of a chain: ie. after error rule */
372 /* FIXME: this needs to deal with internal jump targets */
373 labelidx = entry2index(h, jumpto) - 1;
374 return get_errorlabel(h, index2offset(h, labelidx));
377 /* parser functions */
380 append_entrycopy(const STRUCT_ENTRY *e, struct rule_head *prev)
382 struct rule_head *ruleh = ruleh_alloc(e->next_offset);
386 memcpy(&ruleh->entry, e, e->next_offset);
387 ruleh->chain = prev->chain;
388 ruleh->entry_blob = e;
389 list_append(&ruleh->list, &prev->list);
394 /* have to return 0 on success, bcf ENTRY_ITERATE */
396 parse_entry(const STRUCT_ENTRY *e, TC_HANDLE_T h, struct chain_head **curchain)
400 STRUCT_ENTRY_TARGET ent;
401 STRUCT_STANDARD_TARGET std;
402 struct ipt_error_target err;
405 struct rule_head *lastrule = list_entry((*curchain)->rules.prev,
406 struct rule_head, list);
407 struct rule_head *newrule;
409 tgt = (union tgt_u *) GET_TARGET(e);
411 if (e->target_offset == sizeof(STRUCT_ENTRY)
412 && (strcmp(tgt->ent.u.user.name, IPT_STANDARD_TARGET) == 0)) {
413 /* jump to somewhere else */
415 struct chain_head *chainh;
417 newrule = append_entrycopy(e, lastrule);
419 targname = parse_jumptarget(e, h);
420 if (!(chainh = find_label(targname, h))) {
421 chainh = chainh_alloc(h, targname);
427 newrule->jumpto = chainh;
429 } else if (e->target_offset == sizeof(STRUCT_ENTRY)
430 && e->next_offset == sizeof(STRUCT_ENTRY)
431 + ALIGN(sizeof(struct ipt_error_target))
432 && !strcmp(tgt->ent.u.user.name, ERROR_TARGET)) {
434 *curchain = chainh_find(h, tgt->err.error);
436 *curchain = chainh_alloc(h, tgt->err.error);
437 /* FIXME: error handling */
439 newrule = append_entrycopy(e, lastrule);
440 (*curchain)->firstrule = newrule;
442 } else if (e->target_offset == sizeof(STRUCT_ENTRY)
443 && e->next_offset == sizeof(STRUCT_ENTRY)
444 + ALIGN(sizeof(STRUCT_STANDARD_TARGET))
445 && tgt->std.verdict == RETURN) {
447 newrule = append_entrycopy(e, lastrule);
448 (*curchain)->lastrule = newrule;
452 newrule = append_entrycopy(e, lastrule);
455 /* create counter map entry */
456 newrule->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
457 newrule->counter_map.mappos = entry2index(h, e);
459 /* iterate over hook_entries, needed to connect builtin
460 * chains with hook numbers */
461 for (i = 0; i < NUMHOOKS; i++) {
462 if (!(h->info.valid_hooks & (1 << i)))
464 if (h->info.hook_entry[i] == entry2offset(h, e)) {
465 /* found hook entry point */
467 (*curchain)->hooknum = i;
469 if (h->info.underflow[i] == entry2offset(h, e)) {
470 /* found underflow point */
477 static int parse_ruleset(TC_HANDLE_T h)
479 struct chain_head *curchain;
481 /* iterate over ruleset; create linked list of rule_head/chain_head */
482 if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
483 parse_entry, h, &curchain)) {
484 /* some error happened while iterating */
492 TC_INIT(const char *tablename)
506 if (strlen(tablename) >= TABLE_MAXNAMELEN) {
511 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
517 strcpy(info.name, tablename);
518 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
521 if ((h = alloc_tc_handle(info.name, info.size, info.num_entries))
530 sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
531 dynlib = dlopen(pathname, RTLD_NOW);
536 h->hooknames = dlsym(dynlib, "hooknames");
542 h->hooknames = hooknames;
545 /* Initialize current state */
547 //h->new_number = h->info.num_entries;
549 h->entries.size = h->info.size;
551 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
553 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
568 TC_FREE(TC_HANDLE_T *h)
570 struct list_head *cur_item, *item2;
575 /* free all chains */
576 list_for_each_safe(cur_item, item2, &(*h)->chains) {
577 struct chain_head *chead = list_entry(cur_item,
583 /* FIXME: free all other ressources we might be using */
590 print_match(const STRUCT_ENTRY_MATCH *m)
592 printf("Match name: `%s'\n", m->u.user.name);
596 static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
600 TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
604 printf("libiptc v%s. %u entries, %u bytes.\n",
606 handle->new_number, handle->entries.size);
607 printf("Table `%s'\n", handle->info.name);
608 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
609 handle->info.hook_entry[HOOK_PRE_ROUTING],
610 handle->info.hook_entry[HOOK_LOCAL_IN],
611 handle->info.hook_entry[HOOK_FORWARD],
612 handle->info.hook_entry[HOOK_LOCAL_OUT],
613 handle->info.hook_entry[HOOK_POST_ROUTING]);
614 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
615 handle->info.underflow[HOOK_PRE_ROUTING],
616 handle->info.underflow[HOOK_LOCAL_IN],
617 handle->info.underflow[HOOK_FORWARD],
618 handle->info.underflow[HOOK_LOCAL_OUT],
619 handle->info.underflow[HOOK_POST_ROUTING]);
621 ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
625 /* Returns 0 if not hook entry, else hooknumber + 1 */
626 static inline unsigned int
627 is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
631 for (i = 0; i < NUMHOOKS; i++) {
632 if ((h->info.valid_hooks & (1 << i))
633 && get_entry(h, h->info.hook_entry[i]) == e)
640 static int alphasort(const void *a, const void *b)
642 return strcmp(((struct chain_cache *)a)->name,
643 ((struct chain_cache *)b)->name);
647 /* Does this chain exist? */
648 int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
650 return find_label(chain, handle) != NULL;
654 /* Returns the position of the final (ie. unconditional) element. */
656 get_chain_end(const TC_HANDLE_T handle, unsigned int start)
658 unsigned int last_off, off;
662 e = get_entry(handle, start);
664 /* Terminate when we meet a error label or a hook entry. */
665 for (off = start + e->next_offset;
666 off < handle->entries.size;
667 last_off = off, off += e->next_offset) {
668 STRUCT_ENTRY_TARGET *t;
671 e = get_entry(handle, off);
673 /* We hit an entry point. */
674 for (i = 0; i < NUMHOOKS; i++) {
675 if ((handle->info.valid_hooks & (1 << i))
676 && off == handle->info.hook_entry[i])
680 /* We hit a user chain label */
682 if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
685 /* SHOULD NEVER HAPPEN */
686 fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
687 handle->entries.size, off);
692 /* Iterator functions to run through the chains. */
694 TC_FIRST_CHAIN(TC_HANDLE_T *handle)
696 struct chain_head *firsthead = list_entry((*handle)->chains.next,
697 struct chain_head, list);
698 (*handle)->chain_iterator_cur = firsthead;
700 return firsthead->name;
703 /* Iterator functions to run through the chains. Returns NULL at end. */
705 TC_NEXT_CHAIN(TC_HANDLE_T *handle)
707 struct chain_head *next = list_entry(&(*handle)->chain_iterator_cur->list.next, struct chain_head, list);
708 (*handle)->chain_iterator_cur = next;
710 if (&next->list == &(*handle)->chains)
716 /* Get first rule in the given chain: NULL for empty chain. */
718 TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
720 struct chain_head *c;
723 c = find_label(chain, *handle);
729 /* Empty chain: single return/policy rule */
730 if (list_empty(&c->rules))
733 r = list_entry(c->rules.next, struct rule_head, list);
734 (*handle)->rule_iterator_cur = r;
739 /* Returns NULL when rules run out. */
741 TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
743 struct rule_head *r = list_entry((*handle)->rule_iterator_cur->list.next, struct rule_head, list);
745 if (&r->list == &r->chain->rules)
748 /* NOTE: prev is without any influence ! */
753 /* How many rules in this chain? */
755 TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
757 unsigned int off = 0;
758 STRUCT_ENTRY *start, *end;
761 if (!find_label(&off, chain, *handle)) {
763 return (unsigned int)-1;
766 start = get_entry(*handle, off);
767 end = get_entry(*handle, get_chain_end(*handle, off));
769 return entry2index(*handle, end) - entry2index(*handle, start);
772 /* Get n'th rule in this chain. */
773 const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
777 unsigned int pos = 0, chainindex;
780 if (!find_label(&pos, chain, *handle)) {
785 chainindex = entry2index(*handle, get_entry(*handle, pos));
787 return index2entry(*handle, chainindex + n);
792 target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
796 /* To avoid const warnings */
797 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
799 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
800 return GET_TARGET(e)->u.user.name;
802 /* Standard target: evaluate */
803 spos = *(int *)GET_TARGET(e)->data;
807 else if (spos == -NF_ACCEPT-1)
809 else if (spos == -NF_DROP-1)
811 else if (spos == -NF_QUEUE-1)
814 fprintf(stderr, "ERROR: entry %p not a valid target (%d)\n",
820 // jumpto = get_entry(handle, spos);
822 /* Fall through rule */
823 if (jumpto == (void *)e + e->next_offset)
826 /* Must point to head of a chain: ie. after error rule */
827 /* FIXME: this needs to deal with internal jump targets */
828 labelidx = entry2index(handle, jumpto) - 1;
829 return get_errorlabel(handle, index2offset(handle, labelidx));
834 /* Returns a pointer to the target name of this position. */
835 const char *TC_GET_TARGET(const STRUCT_ENTRY *e,
838 return target_name(*handle, e);
841 /* Is this a built-in chain? Actually returns hook + 1. */
843 TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
847 for (i = 0; i < NUMHOOKS; i++) {
848 if ((handle->info.valid_hooks & (1 << i))
849 && handle->hooknames[i]
850 && strcmp(handle->hooknames[i], chain) == 0)
856 /* Get the policy of a given built-in chain */
858 TC_GET_POLICY(const char *chain,
859 STRUCT_COUNTERS *counters,
863 struct chain_head *chainh;
864 struct rule_head *ruleh;
867 hook = TC_BUILTIN(chain, *handle);
871 chainh = find_label(chain, *handle);
877 ruleh = chainh->lastrule;
880 *counters = e->counters;
882 return target_name(*handle, e);
887 correct_verdict(STRUCT_ENTRY *e,
889 unsigned int offset, int delta_offset)
891 STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
892 unsigned int curr = (char *)e - base;
894 /* Trap: insert of fall-through rule. Don't change fall-through
895 verdict to jump-over-next-rule. */
896 if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
897 && t->verdict > (int)offset
898 && !(curr == offset &&
899 t->verdict == curr + e->next_offset)) {
900 t->verdict += delta_offset;
906 /* Adjusts standard verdict jump positions after an insertion/deletion. */
908 set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
910 ENTRY_ITERATE((*handle)->entries.entrytable,
911 (*handle)->entries.size,
912 correct_verdict, (char *)(*handle)->entries.entrytable,
913 offset, delta_offset);
915 set_changed(*handle);
923 standard_map(STRUCT_ENTRY *e, int verdict)
925 STRUCT_STANDARD_TARGET *t;
927 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
929 if (t->target.u.target_size
930 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
934 /* memset for memcmp convenience on delete/replace */
935 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
936 strcpy(t->target.u.user.name, STANDARD_TARGET);
937 t->verdict = verdict;
943 map_target(const TC_HANDLE_T handle,
946 STRUCT_ENTRY_TARGET *old)
948 STRUCT_ENTRY_TARGET *t = (STRUCT_ENTRY_TARGET *)GET_TARGET(e);
950 /* Save old target (except data, which we don't change, except for
951 standard case, where we don't care). */
954 /* Maybe it's empty (=> fall through) */
955 if (strcmp(t->u.user.name, "") == 0)
956 return standard_map(e, offset + e->next_offset);
957 /* Maybe it's a standard target name... */
958 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
959 return standard_map(e, -NF_ACCEPT - 1);
960 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
961 return standard_map(e, -NF_DROP - 1);
962 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
963 return standard_map(e, -NF_QUEUE - 1);
964 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
965 return standard_map(e, RETURN);
966 else if (TC_BUILTIN(t->u.user.name, handle)) {
967 /* Can't jump to builtins. */
971 /* Maybe it's an existing chain name. */
972 struct chain_head *c;
976 c = find_label(t->u.user.name, handle);
978 return standard_map(e, c->start_off);
982 /* Must be a module? If not, kernel will reject... */
983 /* memset to all 0 for your memcmp convenience. */
984 memset(t->u.user.name + strlen(t->u.user.name),
986 FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
991 unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
993 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
995 /* Save old target (except data, which we don't change, except for
996 standard case, where we don't care). */
1000 static struct rule_head *
1001 ruleh_get_n(struct chain_head *chead, int rulenum)
1004 struct list_head *list;
1007 list_for_each(list, &chead->rules) {
1008 struct rule_head *rhead = list_entry(list, struct rule_head,
1017 /* Insert the entry `e' in chain `chain' into position `rulenum'. */
1019 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1020 const STRUCT_ENTRY *e,
1021 unsigned int rulenum,
1022 TC_HANDLE_T *handle)
1024 struct chain_head *c;
1025 struct rule_head *prev;
1027 iptc_fn = TC_INSERT_ENTRY;
1028 if (!(c = find_label(chain, *handle))) {
1033 prev = ruleh_get_n(c, rulenum-1);
1039 if (append_entrycopy(e, prev))
1045 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1047 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1048 const STRUCT_ENTRY *e,
1049 unsigned int rulenum,
1050 TC_HANDLE_T *handle)
1052 struct chain_head *c;
1053 struct rule_head *repl;
1055 iptc_fn = TC_REPLACE_ENTRY;
1057 if (!(c = find_label(chain, *handle))) {
1062 repl = ruleh_get_n(c, rulenum);
1068 if (!append_entrycopy(e, repl)) {
1077 /* Append entry `e' to chain `chain'. Equivalent to insert with
1078 rulenum = length of chain. */
1080 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1081 const STRUCT_ENTRY *e,
1082 TC_HANDLE_T *handle)
1084 struct chain_head *c;
1085 struct rule_head *rhead;
1087 iptc_fn = TC_APPEND_ENTRY;
1089 if (!(c = find_label(chain, *handle))) {
1094 rhead = list_entry(c->rules.prev, struct rule_head, list);
1095 if(append_entrycopy(e, rhead))
1102 match_different(const STRUCT_ENTRY_MATCH *a,
1103 const unsigned char *a_elems,
1104 const unsigned char *b_elems,
1105 unsigned char **maskptr)
1107 const STRUCT_ENTRY_MATCH *b;
1110 /* Offset of b is the same as a. */
1111 b = (void *)b_elems + ((unsigned char *)a - a_elems);
1113 if (a->u.match_size != b->u.match_size)
1116 if (strcmp(a->u.user.name, b->u.user.name) != 0)
1119 *maskptr += ALIGN(sizeof(*a));
1121 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1122 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1129 target_different(const unsigned char *a_targdata,
1130 const unsigned char *b_targdata,
1131 unsigned int tdatasize,
1132 const unsigned char *mask)
1135 for (i = 0; i < tdatasize; i++)
1136 if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
1143 is_same(const STRUCT_ENTRY *a,
1144 const STRUCT_ENTRY *b,
1145 unsigned char *matchmask);
1147 /* Delete the first rule in `chain' which matches `origfw'. */
1149 TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
1150 const STRUCT_ENTRY *origfw,
1151 unsigned char *matchmask,
1152 TC_HANDLE_T *handle)
1154 struct chain_head *c;
1155 struct list_head *cur, *cur2;
1157 iptc_fn = TC_DELETE_ENTRY;
1158 if (!(c = find_label(chain, *handle))) {
1163 list_for_each_safe(cur, cur2, &c->rules) {
1164 struct rule_head *rhead = list_entry(cur, struct rule_head,
1166 if (is_same(rhead->entry, origfw, matchmask)) {
1176 /* Delete the rule in position `rulenum' in `chain'. */
1178 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
1179 unsigned int rulenum,
1180 TC_HANDLE_T *handle)
1182 struct chain_head *chainh;
1183 struct rule_head *rhead;
1185 iptc_fn = TC_DELETE_NUM_ENTRY;
1187 if (!(chainh = find_label(chain, *handle))) {
1192 rhead = ruleh_get_n(chainh, rulenum);
1203 /* Check the packet `fw' on chain `chain'. Returns the verdict, or
1204 NULL and sets errno. */
1206 TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
1207 STRUCT_ENTRY *entry,
1208 TC_HANDLE_T *handle)
1214 /* Flushes the entries in the given chain (ie. empties chain). */
1216 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1218 struct list_head *cur, *cur2;
1219 struct chain_head *chainh;
1221 if (!(chainh = find_label(chain, *handle))) {
1226 list_for_each_safe(cur, cur2, &chainh->rules) {
1227 struct rule_head *ruleh = list_entry(cur, struct rule_head,
1229 /* don't free the entry and policy/return entries */
1230 if (ruleh != chainh->firstrule && ruleh != chainh->lastrule)
1236 /* Zeroes the counters in a chain. */
1238 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1240 struct chain_head *c;
1241 struct list_head *cur;
1243 if (!(c = find_label(chain, *handle))) {
1248 list_for_each(cur, c->rules.next) {
1249 struct rule_head *r = list_entry(cur, struct rule_head, list);
1250 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1251 r->counter_map.maptype = COUNTER_MAP_ZEROED;
1253 set_changed(*handle);
1259 TC_READ_COUNTER(const IPT_CHAINLABEL chain,
1260 unsigned int rulenum,
1261 TC_HANDLE_T *handle)
1264 struct chain_head *c;
1265 struct rule_head *r;
1267 iptc_fn = TC_READ_COUNTER;
1270 if (!(c = find_label(chain, *handle) )
1271 || !(r = ruleh_get_n(c, rulenum))) {
1276 return &r->entry->counters;
1280 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
1281 unsigned int rulenum,
1282 TC_HANDLE_T *handle)
1285 struct chain_head *c;
1286 struct rule_head *r;
1288 iptc_fn = TC_ZERO_COUNTER;
1291 if (!(c = find_label(chain, *handle))
1292 || !(r = ruleh_get_n(c, rulenum))) {
1297 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1298 r->counter_map.maptype = COUNTER_MAP_ZEROED;
1300 set_changed(*handle);
1306 TC_SET_COUNTER(const IPT_CHAINLABEL chain,
1307 unsigned int rulenum,
1308 STRUCT_COUNTERS *counters,
1309 TC_HANDLE_T *handle)
1312 struct chain_head *c;
1313 struct rule_head *r;
1315 iptc_fn = TC_SET_COUNTER;
1318 if (!(c = find_label(chain, *handle))
1319 || !(r = ruleh_get_n(c, rulenum))) {
1324 r->counter_map.maptype = COUNTER_MAP_SET;
1325 memcpy(&r->entry->counters, counters, sizeof(STRUCT_COUNTERS));
1327 set_changed(*handle);
1332 /* Creates a new chain. */
1333 /* To create a chain, create two rules: error node and unconditional
1336 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1341 struct ipt_error_target name;
1345 STRUCT_STANDARD_TARGET target;
1347 struct rule_head *newr1, *newr2;
1348 struct chain_head *chead;
1350 iptc_fn = TC_CREATE_CHAIN;
1352 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1354 if (find_label(chain, *handle)
1355 || strcmp(chain, LABEL_DROP) == 0
1356 || strcmp(chain, LABEL_ACCEPT) == 0
1357 || strcmp(chain, LABEL_QUEUE) == 0
1358 || strcmp(chain, LABEL_RETURN) == 0) {
1363 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1368 chead = chainh_alloc(*handle, chain);
1374 newr1 = ruleh_alloc(sizeof(*newc1));
1379 newc1 = (struct chainstart *) newr1->entry;
1381 newr2 = ruleh_alloc(sizeof(*newc2));
1387 newc2 = (struct chainend *) newr2->entry;
1389 newc1->head.target_offset = sizeof(STRUCT_ENTRY);
1390 newc1->head.next_offset
1391 = sizeof(STRUCT_ENTRY)
1392 + ALIGN(sizeof(struct ipt_error_target));
1393 strcpy(newc1->name.t.u.user.name, ERROR_TARGET);
1394 newc1->name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
1395 strcpy(newc1->name.error, chain);
1397 newc2->ret.target_offset = sizeof(STRUCT_ENTRY);
1398 newc2->ret.next_offset
1399 = sizeof(STRUCT_ENTRY)
1400 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1401 strcpy(newc2->target.target.u.user.name, STANDARD_TARGET);
1402 newc2->target.target.u.target_size
1403 = ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1404 newc2->target.verdict = RETURN;
1406 list_prepend(&newr1->list, &chead->rules);
1407 chead->firstrule = newr1;
1408 list_append(&newr2->list, &chead->rules);
1409 chead->lastrule = newr2;
1416 count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
1418 STRUCT_STANDARD_TARGET *t;
1420 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
1421 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1423 if (t->verdict == offset)
1430 /* Get the number of references to this chain. */
1432 TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
1433 TC_HANDLE_T *handle)
1435 struct chain_cache *c;
1437 if (!(c = find_label(chain, *handle))) {
1443 ENTRY_ITERATE((*handle)->entries.entrytable,
1444 (*handle)->entries.size,
1445 count_ref, c->start_off, ref);
1451 count_rules(struct chain_head *chainh)
1453 unsigned int numrules = 0;
1454 struct list_head *cur;
1456 list_for_each(cur, &chainh->rules) {
1466 /* Deletes a chain. */
1468 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1470 unsigned int references;
1471 struct chain_head *chainh;
1474 if (!TC_GET_REFERENCES(&references, chain, handle))
1477 iptc_fn = TC_DELETE_CHAIN;
1479 if (TC_BUILTIN(chain, *handle)) {
1484 if (references > 0) {
1490 if (!(chainh = find_label(chain, *handle))) {
1495 if (!(count_rules(chainh) == 0)) {
1500 chainh_free(chainh);
1504 /* Renames a chain. */
1505 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
1506 const IPT_CHAINLABEL newname,
1507 TC_HANDLE_T *handle)
1509 struct chain_head *c;
1510 struct rule_head *ruleh;
1511 struct ipt_error_target *t;
1513 iptc_fn = TC_RENAME_CHAIN;
1515 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1517 if (find_label(newname, *handle)
1518 || strcmp(newname, LABEL_DROP) == 0
1519 || strcmp(newname, LABEL_ACCEPT) == 0
1520 || strcmp(newname, LABEL_QUEUE) == 0
1521 || strcmp(newname, LABEL_RETURN) == 0) {
1526 if (!(c = find_label(oldname, *handle))
1527 || TC_BUILTIN(oldname, *handle)) {
1532 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1537 ruleh = list_entry(&c->rules.next, struct rule_head, list);
1539 t = (struct ipt_error_target *)
1540 GET_TARGET(ruleh->entry);
1542 memset(t->error, 0, sizeof(t->error));
1543 strcpy(t->error, newname);
1548 /* Sets the policy on a built-in chain. */
1550 TC_SET_POLICY(const IPT_CHAINLABEL chain,
1551 const IPT_CHAINLABEL policy,
1552 STRUCT_COUNTERS *counters,
1553 TC_HANDLE_T *handle)
1557 struct chain_head *chainh;
1558 struct rule_head *policyrh;
1560 STRUCT_STANDARD_TARGET *t;
1562 iptc_fn = TC_SET_POLICY;
1563 /* Figure out which chain. */
1564 hook = TC_BUILTIN(chain, *handle);
1571 if (!(chainh = find_label(chain, *handle))) {
1576 policyrh = chainh->lastrule;
1578 printf("ERROR: Policy for `%s' non-existant", chain);
1582 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(policyrh->entry);
1584 if (strcmp(policy, LABEL_ACCEPT) == 0)
1585 t->verdict = -NF_ACCEPT - 1;
1586 else if (strcmp(policy, LABEL_DROP) == 0)
1587 t->verdict = -NF_DROP - 1;
1593 ctrindex = entry2index(*handle, e);
1596 /* set byte and packet counters */
1597 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
1599 policyrh->counter_map.maptype = COUNTER_MAP_SET;
1602 policyrh->counter_map.maptype = COUNTER_MAP_NOMAP;
1603 policyrh->counter_map.mappos = 0;
1606 set_changed(*handle);
1611 /* Without this, on gcc 2.7.2.3, we get:
1612 libiptc.c: In function `TC_COMMIT':
1613 libiptc.c:833: fixed or forbidden register was spilled.
1614 This may be due to a compiler bug or to impossible asm
1615 statements or clauses.
1618 subtract_counters(STRUCT_COUNTERS *answer,
1619 const STRUCT_COUNTERS *a,
1620 const STRUCT_COUNTERS *b)
1622 answer->pcnt = a->pcnt - b->pcnt;
1623 answer->bcnt = a->bcnt - b->bcnt;
1627 TC_COMMIT(TC_HANDLE_T *handle)
1629 /* Replace, then map back the counters. */
1630 STRUCT_REPLACE *repl;
1631 STRUCT_COUNTERS_INFO *newcounters;
1637 counterlen = sizeof(STRUCT_COUNTERS_INFO)
1638 + sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
1641 TC_DUMP_ENTRIES(*handle);
1644 /* Don't commit if nothing changed. */
1645 if (!(*handle)->changed)
1648 repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1654 /* These are the old counters we will get from kernel */
1655 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1656 * (*handle)->info.num_entries);
1657 if (!repl->counters) {
1663 /* These are the counters we're going to put back, later. */
1664 newcounters = malloc(counterlen);
1666 free(repl->counters);
1672 strcpy(repl->name, (*handle)->info.name);
1673 repl->num_entries = (*handle)->new_number;
1674 repl->size = (*handle)->entries.size;
1675 memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1676 sizeof(repl->hook_entry));
1677 memcpy(repl->underflow, (*handle)->info.underflow,
1678 sizeof(repl->underflow));
1679 repl->num_counters = (*handle)->info.num_entries;
1680 repl->valid_hooks = (*handle)->info.valid_hooks;
1681 memcpy(repl->entries, (*handle)->entries.entrytable,
1682 (*handle)->entries.size);
1684 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
1685 sizeof(*repl) + (*handle)->entries.size) < 0) {
1686 free(repl->counters);
1692 /* Put counters back. */
1693 strcpy(newcounters->name, (*handle)->info.name);
1694 newcounters->num_counters = (*handle)->new_number;
1695 for (i = 0; i < (*handle)->new_number; i++) {
1696 unsigned int mappos = (*handle)->counter_map[i].mappos;
1697 switch ((*handle)->counter_map[i].maptype) {
1698 case COUNTER_MAP_NOMAP:
1699 newcounters->counters[i]
1700 = ((STRUCT_COUNTERS){ 0, 0 });
1703 case COUNTER_MAP_NORMAL_MAP:
1704 /* Original read: X.
1705 * Atomic read on replacement: X + Y.
1706 * Currently in kernel: Z.
1707 * Want in kernel: X + Y + Z.
1709 * => Add in replacement read.
1711 newcounters->counters[i] = repl->counters[mappos];
1714 case COUNTER_MAP_ZEROED:
1715 /* Original read: X.
1716 * Atomic read on replacement: X + Y.
1717 * Currently in kernel: Z.
1718 * Want in kernel: Y + Z.
1720 * => Add in (replacement read - original read).
1722 subtract_counters(&newcounters->counters[i],
1723 &repl->counters[mappos],
1724 &index2entry(*handle, i)->counters);
1727 case COUNTER_MAP_SET:
1728 /* Want to set counter (iptables-restore) */
1730 memcpy(&newcounters->counters[i],
1731 &index2entry(*handle, i)->counters,
1732 sizeof(STRUCT_COUNTERS));
1738 #ifdef KERNEL_64_USERSPACE_32
1740 /* Kernel will think that pointer should be 64-bits, and get
1741 padding. So we accomodate here (assumption: alignment of
1742 `counters' is on 64-bit boundary). */
1743 u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
1744 if ((unsigned long)&newcounters->counters % 8 != 0) {
1746 "counters alignment incorrect! Mail rusty!\n");
1749 *kernptr = newcounters->counters;
1751 #endif /* KERNEL_64_USERSPACE_32 */
1753 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
1754 newcounters, counterlen) < 0) {
1755 free(repl->counters);
1761 free(repl->counters);
1770 /* Get raw socket. */
1777 /* Translates errno numbers into more human-readable form than strerror. */
1779 TC_STRERROR(int err)
1782 struct table_struct {
1785 const char *message;
1787 { { TC_INIT, EPERM, "Permission denied (you must be root)" },
1788 { TC_INIT, EINVAL, "Module is wrong version" },
1790 "Table does not exist (do you need to insmod?)" },
1791 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
1792 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
1793 { TC_DELETE_CHAIN, EMLINK,
1794 "Can't delete chain with references left" },
1795 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
1796 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
1797 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
1798 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
1799 { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
1800 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
1801 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
1802 { TC_INSERT_ENTRY, EINVAL, "Target problem" },
1803 /* EINVAL for CHECK probably means bad interface. */
1804 { TC_CHECK_PACKET, EINVAL,
1805 "Bad arguments (does that interface exist?)" },
1806 { TC_CHECK_PACKET, ENOSYS,
1807 "Checking will most likely never get implemented" },
1808 /* ENOENT for DELETE probably means no matching rule */
1809 { TC_DELETE_ENTRY, ENOENT,
1810 "Bad rule (does a matching rule exist in that chain?)" },
1811 { TC_SET_POLICY, ENOENT,
1812 "Bad built-in chain name" },
1813 { TC_SET_POLICY, EINVAL,
1814 "Bad policy name" },
1816 { NULL, 0, "Incompatible with this kernel" },
1817 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1818 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
1819 { NULL, ENOMEM, "Memory allocation problem" },
1820 { NULL, ENOENT, "No chain/target/match by that name" },
1823 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1824 if ((!table[i].fn || table[i].fn == iptc_fn)
1825 && table[i].err == err)
1826 return table[i].message;
1829 return strerror(err);