1 /* Library which manipulates firewall rules. Version $Revision: 1.40 $ */
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 * - total reimplementation
24 #include "linux_listhelp.h"
27 #define IPT_LIB_DIR "/usr/lib/iptables"
30 static int sockfd = -1;
31 static void *iptc_fn = NULL;
33 static const char *hooknames[]
34 = { [HOOK_PRE_ROUTING] "PREROUTING",
35 [HOOK_LOCAL_IN] "INPUT",
36 [HOOK_FORWARD] "FORWARD",
37 [HOOK_LOCAL_OUT] "OUTPUT",
38 [HOOK_POST_ROUTING] "POSTROUTING",
40 [HOOK_DROPPING] "DROPPING"
48 COUNTER_MAP_NORMAL_MAP,
55 /* Convenience structures */
56 struct ipt_error_target
58 STRUCT_ENTRY_TARGET t;
59 char error[TABLE_MAXNAMELEN];
64 struct list_head list; /* list of rules in chain */
66 struct chain_head *chain; /* we're part of this chain */
67 struct rule_head *target; /* target of this rule, in case
71 unsigned int size; /* size of rule */
72 STRUCT_ENTRY *entry_blob; /* pointer to entry in blob */
73 STRUCT_ENTRY entry[0];
78 struct list_head list;
80 char name[TABLE_MAXNAMELEN];
82 struct list_head rules;
87 /* Have changes been made? */
90 /* linked list of chains in this table */
91 struct list_head chains;
93 /* current position of first_chain() / next_chain() */
94 struct chain_head *chain_iterator_cur;
96 /* current position of first_rule() / next_rule() */
97 struct rule_head *rule_iterator_cur;
99 struct counter_map *counter_map;
101 /* the structure we receive from getsockopt() */
104 /* Array of hook names */
105 const char **hooknames;
107 /* Size in here reflects original state. */
110 /* Cached position of chain heads (NULL = no cache). */
111 unsigned int cache_num_chains;
112 unsigned int cache_num_builtins;
113 struct chain_cache *cache_chain_heads;
115 /* Chain iterator: current chain cache entry. */
116 struct chain_cache *cache_chain_iteration;
118 /* Rule iterator: terminal rule */
119 STRUCT_ENTRY *cache_rule_end;
121 /* Number in here reflects current state. */
122 unsigned int new_number;
124 STRUCT_GET_ENTRIES entries;
128 set_changed(TC_HANDLE_T h)
134 static void do_check(TC_HANDLE_T h, unsigned int line);
135 #define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
140 static struct rule_head *ruleh_alloc(unsigned int size)
142 struct rule_head *ruleh = malloc(sizeof(*ruleh)+size);
146 memset(ruleh, 0, sizeof(*ruleh)+size);
152 static void ruleh_free(struct rule_head *ruleh)
154 list_del(&ruleh->list);
158 static struct rule_head *ruleh_get_n(struct chain_head *chain, int num)
163 static struct chain_head *chainh_alloc(TC_HANDLE_T h, const char *name)
165 struct chain_head *chainh = malloc(sizeof(*chainh));
169 memset(chainh, 0, sizeof(*chainh));
170 strncpy(chainh->name, name, sizeof(&chainh->name));
171 list_append(&chainh->list, &h->chains);
177 chainh_free(struct chain_head *chainh)
180 struct list_head *cur_item, *item2;
182 list_for_each_safe(cur_item, item2, &chainh->rules) {
183 struct rule_head *ruleh = list_entry(cur_item,
189 list_del(&chainh->list);
194 get_number(const STRUCT_ENTRY *i,
195 const STRUCT_ENTRY *seek,
205 static struct chain_head *
206 chainh_find(TC_HANDLE_T h, const IPT_CHAINLABEL name)
208 struct list_head *cur;
210 list_for_each(cur, &h->chains) {
211 struct chain_head *ch = list_entry(cur, struct chain_head,
213 if (!strcmp(name, ch->name))
219 static inline unsigned long
220 entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
222 return (void *)e - (void *)h->entries.entrytable;
227 entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
229 unsigned int pos = 0;
231 if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
232 get_number, seek, &pos) == 0) {
233 fprintf(stderr, "ERROR: offset %i not an entry!\n",
234 (char *)seek - (char *)h->entries.entrytable);
241 get_entry_n(STRUCT_ENTRY *i,
246 if (*pos == number) {
254 static STRUCT_ENTRY *
255 index2entry(TC_HANDLE_T h, unsigned int index)
257 unsigned int pos = 0;
258 STRUCT_ENTRY *ret = NULL;
260 ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
261 get_entry_n, index, &pos, &ret);
266 static inline STRUCT_ENTRY *
267 get_entry(TC_HANDLE_T h, unsigned int offset)
269 return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
273 static inline unsigned long
274 index2offset(TC_HANDLE_T h, unsigned int index)
276 return entry2offset(h, index2entry(h, index));
279 static inline STRUCT_ENTRY *
280 offset2entry(TC_HANDLE_T h, unsigned int offset)
282 return (STRUCT_ENTRY *) ((void *)h->entries.entrytable+offset);
285 static inline unsigned int
286 offset2index(const TC_HANDLE_T h, unsigned int offset)
288 return entry2index(h, offset2entry(h, offset));
293 get_errorlabel(TC_HANDLE_T h, unsigned int offset)
297 e = get_entry(h, offset);
298 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) {
299 fprintf(stderr, "ERROR: offset %u not an error node!\n",
304 return (const char *)GET_TARGET(e)->data;
308 /* Allocate handle of given size */
310 alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
315 len = sizeof(STRUCT_TC_HANDLE)
317 + num_rules * sizeof(struct counter_map);
319 if ((h = malloc(len)) == NULL) {
326 h->counter_map = (void *)h
327 + sizeof(STRUCT_TC_HANDLE)
329 strcpy(h->info.name, tablename);
330 strcpy(h->entries.name, tablename);
331 INIT_LIST_HEAD(&h->chains);
337 append_entrycopy(STRUCT_ENTRY *e, struct chain_head *chain)
339 struct rule_head *ruleh = ruleh_alloc(e->next_offset);
343 memcpy(&ruleh->entry, e, e->next_offset);
344 ruleh->chain = chain;
345 ruleh->entry_blob = e;
346 list_append(&ruleh->list, &chain->rules);
352 /* have to return 0 on success, bcf ENTRY_ITERATE */
354 parse_entry(STRUCT_ENTRY *e, TC_HANDLE_T h, struct chain_head **curchain)
358 STRUCT_ENTRY_TARGET ent;
359 STRUCT_STANDARD_TARGET std;
360 struct ipt_error_target err;
363 tgt = (union tgt_u *) GET_TARGET(e);
365 if (e->target_offset == sizeof(STRUCT_ENTRY)
366 && (strcmp(tgt->ent.u.user.name, IPT_STANDARD_TARGET) == 0)) {
367 /* jump to somewhere else */
368 append_entrycopy(e, *curchain);
370 } else if (e->target_offset == sizeof(STRUCT_ENTRY)
371 && e->next_offset == sizeof(STRUCT_ENTRY)
372 + ALIGN(sizeof(struct ipt_error_target))
373 && !strcmp(tgt->ent.u.user.name, ERROR_TARGET)) {
375 *curchain = chainh_find(h, tgt->err.error);
377 /* FIXME: error handling */
381 *curchain = chainh_alloc(h, tgt->err.error);
382 /* FIXME: error handling */
383 append_entrycopy(e, *curchain);
384 } else if (e->target_offset == sizeof(STRUCT_ENTRY)
385 && e->next_offset == sizeof(STRUCT_ENTRY)
386 + ALIGN(sizeof(STRUCT_STANDARD_TARGET))
387 && tgt->std.verdict == RETURN) {
389 append_entrycopy(e, *curchain);
393 append_entrycopy(e, *curchain);
396 /* iterate over hook_entries, needed to connect builtin
397 * chains with hook numbers */
398 for (i = 0; i < NUMHOOKS; i++) {
399 if (!(h->info.valid_hooks & (1 << i)))
401 if (h->info.hook_entry[i] == entry2offset(h, e)) {
402 /* found hook entry point */
404 (*curchain)->hooknum = i;
406 if (h->info.underflow[i] == entry2offset(h, e)) {
407 /* found underflow point */
414 static int parse_ruleset(TC_HANDLE_T h)
416 struct chain_head *curchain;
418 /* iterate over ruleset; create linked list of rule_head/chain_head */
419 if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size,
420 parse_entry, h, &curchain)) {
421 /* some error happened while iterating */
429 TC_INIT(const char *tablename)
444 if (strlen(tablename) >= TABLE_MAXNAMELEN) {
449 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
455 strcpy(info.name, tablename);
456 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
459 if ((h = alloc_handle(info.name, info.size, info.num_entries))
468 sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);
469 dynlib = dlopen(pathname, RTLD_NOW);
474 h->hooknames = dlsym(dynlib, "hooknames");
480 h->hooknames = hooknames;
483 /* Initialize current state */
485 //h->new_number = h->info.num_entries;
486 for (i = 0; i < h->info.num_entries; i++)
488 = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});
490 h->entries.size = h->info.size;
492 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
494 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,
509 TC_FREE(TC_HANDLE_T *h)
511 struct list_head *cur_item, *item2;
516 /* free all chains */
517 list_for_each_safe(cur_item, item2, (*h)->chains.next) {
518 struct chain_head *chead = list_entry(cur_item,
524 /* FIXME: free all other ressources we might be using */
531 print_match(const STRUCT_ENTRY_MATCH *m)
533 printf("Match name: `%s'\n", m->u.user.name);
537 static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
541 TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
545 printf("libiptc v%s. %u entries, %u bytes.\n",
547 handle->new_number, handle->entries.size);
548 printf("Table `%s'\n", handle->info.name);
549 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
550 handle->info.hook_entry[HOOK_PRE_ROUTING],
551 handle->info.hook_entry[HOOK_LOCAL_IN],
552 handle->info.hook_entry[HOOK_FORWARD],
553 handle->info.hook_entry[HOOK_LOCAL_OUT],
554 handle->info.hook_entry[HOOK_POST_ROUTING]);
555 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
556 handle->info.underflow[HOOK_PRE_ROUTING],
557 handle->info.underflow[HOOK_LOCAL_IN],
558 handle->info.underflow[HOOK_FORWARD],
559 handle->info.underflow[HOOK_LOCAL_OUT],
560 handle->info.underflow[HOOK_POST_ROUTING]);
562 ENTRY_ITERATE(handle->entries.entrytable, handle->entries.size,
566 /* Returns 0 if not hook entry, else hooknumber + 1 */
567 static inline unsigned int
568 is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
572 for (i = 0; i < NUMHOOKS; i++) {
573 if ((h->info.valid_hooks & (1 << i))
574 && get_entry(h, h->info.hook_entry[i]) == e)
581 static int alphasort(const void *a, const void *b)
583 return strcmp(((struct chain_cache *)a)->name,
584 ((struct chain_cache *)b)->name);
588 /* Returns chain head if found, otherwise NULL. */
589 static struct chain_head *
590 find_label(const char *name, TC_HANDLE_T handle)
592 struct list_head *pos;
594 if (list_empty(&handle->chains))
597 list_for_each(pos, &handle->chains) {
598 struct chain_head *c = list_entry(pos, struct chain_head, list);
599 if (!strcmp(c->name, name))
606 /* Does this chain exist? */
607 int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
609 return find_label(chain, handle) != NULL;
613 /* Returns the position of the final (ie. unconditional) element. */
615 get_chain_end(const TC_HANDLE_T handle, unsigned int start)
617 unsigned int last_off, off;
621 e = get_entry(handle, start);
623 /* Terminate when we meet a error label or a hook entry. */
624 for (off = start + e->next_offset;
625 off < handle->entries.size;
626 last_off = off, off += e->next_offset) {
627 STRUCT_ENTRY_TARGET *t;
630 e = get_entry(handle, off);
632 /* We hit an entry point. */
633 for (i = 0; i < NUMHOOKS; i++) {
634 if ((handle->info.valid_hooks & (1 << i))
635 && off == handle->info.hook_entry[i])
639 /* We hit a user chain label */
641 if (strcmp(t->u.user.name, ERROR_TARGET) == 0)
644 /* SHOULD NEVER HAPPEN */
645 fprintf(stderr, "ERROR: Off end (%u) of chain from %u!\n",
646 handle->entries.size, off);
651 /* Iterator functions to run through the chains. */
653 TC_FIRST_CHAIN(TC_HANDLE_T *handle)
655 struct chain_head *firsthead = list_entry((*handle)->chains.next,
656 struct chain_head, list);
657 (*handle)->chain_iterator_cur = firsthead;
659 return firsthead->name;
662 /* Iterator functions to run through the chains. Returns NULL at end. */
664 TC_NEXT_CHAIN(TC_HANDLE_T *handle)
666 struct chain_head *next = list_entry(&(*handle)->chain_iterator_cur->list.next, struct chain_head, list);
667 (*handle)->chain_iterator_cur = next;
669 if (&next->list == &(*handle)->chains)
675 /* Get first rule in the given chain: NULL for empty chain. */
677 TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
679 struct chain_head *c;
682 c = find_label(chain, *handle);
688 /* Empty chain: single return/policy rule */
689 if (list_empty(&c->rules))
692 r = list_entry(c->rules.next, struct rule_head, list);
693 (*handle)->rule_iterator_cur = r;
698 /* Returns NULL when rules run out. */
700 TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
702 struct rule_head *r = list_entry((*handle)->rule_iterator_cur->list.next, struct rule_head, list);
704 if (&r->list == &r->chain->rules)
707 /* NOTE: prev is without any influence ! */
712 /* How many rules in this chain? */
714 TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
716 unsigned int off = 0;
717 STRUCT_ENTRY *start, *end;
720 if (!find_label(&off, chain, *handle)) {
722 return (unsigned int)-1;
725 start = get_entry(*handle, off);
726 end = get_entry(*handle, get_chain_end(*handle, off));
728 return entry2index(*handle, end) - entry2index(*handle, start);
731 /* Get n'th rule in this chain. */
732 const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
736 unsigned int pos = 0, chainindex;
739 if (!find_label(&pos, chain, *handle)) {
744 chainindex = entry2index(*handle, get_entry(*handle, pos));
746 return index2entry(*handle, chainindex + n);
751 target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
754 unsigned int labelidx;
755 STRUCT_ENTRY *jumpto;
757 /* To avoid const warnings */
758 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
760 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0)
761 return GET_TARGET(e)->u.user.name;
763 /* Standard target: evaluate */
764 spos = *(int *)GET_TARGET(e)->data;
768 else if (spos == -NF_ACCEPT-1)
770 else if (spos == -NF_DROP-1)
772 else if (spos == -NF_QUEUE-1)
775 fprintf(stderr, "ERROR: off %lu/%u not a valid target (%d)\n",
776 entry2offset(handle, e), handle->entries.size,
781 jumpto = get_entry(handle, spos);
783 /* Fall through rule */
784 if (jumpto == (void *)e + e->next_offset)
787 /* Must point to head of a chain: ie. after error rule */
788 /* FIXME: this needs to deal with internal jump targets */
789 labelidx = entry2index(handle, jumpto) - 1;
790 return get_errorlabel(handle, index2offset(handle, labelidx));
793 /* Returns a pointer to the target name of this position. */
794 const char *TC_GET_TARGET(const STRUCT_ENTRY *e,
797 return target_name(*handle, e);
800 /* Is this a built-in chain? Actually returns hook + 1. */
802 TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
806 for (i = 0; i < NUMHOOKS; i++) {
807 if ((handle->info.valid_hooks & (1 << i))
808 && handle->hooknames[i]
809 && strcmp(handle->hooknames[i], chain) == 0)
815 /* Get the policy of a given built-in chain */
817 TC_GET_POLICY(const char *chain,
818 STRUCT_COUNTERS *counters,
825 hook = TC_BUILTIN(chain, *handle);
827 start = (*handle)->info.hook_entry[hook-1];
831 e = get_entry(*handle, get_chain_end(*handle, start));
832 *counters = e->counters;
834 return target_name(*handle, e);
838 correct_verdict(STRUCT_ENTRY *e,
840 unsigned int offset, int delta_offset)
842 STRUCT_STANDARD_TARGET *t = (void *)GET_TARGET(e);
843 unsigned int curr = (char *)e - base;
845 /* Trap: insert of fall-through rule. Don't change fall-through
846 verdict to jump-over-next-rule. */
847 if (strcmp(t->target.u.user.name, STANDARD_TARGET) == 0
848 && t->verdict > (int)offset
849 && !(curr == offset &&
850 t->verdict == curr + e->next_offset)) {
851 t->verdict += delta_offset;
857 /* Adjusts standard verdict jump positions after an insertion/deletion. */
859 set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle)
861 ENTRY_ITERATE((*handle)->entries.entrytable,
862 (*handle)->entries.size,
863 correct_verdict, (char *)(*handle)->entries.entrytable,
864 offset, delta_offset);
866 set_changed(*handle);
870 /* If prepend is set, then we are prepending to a chain: if the
871 * insertion position is an entry point, keep the entry point. */
873 insert_rules(unsigned int num_rules, unsigned int rules_size,
874 const STRUCT_ENTRY *insert,
875 unsigned int offset, unsigned int num_rules_offset,
880 STRUCT_GETINFO newinfo;
883 if (offset >= (*handle)->entries.size) {
888 newinfo = (*handle)->info;
890 /* Fix up entry points. */
891 for (i = 0; i < NUMHOOKS; i++) {
892 /* Entry points to START of chain, so keep same if
893 inserting on at that point. */
894 if ((*handle)->info.hook_entry[i] > offset)
895 newinfo.hook_entry[i] += rules_size;
897 /* Underflow always points to END of chain (policy),
898 so if something is inserted at same point, it
899 should be advanced. */
900 if ((*handle)->info.underflow[i] >= offset)
901 newinfo.underflow[i] += rules_size;
904 newh = alloc_handle((*handle)->info.name,
905 (*handle)->entries.size + rules_size,
906 (*handle)->new_number + num_rules);
909 newh->info = newinfo;
912 memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset);
913 /* ... Insert new ... */
914 memcpy((char *)newh->entries.entrytable + offset, insert, rules_size);
916 memcpy((char *)newh->entries.entrytable + offset + rules_size,
917 (char *)(*handle)->entries.entrytable + offset,
918 (*handle)->entries.size - offset);
920 /* Move counter map. */
922 memcpy(newh->counter_map, (*handle)->counter_map,
923 sizeof(struct counter_map) * num_rules_offset);
925 memcpy(newh->counter_map + num_rules_offset + num_rules,
926 (*handle)->counter_map + num_rules_offset,
927 sizeof(struct counter_map) * ((*handle)->new_number
928 - num_rules_offset));
929 /* Set intermediates to no counter copy */
930 for (i = 0; i < num_rules; i++)
931 newh->counter_map[num_rules_offset+i]
932 = ((struct counter_map){ COUNTER_MAP_SET, 0 });
934 newh->new_number = (*handle)->new_number + num_rules;
935 newh->entries.size = (*handle)->entries.size + rules_size;
936 newh->hooknames = (*handle)->hooknames;
938 if ((*handle)->cache_chain_heads)
939 free((*handle)->cache_chain_heads);
943 return set_verdict(offset, rules_size, handle);
947 delete_rules(unsigned int num_rules, unsigned int rules_size,
948 unsigned int offset, unsigned int num_rules_offset,
953 if (offset + rules_size > (*handle)->entries.size) {
958 /* Fix up entry points. */
959 for (i = 0; i < NUMHOOKS; i++) {
960 /* In practice, we never delete up to a hook entry,
961 since the built-in chains are always first,
962 so these two are never equal */
963 if ((*handle)->info.hook_entry[i] >= offset + rules_size)
964 (*handle)->info.hook_entry[i] -= rules_size;
965 else if ((*handle)->info.hook_entry[i] > offset) {
966 fprintf(stderr, "ERROR: Deleting entry %u %u %u\n",
967 i, (*handle)->info.hook_entry[i], offset);
971 /* Underflow points to policy (terminal) rule in
972 built-in, so sequality is valid here (when deleting
974 if ((*handle)->info.underflow[i] >= offset + rules_size)
975 (*handle)->info.underflow[i] -= rules_size;
976 else if ((*handle)->info.underflow[i] > offset) {
977 fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n",
978 i, (*handle)->info.underflow[i], offset);
983 /* Move the rules down. */
984 memmove((char *)(*handle)->entries.entrytable + offset,
985 (char *)(*handle)->entries.entrytable + offset + rules_size,
986 (*handle)->entries.size - (offset + rules_size));
988 /* Move the counter map down. */
989 memmove(&(*handle)->counter_map[num_rules_offset],
990 &(*handle)->counter_map[num_rules_offset + num_rules],
991 sizeof(struct counter_map)
992 * ((*handle)->new_number - (num_rules + num_rules_offset)));
995 (*handle)->new_number -= num_rules;
996 (*handle)->entries.size -= rules_size;
998 return set_verdict(offset, -(int)rules_size, handle);
1002 standard_map(STRUCT_ENTRY *e, int verdict)
1004 STRUCT_STANDARD_TARGET *t;
1006 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1008 if (t->target.u.target_size
1009 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1013 /* memset for memcmp convenience on delete/replace */
1014 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
1015 strcpy(t->target.u.user.name, STANDARD_TARGET);
1016 t->verdict = verdict;
1022 map_target(const TC_HANDLE_T handle,
1024 unsigned int offset,
1025 STRUCT_ENTRY_TARGET *old)
1027 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1029 /* Save old target (except data, which we don't change, except for
1030 standard case, where we don't care). */
1033 /* Maybe it's empty (=> fall through) */
1034 if (strcmp(t->u.user.name, "") == 0)
1035 return standard_map(e, offset + e->next_offset);
1036 /* Maybe it's a standard target name... */
1037 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
1038 return standard_map(e, -NF_ACCEPT - 1);
1039 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
1040 return standard_map(e, -NF_DROP - 1);
1041 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
1042 return standard_map(e, -NF_QUEUE - 1);
1043 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
1044 return standard_map(e, RETURN);
1045 else if (TC_BUILTIN(t->u.user.name, handle)) {
1046 /* Can't jump to builtins. */
1050 /* Maybe it's an existing chain name. */
1051 struct chain_cache *c;
1053 c = find_label(t->u.user.name, handle);
1055 return standard_map(e, c->start_off);
1058 /* Must be a module? If not, kernel will reject... */
1059 /* memset to all 0 for your memcmp convenience. */
1060 memset(t->u.user.name + strlen(t->u.user.name),
1062 FUNCTION_MAXNAMELEN - strlen(t->u.user.name));
1067 unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
1069 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
1071 /* Save old target (except data, which we don't change, except for
1072 standard case, where we don't care). */
1076 /* Insert the entry `fw' in chain `chain' into position `rulenum'. */
1078 TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1079 const STRUCT_ENTRY *e,
1080 unsigned int rulenum,
1081 TC_HANDLE_T *handle)
1083 unsigned int chainindex, offset;
1084 STRUCT_ENTRY_TARGET old;
1085 struct chain_cache *c;
1089 iptc_fn = TC_INSERT_ENTRY;
1090 if (!(c = find_label(chain, *handle))) {
1095 chainindex = offset2index(*handle, c->start_off);
1097 tmp = index2entry(*handle, chainindex + rulenum);
1098 if (!tmp || tmp > offset2entry(*handle, c->end_off)) {
1102 offset = index2offset(*handle, chainindex + rulenum);
1104 /* Mapping target actually alters entry, but that's
1105 transparent to the caller. */
1106 if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
1109 ret = insert_rules(1, e->next_offset, e, offset,
1110 chainindex + rulenum, rulenum == 0, handle);
1111 unmap_target((STRUCT_ENTRY *)e, &old);
1115 /* Atomically replace rule `rulenum' in `chain' with `fw'. */
1117 TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1118 const STRUCT_ENTRY *e,
1119 unsigned int rulenum,
1120 TC_HANDLE_T *handle)
1122 unsigned int chainindex, offset;
1123 STRUCT_ENTRY_TARGET old;
1124 struct chain_cache *c;
1128 iptc_fn = TC_REPLACE_ENTRY;
1130 if (!(c = find_label(chain, *handle))) {
1135 chainindex = offset2index(*handle, c->start_off);
1137 tmp = index2entry(*handle, chainindex + rulenum);
1138 if (!tmp || tmp >= offset2entry(*handle, c->end_off)) {
1143 offset = index2offset(*handle, chainindex + rulenum);
1144 /* Replace = delete and insert. */
1145 if (!delete_rules(1, get_entry(*handle, offset)->next_offset,
1146 offset, chainindex + rulenum, handle))
1149 if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
1152 ret = insert_rules(1, e->next_offset, e, offset,
1153 chainindex + rulenum, 1, handle);
1154 unmap_target((STRUCT_ENTRY *)e, &old);
1158 /* Append entry `fw' to chain `chain'. Equivalent to insert with
1159 rulenum = length of chain. */
1161 TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1162 const STRUCT_ENTRY *e,
1163 TC_HANDLE_T *handle)
1165 struct chain_cache *c;
1166 STRUCT_ENTRY_TARGET old;
1169 iptc_fn = TC_APPEND_ENTRY;
1170 if (!(c = find_label(chain, *handle))) {
1175 if (!map_target(*handle, (STRUCT_ENTRY *)e,
1179 ret = insert_rules(1, e->next_offset, e, c->end_off,
1180 offset2index(*handle, c->end_off), 0, handle);
1181 unmap_target((STRUCT_ENTRY *)e, &old);
1186 match_different(const STRUCT_ENTRY_MATCH *a,
1187 const unsigned char *a_elems,
1188 const unsigned char *b_elems,
1189 unsigned char **maskptr)
1191 const STRUCT_ENTRY_MATCH *b;
1194 /* Offset of b is the same as a. */
1195 b = (void *)b_elems + ((unsigned char *)a - a_elems);
1197 if (a->u.match_size != b->u.match_size)
1200 if (strcmp(a->u.user.name, b->u.user.name) != 0)
1203 *maskptr += ALIGN(sizeof(*a));
1205 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
1206 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
1213 target_different(const unsigned char *a_targdata,
1214 const unsigned char *b_targdata,
1215 unsigned int tdatasize,
1216 const unsigned char *mask)
1219 for (i = 0; i < tdatasize; i++)
1220 if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0)
1227 is_same(const STRUCT_ENTRY *a,
1228 const STRUCT_ENTRY *b,
1229 unsigned char *matchmask);
1231 /* Delete the first rule in `chain' which matches `fw'. */
1233 TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
1234 const STRUCT_ENTRY *origfw,
1235 unsigned char *matchmask,
1236 TC_HANDLE_T *handle)
1238 unsigned int offset;
1239 struct chain_cache *c;
1240 STRUCT_ENTRY *e, *fw;
1242 iptc_fn = TC_DELETE_ENTRY;
1243 if (!(c = find_label(chain, *handle))) {
1248 fw = malloc(origfw->next_offset);
1254 for (offset = c->start_off; offset < c->end_off;
1255 offset += e->next_offset) {
1256 STRUCT_ENTRY_TARGET discard;
1258 memcpy(fw, origfw, origfw->next_offset);
1260 /* FIXME: handle this in is_same --RR */
1261 if (!map_target(*handle, fw, offset, &discard)) {
1265 e = get_entry(*handle, offset);
1268 printf("Deleting:\n");
1271 if (is_same(e, fw, matchmask)) {
1273 ret = delete_rules(1, e->next_offset,
1274 offset, entry2index(*handle, e),
1286 /* Delete the rule in position `rulenum' in `chain'. */
1288 TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
1289 unsigned int rulenum,
1290 TC_HANDLE_T *handle)
1295 struct chain_cache *c;
1297 iptc_fn = TC_DELETE_NUM_ENTRY;
1298 if (!(c = find_label(chain, *handle))) {
1303 index = offset2index(*handle, c->start_off) + rulenum;
1305 if (index >= offset2index(*handle, c->end_off)) {
1310 e = index2entry(*handle, index);
1316 ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
1321 /* Check the packet `fw' on chain `chain'. Returns the verdict, or
1322 NULL and sets errno. */
1324 TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
1325 STRUCT_ENTRY *entry,
1326 TC_HANDLE_T *handle)
1332 /* Flushes the entries in the given chain (ie. empties chain). */
1334 TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1336 unsigned int startindex, endindex;
1337 STRUCT_ENTRY *startentry, *endentry;
1338 struct chain_cache *c;
1341 iptc_fn = TC_FLUSH_ENTRIES;
1342 if (!(c = find_label(chain, *handle))) {
1346 startindex = offset2index(*handle, c->start_off);
1347 endindex = offset2index(*handle, c->end_off);
1348 startentry = offset2entry(*handle, c->start_off);
1349 endentry = offset2entry(*handle, c->end_off);
1351 ret = delete_rules(endindex - startindex,
1352 (char *)endentry - (char *)startentry,
1353 c->start_off, startindex,
1358 /* Zeroes the counters in a chain. */
1360 TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1362 unsigned int i, end;
1363 struct chain_cache *c;
1365 if (!(c = find_label(chain, *handle))) {
1370 i = offset2index(*handle, c->start_off);
1371 end = offset2index(*handle, c->end_off);
1373 for (; i <= end; i++) {
1374 if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP)
1375 (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED;
1377 set_changed(*handle);
1383 TC_READ_COUNTER(const IPT_CHAINLABEL chain,
1384 unsigned int rulenum,
1385 TC_HANDLE_T *handle)
1388 struct chain_cache *c;
1389 unsigned int chainindex, end;
1391 iptc_fn = TC_READ_COUNTER;
1394 if (!(c = find_label(chain, *handle))) {
1399 chainindex = offset2index(*handle, c->start_off);
1400 end = offset2index(*handle, c->end_off);
1402 if (chainindex + rulenum > end) {
1407 e = index2entry(*handle, chainindex + rulenum);
1409 return &e->counters;
1413 TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
1414 unsigned int rulenum,
1415 TC_HANDLE_T *handle)
1418 struct chain_cache *c;
1419 unsigned int chainindex, end;
1421 iptc_fn = TC_ZERO_COUNTER;
1424 if (!(c = find_label(chain, *handle))) {
1429 chainindex = offset2index(*handle, c->start_off);
1430 end = offset2index(*handle, c->end_off);
1432 if (chainindex + rulenum > end) {
1437 e = index2entry(*handle, chainindex + rulenum);
1439 if ((*handle)->counter_map[chainindex + rulenum].maptype
1440 == COUNTER_MAP_NORMAL_MAP) {
1441 (*handle)->counter_map[chainindex + rulenum].maptype
1442 = COUNTER_MAP_ZEROED;
1445 set_changed(*handle);
1451 TC_SET_COUNTER(const IPT_CHAINLABEL chain,
1452 unsigned int rulenum,
1453 STRUCT_COUNTERS *counters,
1454 TC_HANDLE_T *handle)
1457 struct chain_cache *c;
1458 unsigned int chainindex, end;
1460 iptc_fn = TC_SET_COUNTER;
1463 if (!(c = find_label(chain, *handle))) {
1468 chainindex = offset2index(*handle, c->start_off);
1469 end = offset2index(*handle, c->end_off);
1471 if (chainindex + rulenum > end) {
1476 e = index2entry(*handle, chainindex + rulenum);
1478 (*handle)->counter_map[chainindex + rulenum].maptype
1481 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
1483 set_changed(*handle);
1488 /* Creates a new chain. */
1489 /* To create a chain, create two rules: error node and unconditional
1492 TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1497 struct ipt_error_target name;
1501 STRUCT_STANDARD_TARGET target;
1503 struct chain_head *chead;
1505 iptc_fn = TC_CREATE_CHAIN;
1507 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1509 if (find_label(chain, *handle)
1510 || strcmp(chain, LABEL_DROP) == 0
1511 || strcmp(chain, LABEL_ACCEPT) == 0
1512 || strcmp(chain, LABEL_QUEUE) == 0
1513 || strcmp(chain, LABEL_RETURN) == 0) {
1518 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
1523 chead = chainh_alloc(*handle, chain);
1529 newc1 = ruleh_alloc(sizeof(*newc1));
1535 newc2 = ruleh_alloc(sizeof(*newc2));
1542 newc1->head.target_offset = sizeof(STRUCT_ENTRY);
1543 newc1->head.next_offset
1544 = sizeof(STRUCT_ENTRY)
1545 + ALIGN(sizeof(struct ipt_error_target));
1546 strcpy(newc1->name.t.u.user.name, ERROR_TARGET);
1547 newc1->name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target));
1548 strcpy(newc1->name.error, chain);
1550 newc2->ret.target_offset = sizeof(STRUCT_ENTRY);
1551 newc2->ret.next_offset
1552 = sizeof(STRUCT_ENTRY)
1553 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1554 strcpy(newc2->target.target.u.user.name, STANDARD_TARGET);
1555 newc->target.target.u.target_size
1556 = ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1557 newc->target.verdict = RETURN;
1559 list_prepend(newc1, &chead->rules);
1560 list_append(newc2, &chead->rules);
1566 count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
1568 STRUCT_STANDARD_TARGET *t;
1570 if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) == 0) {
1571 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1573 if (t->verdict == offset)
1580 /* Get the number of references to this chain. */
1582 TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
1583 TC_HANDLE_T *handle)
1585 struct chain_cache *c;
1587 if (!(c = find_label(chain, *handle))) {
1593 ENTRY_ITERATE((*handle)->entries.entrytable,
1594 (*handle)->entries.size,
1595 count_ref, c->start_off, ref);
1599 /* Deletes a chain. */
1601 TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
1603 unsigned int labelidx, labeloff;
1604 unsigned int references;
1605 struct chain_cache *c;
1607 STRUCT_ENTRY *start;
1609 if (!TC_GET_REFERENCES(&references, chain, handle))
1612 iptc_fn = TC_DELETE_CHAIN;
1614 if (TC_BUILTIN(chain, *handle)) {
1619 if (references > 0) {
1624 if (!(c = find_label(chain, *handle))) {
1629 if (c->start_off != c->end_off) {
1634 /* Need label index: preceeds chain start */
1635 labelidx = offset2index(*handle, c->start_off) - 1;
1636 labeloff = index2offset(*handle, labelidx);
1638 start = offset2entry(*handle, c->start_off);
1640 ret = delete_rules(2,
1641 get_entry(*handle, labeloff)->next_offset
1642 + start->next_offset,
1643 labeloff, labelidx, handle);
1647 /* Renames a chain. */
1648 int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
1649 const IPT_CHAINLABEL newname,
1650 TC_HANDLE_T *handle)
1652 unsigned int labeloff, labelidx;
1653 struct chain_cache *c;
1654 struct ipt_error_target *t;
1656 iptc_fn = TC_RENAME_CHAIN;
1658 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1660 if (find_label(newname, *handle)
1661 || strcmp(newname, LABEL_DROP) == 0
1662 || strcmp(newname, LABEL_ACCEPT) == 0
1663 || strcmp(newname, LABEL_QUEUE) == 0
1664 || strcmp(newname, LABEL_RETURN) == 0) {
1669 if (!(c = find_label(oldname, *handle))
1670 || TC_BUILTIN(oldname, *handle)) {
1675 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
1680 /* Need label index: preceeds chain start */
1681 labelidx = offset2index(*handle, c->start_off) - 1;
1682 labeloff = index2offset(*handle, labelidx);
1684 t = (struct ipt_error_target *)
1685 GET_TARGET(get_entry(*handle, labeloff));
1687 memset(t->error, 0, sizeof(t->error));
1688 strcpy(t->error, newname);
1689 set_changed(*handle);
1694 /* Sets the policy on a built-in chain. */
1696 TC_SET_POLICY(const IPT_CHAINLABEL chain,
1697 const IPT_CHAINLABEL policy,
1698 STRUCT_COUNTERS *counters,
1699 TC_HANDLE_T *handle)
1702 unsigned int policyoff, ctrindex;
1704 STRUCT_STANDARD_TARGET *t;
1706 iptc_fn = TC_SET_POLICY;
1707 /* Figure out which chain. */
1708 hook = TC_BUILTIN(chain, *handle);
1715 policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]);
1716 if (policyoff != (*handle)->info.underflow[hook]) {
1717 printf("ERROR: Policy for `%s' offset %u != underflow %u\n",
1718 chain, policyoff, (*handle)->info.underflow[hook]);
1722 e = get_entry(*handle, policyoff);
1723 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1725 if (strcmp(policy, LABEL_ACCEPT) == 0)
1726 t->verdict = -NF_ACCEPT - 1;
1727 else if (strcmp(policy, LABEL_DROP) == 0)
1728 t->verdict = -NF_DROP - 1;
1734 ctrindex = entry2index(*handle, e);
1737 /* set byte and packet counters */
1738 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
1740 (*handle)->counter_map[ctrindex].maptype
1744 (*handle)->counter_map[ctrindex]
1745 = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
1748 set_changed(*handle);
1753 /* Without this, on gcc 2.7.2.3, we get:
1754 libiptc.c: In function `TC_COMMIT':
1755 libiptc.c:833: fixed or forbidden register was spilled.
1756 This may be due to a compiler bug or to impossible asm
1757 statements or clauses.
1760 subtract_counters(STRUCT_COUNTERS *answer,
1761 const STRUCT_COUNTERS *a,
1762 const STRUCT_COUNTERS *b)
1764 answer->pcnt = a->pcnt - b->pcnt;
1765 answer->bcnt = a->bcnt - b->bcnt;
1769 TC_COMMIT(TC_HANDLE_T *handle)
1771 /* Replace, then map back the counters. */
1772 STRUCT_REPLACE *repl;
1773 STRUCT_COUNTERS_INFO *newcounters;
1779 counterlen = sizeof(STRUCT_COUNTERS_INFO)
1780 + sizeof(STRUCT_COUNTERS) * (*handle)->new_number;
1783 TC_DUMP_ENTRIES(*handle);
1786 /* Don't commit if nothing changed. */
1787 if (!(*handle)->changed)
1790 repl = malloc(sizeof(*repl) + (*handle)->entries.size);
1796 /* These are the old counters we will get from kernel */
1797 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
1798 * (*handle)->info.num_entries);
1799 if (!repl->counters) {
1805 /* These are the counters we're going to put back, later. */
1806 newcounters = malloc(counterlen);
1808 free(repl->counters);
1814 strcpy(repl->name, (*handle)->info.name);
1815 repl->num_entries = (*handle)->new_number;
1816 repl->size = (*handle)->entries.size;
1817 memcpy(repl->hook_entry, (*handle)->info.hook_entry,
1818 sizeof(repl->hook_entry));
1819 memcpy(repl->underflow, (*handle)->info.underflow,
1820 sizeof(repl->underflow));
1821 repl->num_counters = (*handle)->info.num_entries;
1822 repl->valid_hooks = (*handle)->info.valid_hooks;
1823 memcpy(repl->entries, (*handle)->entries.entrytable,
1824 (*handle)->entries.size);
1826 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
1827 sizeof(*repl) + (*handle)->entries.size) < 0) {
1828 free(repl->counters);
1834 /* Put counters back. */
1835 strcpy(newcounters->name, (*handle)->info.name);
1836 newcounters->num_counters = (*handle)->new_number;
1837 for (i = 0; i < (*handle)->new_number; i++) {
1838 unsigned int mappos = (*handle)->counter_map[i].mappos;
1839 switch ((*handle)->counter_map[i].maptype) {
1840 case COUNTER_MAP_NOMAP:
1841 newcounters->counters[i]
1842 = ((STRUCT_COUNTERS){ 0, 0 });
1845 case COUNTER_MAP_NORMAL_MAP:
1846 /* Original read: X.
1847 * Atomic read on replacement: X + Y.
1848 * Currently in kernel: Z.
1849 * Want in kernel: X + Y + Z.
1851 * => Add in replacement read.
1853 newcounters->counters[i] = repl->counters[mappos];
1856 case COUNTER_MAP_ZEROED:
1857 /* Original read: X.
1858 * Atomic read on replacement: X + Y.
1859 * Currently in kernel: Z.
1860 * Want in kernel: Y + Z.
1862 * => Add in (replacement read - original read).
1864 subtract_counters(&newcounters->counters[i],
1865 &repl->counters[mappos],
1866 &index2entry(*handle, i)->counters);
1869 case COUNTER_MAP_SET:
1870 /* Want to set counter (iptables-restore) */
1872 memcpy(&newcounters->counters[i],
1873 &index2entry(*handle, i)->counters,
1874 sizeof(STRUCT_COUNTERS));
1880 #ifdef KERNEL_64_USERSPACE_32
1882 /* Kernel will think that pointer should be 64-bits, and get
1883 padding. So we accomodate here (assumption: alignment of
1884 `counters' is on 64-bit boundary). */
1885 u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
1886 if ((unsigned long)&newcounters->counters % 8 != 0) {
1888 "counters alignment incorrect! Mail rusty!\n");
1891 *kernptr = newcounters->counters;
1893 #endif /* KERNEL_64_USERSPACE_32 */
1895 if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
1896 newcounters, counterlen) < 0) {
1897 free(repl->counters);
1903 free(repl->counters);
1912 /* Get raw socket. */
1919 /* Translates errno numbers into more human-readable form than strerror. */
1921 TC_STRERROR(int err)
1924 struct table_struct {
1927 const char *message;
1929 { { TC_INIT, EPERM, "Permission denied (you must be root)" },
1930 { TC_INIT, EINVAL, "Module is wrong version" },
1932 "Table does not exist (do you need to insmod?)" },
1933 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
1934 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
1935 { TC_DELETE_CHAIN, EMLINK,
1936 "Can't delete chain with references left" },
1937 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
1938 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
1939 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
1940 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
1941 { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
1942 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
1943 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
1944 { TC_INSERT_ENTRY, EINVAL, "Target problem" },
1945 /* EINVAL for CHECK probably means bad interface. */
1946 { TC_CHECK_PACKET, EINVAL,
1947 "Bad arguments (does that interface exist?)" },
1948 { TC_CHECK_PACKET, ENOSYS,
1949 "Checking will most likely never get implemented" },
1950 /* ENOENT for DELETE probably means no matching rule */
1951 { TC_DELETE_ENTRY, ENOENT,
1952 "Bad rule (does a matching rule exist in that chain?)" },
1953 { TC_SET_POLICY, ENOENT,
1954 "Bad built-in chain name" },
1955 { TC_SET_POLICY, EINVAL,
1956 "Bad policy name" },
1958 { NULL, 0, "Incompatible with this kernel" },
1959 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
1960 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
1961 { NULL, ENOMEM, "Memory allocation problem" },
1962 { NULL, ENOENT, "No chain/target/match by that name" },
1965 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
1966 if ((!table[i].fn || table[i].fn == iptc_fn)
1967 && table[i].err == err)
1968 return table[i].message;
1971 return strerror(err);