From 9e03380e9f78ae347ae4f3f041c4eca50348f2e8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 6 Jan 2004 18:59:46 +0000 Subject: commit all current changes --- libiptc/libiptc.c | 1190 ++++++++++++++++++++++++----------------------------- 1 file changed, 548 insertions(+), 642 deletions(-) (limited to 'libiptc') diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index 8636c8b0..ad20251f 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -1,4 +1,4 @@ -/* Library which manipulates firewall rules. Version $Revision: 1.40 $ */ +/* Library which manipulates firewall rules. Version $Revision: 1.41 $ */ /* Architecture of firewall rules is as follows: * @@ -15,23 +15,19 @@ * 2003-Jun-20: Harald Welte : * - Reimplementation of chain cache to use offsets instead of entries * 2003-Jun-23: Harald Welte : - * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/) + * - speed optimization, sponsored by Astaro AG (http://www.astaro.com/) * don't rebuild the chain cache after every operation, instead fix it * up after a ruleset change. + * 2003-Jun-30: Harald Welte : + * - reimplementation from scratch. *sigh*. I hope nobody has to touch + * this code ever again. */ +#include "linux_listhelp.h" #ifndef IPT_LIB_DIR #define IPT_LIB_DIR "/usr/local/lib/iptables" #endif -#ifndef __OPTIMIZE__ -STRUCT_ENTRY_TARGET * -GET_TARGET(STRUCT_ENTRY *e) -{ - return (void *)e + e->target_offset; -} -#endif - static int sockfd = -1; static void *iptc_fn = NULL; @@ -64,25 +60,55 @@ struct ipt_error_target char error[TABLE_MAXNAMELEN]; }; -struct chain_cache +struct rule_head +{ + struct list_head list; /* list of rules in chain */ + + struct chain_head *chain; /* we're part of this chain */ + + struct chain_head *jumpto; /* target of this rule, in case + it is a jump rule */ + + struct counter_map counter_map; + + unsigned int size; /* size of rule */ + STRUCT_ENTRY *entry_blob; /* pointer to entry in blob */ + STRUCT_ENTRY entry[0]; +}; + +struct chain_head { + struct list_head list; + char name[TABLE_MAXNAMELEN]; - /* This is the first rule in chain. */ - unsigned int start_off; - /* Last rule in chain */ - unsigned int end_off; + unsigned int hooknum; + struct list_head rules; + struct rule_head *firstrule; /* first (ERROR) rule */ + struct rule_head *lastrule; /* last (RETURN) rule */ }; STRUCT_TC_HANDLE { /* Have changes been made? */ int changed; - /* Size in here reflects original state. */ + + /* linked list of chains in this table */ + struct list_head chains; + + /* current position of first_chain() / next_chain() */ + struct chain_head *chain_iterator_cur; + + /* current position of first_rule() / next_rule() */ + struct rule_head *rule_iterator_cur; + + /* the structure we receive from getsockopt() */ STRUCT_GETINFO info; - struct counter_map *counter_map; /* Array of hook names */ const char **hooknames; +#if 0 + /* Size in here reflects original state. */ + /* Cached position of chain heads (NULL = no cache). */ unsigned int cache_num_chains; @@ -97,6 +123,7 @@ STRUCT_TC_HANDLE /* Number in here reflects current state. */ unsigned int new_number; +#endif STRUCT_GET_ENTRIES entries; }; @@ -113,6 +140,97 @@ static void do_check(TC_HANDLE_T h, unsigned int line); #define CHECK(h) #endif +static struct rule_head *ruleh_alloc(unsigned int size) +{ + struct rule_head *ruleh = malloc(sizeof(*ruleh)+size); + if (!ruleh) + return NULL; + + memset(ruleh, 0, sizeof(*ruleh)+size); + ruleh->size = size; + + return ruleh; +} + +static void ruleh_free(struct rule_head *ruleh) +{ + list_del(&ruleh->list); + free(ruleh); +} + +static struct chain_head *chainh_alloc(TC_HANDLE_T h, const char *name) +{ + struct chain_head *chainh = malloc(sizeof(*chainh)); + if (!chainh) + return NULL; + + memset(chainh, 0, sizeof(*chainh)); + strncpy(chainh->name, name, sizeof(&chainh->name)); + list_append(&chainh->list, &h->chains); + + return chainh; +} + +static void +chainh_clean(struct chain_head *chainh) +{ + /* FIXME */ + struct list_head *cur_item, *item2; + + list_for_each_safe(cur_item, item2, &chainh->rules) { + struct rule_head *ruleh = list_entry(cur_item, + struct rule_head, + list); + ruleh_free(ruleh); + } +} + +static void +chainh_free(struct chain_head *chainh) +{ + chainh_clean(chainh); + list_del(&chainh->list); +} + +static struct chain_head * +chainh_find(TC_HANDLE_T h, const IPT_CHAINLABEL name) +{ + struct list_head *cur; + + list_for_each(cur, &h->chains) { + struct chain_head *ch = list_entry(cur, struct chain_head, + list); + if (!strcmp(name, ch->name)) + return ch; + } + return NULL; +} + +/* Returns chain head if found, otherwise NULL. */ +static struct chain_head * +find_label(const char *name, TC_HANDLE_T handle) +{ + return chainh_find(handle, name); +} + + +/* + * functions that directly operate on the blob + */ + +static inline unsigned long +entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) +{ + return (void *)e - (void *)h->entries.entrytable; +} + +static inline STRUCT_ENTRY * +get_entry(TC_HANDLE_T h, unsigned int offset) +{ + return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset); +} + +/* needed by entry2index */ static inline int get_number(const STRUCT_ENTRY *i, const STRUCT_ENTRY *seek, @@ -164,24 +282,28 @@ index2entry(TC_HANDLE_T h, unsigned int index) return ret; } -static inline STRUCT_ENTRY * -get_entry(TC_HANDLE_T h, unsigned int offset) -{ - return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset); -} - static inline unsigned long -entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e) +index2offset(TC_HANDLE_T h, unsigned int index) { - return (void *)e - (void *)h->entries.entrytable; + return entry2offset(h, index2entry(h, index)); } -static inline unsigned long -index2offset(TC_HANDLE_T h, unsigned int index) +static char * +get_errorlabel(TC_HANDLE_T h, unsigned int offset) { - return entry2offset(h, index2entry(h, index)); + STRUCT_ENTRY *e; + + e = get_entry(h, offset); + if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) { + fprintf(stderr, "ERROR: offset %u not an error node!\n", + offset); + abort(); + } + + return (char *)GET_TARGET(e)->data; } +#if 0 static inline STRUCT_ENTRY * offset2entry(TC_HANDLE_T h, unsigned int offset) { @@ -195,24 +317,12 @@ offset2index(const TC_HANDLE_T h, unsigned int offset) } -static const char * -get_errorlabel(TC_HANDLE_T h, unsigned int offset) -{ - STRUCT_ENTRY *e; - - e = get_entry(h, offset); - if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) != 0) { - fprintf(stderr, "ERROR: offset %u not an error node!\n", - offset); - abort(); - } - - return (const char *)GET_TARGET(e)->data; -} +#endif /* Allocate handle of given size */ static TC_HANDLE_T -alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) +alloc_tc_handle(const char *tablename, unsigned int size, + unsigned int num_rules) { size_t len; TC_HANDLE_T h; @@ -227,23 +337,162 @@ alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules) } h->changed = 0; - h->cache_num_chains = 0; - h->cache_chain_heads = NULL; - h->counter_map = (void *)h - + sizeof(STRUCT_TC_HANDLE) - + size; + strcpy(h->info.name, tablename); strcpy(h->entries.name, tablename); + INIT_LIST_HEAD(&h->chains); return h; } +/* get the name of the chain that we jump to */ +static char * +parse_jumptarget(const STRUCT_ENTRY *e, TC_HANDLE_T h) +{ + STRUCT_ENTRY *jumpto; + int spos, labelidx; + + if (strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET) != 0) { + /* called for non-standard target */ + return "__FIXME"; + } + /* Standard target: evaluate */ + spos = *(int *)GET_TARGET(e)->data; + if (spos < 0) { + return "__FIXME"; + } + + jumpto = get_entry(h, spos); + + /* Fall through rule */ + if (jumpto == (void *)e + e->next_offset) + return ""; + + /* Must point to head of a chain: ie. after error rule */ + /* FIXME: this needs to deal with internal jump targets */ + labelidx = entry2index(h, jumpto) - 1; + return get_errorlabel(h, index2offset(h, labelidx)); +} + +/* parser functions */ + +struct rule_head * +append_entrycopy(const STRUCT_ENTRY *e, struct rule_head *prev) +{ + struct rule_head *ruleh = ruleh_alloc(e->next_offset); + if (!ruleh) + return NULL; + + memcpy(&ruleh->entry, e, e->next_offset); + ruleh->chain = prev->chain; + ruleh->entry_blob = e; + list_append(&ruleh->list, &prev->list); + + return ruleh; +} + +/* have to return 0 on success, bcf ENTRY_ITERATE */ +static inline int +parse_entry(const STRUCT_ENTRY *e, TC_HANDLE_T h, struct chain_head **curchain) +{ + int i; + union tgt_u { + STRUCT_ENTRY_TARGET ent; + STRUCT_STANDARD_TARGET std; + struct ipt_error_target err; + } *tgt; + + struct rule_head *lastrule = list_entry((*curchain)->rules.prev, + struct rule_head, list); + struct rule_head *newrule; + + tgt = (union tgt_u *) GET_TARGET(e); + + if (e->target_offset == sizeof(STRUCT_ENTRY) + && (strcmp(tgt->ent.u.user.name, IPT_STANDARD_TARGET) == 0)) { + /* jump to somewhere else */ + char *targname; + struct chain_head *chainh; + + newrule = append_entrycopy(e, lastrule); + + targname = parse_jumptarget(e, h); + if (!(chainh = find_label(targname, h))) { + chainh = chainh_alloc(h, targname); + } + if (!chainh) { + errno = ENOMEM; + return 1; + } + newrule->jumpto = chainh; + + } else if (e->target_offset == sizeof(STRUCT_ENTRY) + && e->next_offset == sizeof(STRUCT_ENTRY) + + ALIGN(sizeof(struct ipt_error_target)) + && !strcmp(tgt->ent.u.user.name, ERROR_TARGET)) { + /* chain head */ + *curchain = chainh_find(h, tgt->err.error); + if (!(*curchain)) { + *curchain = chainh_alloc(h, tgt->err.error); + /* FIXME: error handling */ + } + newrule = append_entrycopy(e, lastrule); + (*curchain)->firstrule = newrule; + + } else if (e->target_offset == sizeof(STRUCT_ENTRY) + && e->next_offset == sizeof(STRUCT_ENTRY) + + ALIGN(sizeof(STRUCT_STANDARD_TARGET)) + && tgt->std.verdict == RETURN) { + /* chain end */ + newrule = append_entrycopy(e, lastrule); + (*curchain)->lastrule = newrule; + *curchain = NULL; + } else { + /* normal rule */ + newrule = append_entrycopy(e, lastrule); + } + + /* create counter map entry */ + newrule->counter_map.maptype = COUNTER_MAP_NORMAL_MAP; + newrule->counter_map.mappos = entry2index(h, e); + + /* iterate over hook_entries, needed to connect builtin + * chains with hook numbers */ + for (i = 0; i < NUMHOOKS; i++) { + if (!(h->info.valid_hooks & (1 << i))) + continue; + if (h->info.hook_entry[i] == entry2offset(h, e)) { + /* found hook entry point */ + if (*curchain) + (*curchain)->hooknum = i; + } + if (h->info.underflow[i] == entry2offset(h, e)) { + /* found underflow point */ + } + } + + return 0; +} + +static int parse_ruleset(TC_HANDLE_T h) +{ + struct chain_head *curchain; + + /* iterate over ruleset; create linked list of rule_head/chain_head */ + if (ENTRY_ITERATE(h->entries.entrytable, h->entries.size, + parse_entry, h, &curchain)) { + /* some error happened while iterating */ + return 0; + } + + return 1; +} + TC_HANDLE_T TC_INIT(const char *tablename) { TC_HANDLE_T h; STRUCT_GETINFO info; - unsigned int i; int tmp; socklen_t s; @@ -269,7 +518,7 @@ TC_INIT(const char *tablename) if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) return NULL; - if ((h = alloc_handle(info.name, info.size, info.num_entries)) + if ((h = alloc_tc_handle(info.name, info.size, info.num_entries)) == NULL) { close(sockfd); sockfd = -1; @@ -295,11 +544,8 @@ TC_INIT(const char *tablename) /* Initialize current state */ h->info = info; - h->new_number = h->info.num_entries; - for (i = 0; i < h->info.num_entries; i++) - h->counter_map[i] - = ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i}); - + //h->new_number = h->info.num_entries; + // h->entries.size = h->info.size; tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; @@ -313,16 +559,29 @@ TC_INIT(const char *tablename) } CHECK(h); + parse_ruleset(h); + return h; } void TC_FREE(TC_HANDLE_T *h) { + struct list_head *cur_item, *item2; + close(sockfd); sockfd = -1; - if ((*h)->cache_chain_heads) - free((*h)->cache_chain_heads); + + /* free all chains */ + list_for_each_safe(cur_item, item2, &(*h)->chains) { + struct chain_head *chead = list_entry(cur_item, + struct chain_head, + list); + chainh_free(chead); + } + + /* FIXME: free all other ressources we might be using */ + free(*h); *h = NULL; } @@ -336,6 +595,7 @@ print_match(const STRUCT_ENTRY_MATCH *m) static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle); +#if 0 void TC_DUMP_ENTRIES(const TC_HANDLE_T handle) { @@ -376,180 +636,13 @@ is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) return 0; } -static inline int -add_chain(STRUCT_ENTRY *e, TC_HANDLE_T h, STRUCT_ENTRY **prev) -{ - unsigned int builtin; - - /* Last entry. End it. */ - if (entry2offset(h, e) + e->next_offset == h->entries.size) { - /* This is the ERROR node at end of the table */ - h->cache_chain_heads[h->cache_num_chains-1].end_off = - entry2offset(h, *prev); - return 0; - } - - /* We know this is the start of a new chain if it's an ERROR - target, or a hook entry point */ - if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) { - /* prev was last entry in previous chain */ - h->cache_chain_heads[h->cache_num_chains-1].end_off - = entry2offset(h, *prev); - - strcpy(h->cache_chain_heads[h->cache_num_chains].name, - (const char *)GET_TARGET(e)->data); - h->cache_chain_heads[h->cache_num_chains].start_off - = entry2offset(h, (void *)e + e->next_offset); - h->cache_num_chains++; - } else if ((builtin = is_hook_entry(e, h)) != 0) { - if (h->cache_num_chains > 0) - /* prev was last entry in previous chain */ - h->cache_chain_heads[h->cache_num_chains-1].end_off - = entry2offset(h, *prev); - - strcpy(h->cache_chain_heads[h->cache_num_chains].name, - h->hooknames[builtin-1]); - h->cache_chain_heads[h->cache_num_chains].start_off - = entry2offset(h, (void *)e); - h->cache_num_chains++; - } - - *prev = e; - return 0; -} static int alphasort(const void *a, const void *b) { return strcmp(((struct chain_cache *)a)->name, ((struct chain_cache *)b)->name); } - -static int populate_cache(TC_HANDLE_T h) -{ - unsigned int i; - STRUCT_ENTRY *prev; - - /* # chains < # rules / 2 + num builtins - 1 */ - h->cache_chain_heads = malloc((h->new_number / 2 + 4) - * sizeof(struct chain_cache)); - if (!h->cache_chain_heads) { - errno = ENOMEM; - return 0; - } - - h->cache_num_chains = 0; - h->cache_num_builtins = 0; - - /* Count builtins */ - for (i = 0; i < NUMHOOKS; i++) { - if (h->info.valid_hooks & (1 << i)) - h->cache_num_builtins++; - } - - prev = NULL; - ENTRY_ITERATE(h->entries.entrytable, h->entries.size, - add_chain, h, &prev); - - qsort(h->cache_chain_heads + h->cache_num_builtins, - h->cache_num_chains - h->cache_num_builtins, - sizeof(struct chain_cache), alphasort); - - return 1; -} - -static int -correct_cache(TC_HANDLE_T h, unsigned int offset, int delta) -{ - int i; /* needs to be signed because deleting first - chain can make it drop to -1 */ - - if (!delta) - return 1; - - for (i = 0; i < h->cache_num_chains; i++) { - struct chain_cache *cc = &h->cache_chain_heads[i]; - - if (delta < 0) { - /* take care about deleted chains */ - if (cc->start_off > offset+delta - && cc->end_off < offset) { - /* this chain is within the deleted range, - * let's remove it from the cache */ - void *start; - unsigned int size; - - h->cache_num_chains--; - - /* no need for memmove since we are - * removing the last entry */ - if (i >= h->cache_num_chains) - continue; - - start = &h->cache_chain_heads[i+1]; - size = (h->cache_num_chains-i) - * sizeof(struct chain_cache); - memmove(cc, start, size); - - /* iterate over same index again, since - * it is now a different chain */ - i--; - continue; - } - } - - if (cc->start_off > offset) - cc->start_off += delta; - - if (cc->end_off >= offset) - cc->end_off += delta; - } - /* HW_FIXME: sorting might be needed, but just in case a new chain was - * added */ - - return 1; -} - -static int -add_chain_cache(TC_HANDLE_T h, const char *name, unsigned int start_off, - unsigned int end_off) -{ - struct chain_cache *ccs = realloc(h->cache_chain_heads, - (h->new_number / 2 + 4 + 1) - * sizeof(struct chain_cache)); - struct chain_cache *newcc; - - if (!ccs) - return 0; - - h->cache_chain_heads = ccs; - newcc = &h->cache_chain_heads[h->cache_num_chains]; - h->cache_num_chains++; - - strncpy(newcc->name, name, TABLE_MAXNAMELEN-1); - newcc->start_off = start_off; - newcc->end_off = end_off; - - return 1; -} - -/* Returns cache ptr if found, otherwise NULL. */ -static struct chain_cache * -find_label(const char *name, TC_HANDLE_T handle) -{ - unsigned int i; - - if (handle->cache_chain_heads == NULL - && !populate_cache(handle)) - return NULL; - - /* FIXME: Linear search through builtins, then binary --RR */ - for (i = 0; i < handle->cache_num_chains; i++) { - if (strcmp(handle->cache_chain_heads[i].name, name) == 0) - return &handle->cache_chain_heads[i]; - } - - return NULL; -} +#endif /* Does this chain exist? */ int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) @@ -557,6 +650,7 @@ int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle) return find_label(chain, handle) != NULL; } +#if 0 /* Returns the position of the final (ie. unconditional) element. */ static unsigned int get_chain_end(const TC_HANDLE_T handle, unsigned int start) @@ -593,39 +687,38 @@ get_chain_end(const TC_HANDLE_T handle, unsigned int start) handle->entries.size, off); abort(); } +#endif /* Iterator functions to run through the chains. */ const char * TC_FIRST_CHAIN(TC_HANDLE_T *handle) { - if ((*handle)->cache_chain_heads == NULL - && !populate_cache(*handle)) - return NULL; - - (*handle)->cache_chain_iteration - = &(*handle)->cache_chain_heads[0]; + struct chain_head *firsthead = list_entry((*handle)->chains.next, + struct chain_head, list); + (*handle)->chain_iterator_cur = firsthead; - return (*handle)->cache_chain_iteration->name; + return firsthead->name; } /* Iterator functions to run through the chains. Returns NULL at end. */ const char * TC_NEXT_CHAIN(TC_HANDLE_T *handle) { - (*handle)->cache_chain_iteration++; + struct chain_head *next = list_entry(&(*handle)->chain_iterator_cur->list.next, struct chain_head, list); + (*handle)->chain_iterator_cur = next; - if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads - == (*handle)->cache_num_chains) + if (&next->list == &(*handle)->chains) return NULL; - return (*handle)->cache_chain_iteration->name; + return next->name; } /* Get first rule in the given chain: NULL for empty chain. */ const STRUCT_ENTRY * TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) { - struct chain_cache *c; + struct chain_head *c; + struct rule_head *r; c = find_label(chain, *handle); if (!c) { @@ -634,22 +727,26 @@ TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle) } /* Empty chain: single return/policy rule */ - if (c->start_off == c->end_off) + if (list_empty(&c->rules)) return NULL; - (*handle)->cache_rule_end = offset2entry(*handle, c->end_off); - return offset2entry(*handle, c->start_off); + r = list_entry(c->rules.next, struct rule_head, list); + (*handle)->rule_iterator_cur = r; + + return r->entry; } /* Returns NULL when rules run out. */ const STRUCT_ENTRY * TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) { - if ((void *)prev + prev->next_offset - == (void *)(*handle)->cache_rule_end) + struct rule_head *r = list_entry((*handle)->rule_iterator_cur->list.next, struct rule_head, list); + + if (&r->list == &r->chain->rules) return NULL; - return (void *)prev + prev->next_offset; + /* NOTE: prev is without any influence ! */ + return r->entry; } #if 0 @@ -695,8 +792,6 @@ static const char * target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) { int spos; - unsigned int labelidx; - STRUCT_ENTRY *jumpto; /* To avoid const warnings */ STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce; @@ -716,21 +811,24 @@ target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce) else if (spos == -NF_QUEUE-1) return LABEL_QUEUE; - fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n", - entry2offset(handle, e), handle->entries.size, - spos); + fprintf(stderr, "ERROR: entry %p not a valid target (%d)\n", + e, spos); abort(); } - jumpto = get_entry(handle, spos); +#if 0 +// jumpto = get_entry(handle, spos); /* Fall through rule */ if (jumpto == (void *)e + e->next_offset) return ""; /* Must point to head of a chain: ie. after error rule */ + /* FIXME: this needs to deal with internal jump targets */ labelidx = entry2index(handle, jumpto) - 1; return get_errorlabel(handle, index2offset(handle, labelidx)); +#endif + return ""; } /* Returns a pointer to the target name of this position. */ @@ -761,23 +859,31 @@ TC_GET_POLICY(const char *chain, STRUCT_COUNTERS *counters, TC_HANDLE_T *handle) { - unsigned int start; STRUCT_ENTRY *e; + struct chain_head *chainh; + struct rule_head *ruleh; int hook; hook = TC_BUILTIN(chain, *handle); - if (hook != 0) - start = (*handle)->info.hook_entry[hook-1]; - else + if (hook == 0) return NULL; - e = get_entry(*handle, get_chain_end(*handle, start)); + chainh = find_label(chain, *handle); + if (!chainh) { + errno = ENOENT; + return NULL; + } + + ruleh = chainh->lastrule; + + e = ruleh->entry; *counters = e->counters; return target_name(*handle, e); } -static inline int +#if 0 +static int correct_verdict(STRUCT_ENTRY *e, char *base, unsigned int offset, int delta_offset) @@ -809,149 +915,9 @@ set_verdict(unsigned int offset, int delta_offset, TC_HANDLE_T *handle) set_changed(*handle); return 1; } +#endif -/* If prepend is set, then we are prepending to a chain: if the - * insertion position is an entry point, keep the entry point. */ -static int -insert_rules(unsigned int num_rules, unsigned int rules_size, - const STRUCT_ENTRY *insert, - unsigned int offset, unsigned int num_rules_offset, - int prepend, - TC_HANDLE_T *handle) -{ - TC_HANDLE_T newh; - STRUCT_GETINFO newinfo; - unsigned int i; - - if (offset >= (*handle)->entries.size) { - errno = EINVAL; - return 0; - } - - newinfo = (*handle)->info; - - /* Fix up entry points. */ - for (i = 0; i < NUMHOOKS; i++) { - /* Entry points to START of chain, so keep same if - inserting on at that point. */ - if ((*handle)->info.hook_entry[i] > offset) - newinfo.hook_entry[i] += rules_size; - - /* Underflow always points to END of chain (policy), - so if something is inserted at same point, it - should be advanced. */ - if ((*handle)->info.underflow[i] >= offset) - newinfo.underflow[i] += rules_size; - } - - newh = alloc_handle((*handle)->info.name, - (*handle)->entries.size + rules_size, - (*handle)->new_number + num_rules); - if (!newh) - return 0; - newh->info = newinfo; - - /* Copy pre... */ - memcpy(newh->entries.entrytable, (*handle)->entries.entrytable,offset); - /* ... Insert new ... */ - memcpy((char *)newh->entries.entrytable + offset, insert, rules_size); - /* ... copy post */ - memcpy((char *)newh->entries.entrytable + offset + rules_size, - (char *)(*handle)->entries.entrytable + offset, - (*handle)->entries.size - offset); - - /* Move counter map. */ - /* Copy pre... */ - memcpy(newh->counter_map, (*handle)->counter_map, - sizeof(struct counter_map) * num_rules_offset); - /* ... copy post */ - memcpy(newh->counter_map + num_rules_offset + num_rules, - (*handle)->counter_map + num_rules_offset, - sizeof(struct counter_map) * ((*handle)->new_number - - num_rules_offset)); - /* Set intermediates to no counter copy */ - for (i = 0; i < num_rules; i++) - newh->counter_map[num_rules_offset+i] - = ((struct counter_map){ COUNTER_MAP_SET, 0 }); - - newh->new_number = (*handle)->new_number + num_rules; - newh->entries.size = (*handle)->entries.size + rules_size; - newh->hooknames = (*handle)->hooknames; - - newh->cache_chain_heads = (*handle)->cache_chain_heads; - newh->cache_num_builtins = (*handle)->cache_num_builtins; - newh->cache_num_chains = (*handle)->cache_num_chains; - newh->cache_rule_end = (*handle)->cache_rule_end; - newh->cache_chain_iteration = (*handle)->cache_chain_iteration; - if (!correct_cache(newh, offset, rules_size)) { - free(newh); - return 0; - } - - free(*handle); - *handle = newh; - - return set_verdict(offset, rules_size, handle); -} - -static int -delete_rules(unsigned int num_rules, unsigned int rules_size, - unsigned int offset, unsigned int num_rules_offset, - TC_HANDLE_T *handle) -{ - unsigned int i; - - if (offset + rules_size > (*handle)->entries.size) { - errno = EINVAL; - return 0; - } - - /* Fix up entry points. */ - for (i = 0; i < NUMHOOKS; i++) { - /* In practice, we never delete up to a hook entry, - since the built-in chains are always first, - so these two are never equal */ - if ((*handle)->info.hook_entry[i] >= offset + rules_size) - (*handle)->info.hook_entry[i] -= rules_size; - else if ((*handle)->info.hook_entry[i] > offset) { - fprintf(stderr, "ERROR: Deleting entry %u %u %u\n", - i, (*handle)->info.hook_entry[i], offset); - abort(); - } - - /* Underflow points to policy (terminal) rule in - built-in, so sequality is valid here (when deleting - the last rule). */ - if ((*handle)->info.underflow[i] >= offset + rules_size) - (*handle)->info.underflow[i] -= rules_size; - else if ((*handle)->info.underflow[i] > offset) { - fprintf(stderr, "ERROR: Deleting uflow %u %u %u\n", - i, (*handle)->info.underflow[i], offset); - abort(); - } - } - - /* Move the rules down. */ - memmove((char *)(*handle)->entries.entrytable + offset, - (char *)(*handle)->entries.entrytable + offset + rules_size, - (*handle)->entries.size - (offset + rules_size)); - - /* Move the counter map down. */ - memmove(&(*handle)->counter_map[num_rules_offset], - &(*handle)->counter_map[num_rules_offset + num_rules], - sizeof(struct counter_map) - * ((*handle)->new_number - (num_rules + num_rules_offset))); - - /* Fix numbers */ - (*handle)->new_number -= num_rules; - (*handle)->entries.size -= rules_size; - /* Fix the chain cache */ - if (!correct_cache(*handle, offset+rules_size, -(int)rules_size)) - return 0; - - return set_verdict(offset, -(int)rules_size, handle); -} static int standard_map(STRUCT_ENTRY *e, int verdict) @@ -979,7 +945,7 @@ map_target(const TC_HANDLE_T handle, unsigned int offset, STRUCT_ENTRY_TARGET *old) { - STRUCT_ENTRY_TARGET *t = GET_TARGET(e); + STRUCT_ENTRY_TARGET *t = (STRUCT_ENTRY_TARGET *)GET_TARGET(e); /* Save old target (except data, which we don't change, except for standard case, where we don't care). */ @@ -1003,11 +969,14 @@ map_target(const TC_HANDLE_T handle, return 0; } else { /* Maybe it's an existing chain name. */ - struct chain_cache *c; + struct chain_head *c; +#if 0 + /* FIXME */ c = find_label(t->u.user.name, handle); if (c) return standard_map(e, c->start_off); +#endif } /* Must be a module? If not, kernel will reject... */ @@ -1028,18 +997,32 @@ unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old) *t = *old; } -/* Insert the entry `fw' in chain `chain' into position `rulenum'. */ +static struct rule_head * +ruleh_get_n(struct chain_head *chead, int rulenum) +{ + int i = 0; + struct list_head *list; + + + list_for_each(list, &chead->rules) { + struct rule_head *rhead = list_entry(list, struct rule_head, + list); + i++; + if (i == rulenum) + return rhead; + } + return NULL; +} + +/* Insert the entry `e' in chain `chain' into position `rulenum'. */ int TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *e, unsigned int rulenum, TC_HANDLE_T *handle) { - unsigned int chainindex, offset; - STRUCT_ENTRY_TARGET old; - struct chain_cache *c; - STRUCT_ENTRY *tmp; - int ret; + struct chain_head *c; + struct rule_head *prev; iptc_fn = TC_INSERT_ENTRY; if (!(c = find_label(chain, *handle))) { @@ -1047,24 +1030,16 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, return 0; } - chainindex = offset2index(*handle, c->start_off); - - tmp = index2entry(*handle, chainindex + rulenum); - if (!tmp || tmp > offset2entry(*handle, c->end_off)) { + prev = ruleh_get_n(c, rulenum-1); + if (!prev) { errno = E2BIG; return 0; } - offset = index2offset(*handle, chainindex + rulenum); - /* Mapping target actually alters entry, but that's - transparent to the caller. */ - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) - return 0; + if (append_entrycopy(e, prev)) + return 1; - ret = insert_rules(1, e->next_offset, e, offset, - chainindex + rulenum, rulenum == 0, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; + return 0; } /* Atomically replace rule `rulenum' in `chain' with `fw'. */ @@ -1074,11 +1049,8 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, unsigned int rulenum, TC_HANDLE_T *handle) { - unsigned int chainindex, offset; - STRUCT_ENTRY_TARGET old; - struct chain_cache *c; - STRUCT_ENTRY *tmp; - int ret; + struct chain_head *c; + struct rule_head *repl; iptc_fn = TC_REPLACE_ENTRY; @@ -1087,54 +1059,43 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, return 0; } - chainindex = offset2index(*handle, c->start_off); - - tmp = index2entry(*handle, chainindex + rulenum); - if (!tmp || tmp >= offset2entry(*handle, c->end_off)) { + repl = ruleh_get_n(c, rulenum); + if (!repl) { errno = E2BIG; return 0; } - offset = index2offset(*handle, chainindex + rulenum); - /* Replace = delete and insert. */ - if (!delete_rules(1, get_entry(*handle, offset)->next_offset, - offset, chainindex + rulenum, handle)) - return 0; - - if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old)) + if (!append_entrycopy(e, repl)) { + errno = ENOMEM; return 0; + } - ret = insert_rules(1, e->next_offset, e, offset, - chainindex + rulenum, 1, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; + ruleh_free(repl); + return 1; } -/* Append entry `fw' to chain `chain'. Equivalent to insert with +/* Append entry `e' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ int TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *e, TC_HANDLE_T *handle) { - struct chain_cache *c; - STRUCT_ENTRY_TARGET old; - int ret; + struct chain_head *c; + struct rule_head *rhead; iptc_fn = TC_APPEND_ENTRY; + if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } - if (!map_target(*handle, (STRUCT_ENTRY *)e, - c->end_off, &old)) - return 0; - - ret = insert_rules(1, e->next_offset, e, c->end_off, - offset2index(*handle, c->end_off), 0, handle); - unmap_target((STRUCT_ENTRY *)e, &old); - return ret; + rhead = list_entry(c->rules.prev, struct rule_head, list); + if(append_entrycopy(e, rhead)) + return 1; + + return 0; } static inline int @@ -1183,16 +1144,15 @@ is_same(const STRUCT_ENTRY *a, const STRUCT_ENTRY *b, unsigned char *matchmask); -/* Delete the first rule in `chain' which matches `fw'. */ +/* Delete the first rule in `chain' which matches `origfw'. */ int TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, unsigned char *matchmask, TC_HANDLE_T *handle) { - unsigned int offset; - struct chain_cache *c; - STRUCT_ENTRY *e, *fw; + struct chain_head *c; + struct list_head *cur, *cur2; iptc_fn = TC_DELETE_ENTRY; if (!(c = find_label(chain, *handle))) { @@ -1200,40 +1160,15 @@ TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, return 0; } - fw = malloc(origfw->next_offset); - if (fw == NULL) { - errno = ENOMEM; - return 0; - } - - for (offset = c->start_off; offset < c->end_off; - offset += e->next_offset) { - STRUCT_ENTRY_TARGET discard; - - memcpy(fw, origfw, origfw->next_offset); - - /* FIXME: handle this in is_same --RR */ - if (!map_target(*handle, fw, offset, &discard)) { - free(fw); - return 0; - } - e = get_entry(*handle, offset); - -#if 0 - printf("Deleting:\n"); - dump_entry(newe); -#endif - if (is_same(e, fw, matchmask)) { - int ret; - ret = delete_rules(1, e->next_offset, - offset, entry2index(*handle, e), - handle); - free(fw); - return ret; + list_for_each_safe(cur, cur2, &c->rules) { + struct rule_head *rhead = list_entry(cur, struct rule_head, + list); + if (is_same(rhead->entry, origfw, matchmask)) { + ruleh_free(rhead); + return 1; } } - free(fw); errno = ENOENT; return 0; } @@ -1244,33 +1179,25 @@ TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain, unsigned int rulenum, TC_HANDLE_T *handle) { - unsigned int index; - int ret; - STRUCT_ENTRY *e; - struct chain_cache *c; + struct chain_head *chainh; + struct rule_head *rhead; iptc_fn = TC_DELETE_NUM_ENTRY; - if (!(c = find_label(chain, *handle))) { + + if (!(chainh = find_label(chain, *handle))) { errno = ENOENT; return 0; } - index = offset2index(*handle, c->start_off) + rulenum; - - if (index >= offset2index(*handle, c->end_off)) { + rhead = ruleh_get_n(chainh, rulenum); + if (!rhead) { errno = E2BIG; return 0; } - e = index2entry(*handle, index); - if (e == NULL) { - errno = EINVAL; - return 0; - } + ruleh_free(rhead); - ret = delete_rules(1, e->next_offset, entry2offset(*handle, e), - index, handle); - return ret; + return 1; } /* Check the packet `fw' on chain `chain'. Returns the verdict, or @@ -1288,46 +1215,40 @@ TC_CHECK_PACKET(const IPT_CHAINLABEL chain, int TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { - unsigned int startindex, endindex; - STRUCT_ENTRY *startentry, *endentry; - struct chain_cache *c; - int ret; + struct list_head *cur, *cur2; + struct chain_head *chainh; - iptc_fn = TC_FLUSH_ENTRIES; - if (!(c = find_label(chain, *handle))) { + if (!(chainh = find_label(chain, *handle))) { errno = ENOENT; return 0; } - startindex = offset2index(*handle, c->start_off); - endindex = offset2index(*handle, c->end_off); - startentry = offset2entry(*handle, c->start_off); - endentry = offset2entry(*handle, c->end_off); - ret = delete_rules(endindex - startindex, - (char *)endentry - (char *)startentry, - c->start_off, startindex, - handle); - return ret; + list_for_each_safe(cur, cur2, &chainh->rules) { + struct rule_head *ruleh = list_entry(cur, struct rule_head, + list); + /* don't free the entry and policy/return entries */ + if (ruleh != chainh->firstrule && ruleh != chainh->lastrule) + ruleh_free(ruleh); + } + return 1; } /* Zeroes the counters in a chain. */ int TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { - unsigned int i, end; - struct chain_cache *c; + struct chain_head *c; + struct list_head *cur; if (!(c = find_label(chain, *handle))) { errno = ENOENT; return 0; } - i = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - for (; i <= end; i++) { - if ((*handle)->counter_map[i].maptype ==COUNTER_MAP_NORMAL_MAP) - (*handle)->counter_map[i].maptype = COUNTER_MAP_ZEROED; + list_for_each(cur, c->rules.next) { + struct rule_head *r = list_entry(cur, struct rule_head, list); + if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) + r->counter_map.maptype = COUNTER_MAP_ZEROED; } set_changed(*handle); @@ -1340,28 +1261,19 @@ TC_READ_COUNTER(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; + struct chain_head *c; + struct rule_head *r; iptc_fn = TC_READ_COUNTER; CHECK(*handle); - if (!(c = find_label(chain, *handle))) { + if (!(c = find_label(chain, *handle) ) + || !(r = ruleh_get_n(c, rulenum))) { errno = ENOENT; return NULL; } - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return NULL; - } - - e = index2entry(*handle, chainindex + rulenum); - - return &e->counters; + return &r->entry->counters; } int @@ -1370,32 +1282,20 @@ TC_ZERO_COUNTER(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; + struct chain_head *c; + struct rule_head *r; iptc_fn = TC_ZERO_COUNTER; CHECK(*handle); - if (!(c = find_label(chain, *handle))) { + if (!(c = find_label(chain, *handle)) + || !(r = ruleh_get_n(c, rulenum))) { errno = ENOENT; return 0; } - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return 0; - } - - e = index2entry(*handle, chainindex + rulenum); - - if ((*handle)->counter_map[chainindex + rulenum].maptype - == COUNTER_MAP_NORMAL_MAP) { - (*handle)->counter_map[chainindex + rulenum].maptype - = COUNTER_MAP_ZEROED; - } + if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP) + r->counter_map.maptype = COUNTER_MAP_ZEROED; set_changed(*handle); @@ -1409,31 +1309,20 @@ TC_SET_COUNTER(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { STRUCT_ENTRY *e; - struct chain_cache *c; - unsigned int chainindex, end; + struct chain_head *c; + struct rule_head *r; iptc_fn = TC_SET_COUNTER; CHECK(*handle); - if (!(c = find_label(chain, *handle))) { + if (!(c = find_label(chain, *handle)) + || !(r = ruleh_get_n(c, rulenum))) { errno = ENOENT; return 0; } - - chainindex = offset2index(*handle, c->start_off); - end = offset2index(*handle, c->end_off); - - if (chainindex + rulenum > end) { - errno = E2BIG; - return 0; - } - - e = index2entry(*handle, chainindex + rulenum); - - (*handle)->counter_map[chainindex + rulenum].maptype - = COUNTER_MAP_SET; - - memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); + + r->counter_map.maptype = COUNTER_MAP_SET; + memcpy(&r->entry->counters, counters, sizeof(STRUCT_COUNTERS)); set_changed(*handle); @@ -1447,13 +1336,16 @@ int TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { int ret; - struct { + struct chainstart { STRUCT_ENTRY head; struct ipt_error_target name; + } *newc1; + struct chainend { STRUCT_ENTRY ret; STRUCT_STANDARD_TARGET target; - } newc; - unsigned int destination; + } *newc2; + struct rule_head *newr1, *newr2; + struct chain_head *chead; iptc_fn = TC_CREATE_CHAIN; @@ -1473,42 +1365,53 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) return 0; } - memset(&newc, 0, sizeof(newc)); - newc.head.target_offset = sizeof(STRUCT_ENTRY); - newc.head.next_offset + chead = chainh_alloc(*handle, chain); + if (!chead) { + errno = ENOMEM; + return 0; + } + + newr1 = ruleh_alloc(sizeof(*newc1)); + if (!newr1) { + chainh_free(chead); + return 0; + } + newc1 = (struct chainstart *) newr1->entry; + + newr2 = ruleh_alloc(sizeof(*newc2)); + if (!newr2) { + chainh_free(chead); + ruleh_free(newr1); + return 0; + } + newc2 = (struct chainend *) newr2->entry; + + newc1->head.target_offset = sizeof(STRUCT_ENTRY); + newc1->head.next_offset = sizeof(STRUCT_ENTRY) + ALIGN(sizeof(struct ipt_error_target)); - strcpy(newc.name.t.u.user.name, ERROR_TARGET); - newc.name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target)); - strcpy(newc.name.error, chain); + strcpy(newc1->name.t.u.user.name, ERROR_TARGET); + newc1->name.t.u.target_size = ALIGN(sizeof(struct ipt_error_target)); + strcpy(newc1->name.error, chain); - newc.ret.target_offset = sizeof(STRUCT_ENTRY); - newc.ret.next_offset + newc2->ret.target_offset = sizeof(STRUCT_ENTRY); + newc2->ret.next_offset = sizeof(STRUCT_ENTRY) + ALIGN(sizeof(STRUCT_STANDARD_TARGET)); - strcpy(newc.target.target.u.user.name, STANDARD_TARGET); - newc.target.target.u.target_size + strcpy(newc2->target.target.u.user.name, STANDARD_TARGET); + newc2->target.target.u.target_size = ALIGN(sizeof(STRUCT_STANDARD_TARGET)); - newc.target.verdict = RETURN; - - destination = index2offset(*handle, (*handle)->new_number -1); + newc2->target.verdict = RETURN; - /* Add just before terminal entry */ - ret = insert_rules(2, sizeof(newc), &newc.head, - destination, - (*handle)->new_number - 1, - 0, handle); + list_prepend(&newr1->list, &chead->rules); + chead->firstrule = newr1; + list_append(&newr2->list, &chead->rules); + chead->lastrule = newr2; - set_changed(*handle); - - /* add chain cache info for this chain */ - add_chain_cache(*handle, chain, - destination+newc.head.next_offset, - destination+newc.head.next_offset); - - return ret; + return 1; } +#if 0 static int count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref) { @@ -1542,17 +1445,32 @@ TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain, count_ref, c->start_off, ref); return 1; } +#endif + +static unsigned int +count_rules(struct chain_head *chainh) +{ + unsigned int numrules = 0; + struct list_head *cur; + + list_for_each(cur, &chainh->rules) { + numrules++; + } + + if (numrules <=2) + return 0; + else + return numrules-2; +} /* Deletes a chain. */ int TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) { - unsigned int labelidx, labeloff; unsigned int references; - struct chain_cache *c; - int ret; - STRUCT_ENTRY *start; + struct chain_head *chainh; +#if 0 if (!TC_GET_REFERENCES(&references, chain, handle)) return 0; @@ -1567,28 +1485,20 @@ TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) errno = EMLINK; return 0; } +#endif - if (!(c = find_label(chain, *handle))) { + if (!(chainh = find_label(chain, *handle))) { errno = ENOENT; return 0; } - if (c->start_off != c->end_off) { + if (!(count_rules(chainh) == 0)) { errno = ENOTEMPTY; return 0; } - /* Need label index: preceeds chain start */ - labelidx = offset2index(*handle, c->start_off) - 1; - labeloff = index2offset(*handle, labelidx); - - start = offset2entry(*handle, c->start_off); - - ret = delete_rules(2, - get_entry(*handle, labeloff)->next_offset - + start->next_offset, - labeloff, labelidx, handle); - return ret; + chainh_free(chainh); + return 1; } /* Renames a chain. */ @@ -1596,8 +1506,8 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, const IPT_CHAINLABEL newname, TC_HANDLE_T *handle) { - unsigned int labeloff, labelidx; - struct chain_cache *c; + struct chain_head *c; + struct rule_head *ruleh; struct ipt_error_target *t; iptc_fn = TC_RENAME_CHAIN; @@ -1624,22 +1534,14 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname, return 0; } - /* Need label index: preceeds chain start */ - labelidx = offset2index(*handle, c->start_off) - 1; - labeloff = index2offset(*handle, labelidx); + ruleh = list_entry(&c->rules.next, struct rule_head, list); t = (struct ipt_error_target *) - GET_TARGET(get_entry(*handle, labeloff)); + GET_TARGET(ruleh->entry); memset(t->error, 0, sizeof(t->error)); strcpy(t->error, newname); - /* update chain cache */ - memset(c->name, 0, sizeof(c->name)); - strcpy(c->name, newname); - - set_changed(*handle); - return 1; } @@ -1650,8 +1552,10 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain, STRUCT_COUNTERS *counters, TC_HANDLE_T *handle) { + int ctrindex; unsigned int hook; - unsigned int policyoff, ctrindex; + struct chain_head *chainh; + struct rule_head *policyrh; STRUCT_ENTRY *e; STRUCT_STANDARD_TARGET *t; @@ -1664,15 +1568,18 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain, } else hook--; - policyoff = get_chain_end(*handle, (*handle)->info.hook_entry[hook]); - if (policyoff != (*handle)->info.underflow[hook]) { - printf("ERROR: Policy for `%s' offset %u != underflow %u\n", - chain, policyoff, (*handle)->info.underflow[hook]); + if (!(chainh = find_label(chain, *handle))) { + errno = ENOENT; return 0; } - e = get_entry(*handle, policyoff); - t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e); + policyrh = chainh->lastrule; + if (policyrh) { + printf("ERROR: Policy for `%s' non-existant", chain); + return 0; + } + + t = (STRUCT_STANDARD_TARGET *)GET_TARGET(policyrh->entry); if (strcmp(policy, LABEL_ACCEPT) == 0) t->verdict = -NF_ACCEPT - 1; @@ -1689,12 +1596,11 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain, /* set byte and packet counters */ memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS)); - (*handle)->counter_map[ctrindex].maptype - = COUNTER_MAP_SET; + policyrh->counter_map.maptype = COUNTER_MAP_SET; } else { - (*handle)->counter_map[ctrindex] - = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 }); + policyrh->counter_map.maptype = COUNTER_MAP_NOMAP; + policyrh->counter_map.mappos = 0; } set_changed(*handle); -- cgit v1.2.3