summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libiptc/libiptc.c1188
1 files changed, 641 insertions, 547 deletions
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index ad20251f..ba2e35e8 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -15,19 +15,23 @@
* 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
* - Reimplementation of chain cache to use offsets instead of entries
* 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
- * - speed optimization, sponsored by Astaro AG (http://www.astaro.com/)
+ * - performance 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 <laforge@netfilter.org>:
- * - 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;
@@ -60,55 +64,25 @@ struct ipt_error_target
char error[TABLE_MAXNAMELEN];
};
-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 chain_cache
{
- struct list_head list;
-
char name[TABLE_MAXNAMELEN];
- unsigned int hooknum;
- struct list_head rules;
- struct rule_head *firstrule; /* first (ERROR) rule */
- struct rule_head *lastrule; /* last (RETURN) rule */
+ /* This is the first rule in chain. */
+ unsigned int start_off;
+ /* Last rule in chain */
+ unsigned int end_off;
};
STRUCT_TC_HANDLE
{
/* Have changes been made? */
int changed;
-
- /* 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() */
+ /* Size in here reflects original state. */
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;
@@ -123,7 +97,6 @@ STRUCT_TC_HANDLE
/* Number in here reflects current state. */
unsigned int new_number;
-#endif
STRUCT_GET_ENTRIES entries;
};
@@ -140,97 +113,6 @@ 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,
@@ -282,28 +164,24 @@ index2entry(TC_HANDLE_T h, unsigned int index)
return ret;
}
-static inline unsigned long
-index2offset(TC_HANDLE_T h, unsigned int index)
+static inline STRUCT_ENTRY *
+get_entry(TC_HANDLE_T h, unsigned int offset)
{
- return entry2offset(h, index2entry(h, index));
+ return (STRUCT_ENTRY *)((char *)h->entries.entrytable + offset);
}
-static char *
-get_errorlabel(TC_HANDLE_T h, unsigned int offset)
+static inline unsigned long
+entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
{
- 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 (void *)e - (void *)h->entries.entrytable;
+}
- return (char *)GET_TARGET(e)->data;
+static inline unsigned long
+index2offset(TC_HANDLE_T h, unsigned int index)
+{
+ return entry2offset(h, index2entry(h, index));
}
-#if 0
static inline STRUCT_ENTRY *
offset2entry(TC_HANDLE_T h, unsigned int offset)
{
@@ -317,12 +195,24 @@ offset2index(const TC_HANDLE_T h, unsigned int offset)
}
-#endif
+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;
+}
/* Allocate handle of given size */
static TC_HANDLE_T
-alloc_tc_handle(const char *tablename, unsigned int size,
- unsigned int num_rules)
+alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
{
size_t len;
TC_HANDLE_T h;
@@ -337,162 +227,23 @@ alloc_tc_handle(const char *tablename, unsigned int size,
}
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;
@@ -518,7 +269,7 @@ TC_INIT(const char *tablename)
if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
return NULL;
- if ((h = alloc_tc_handle(info.name, info.size, info.num_entries))
+ if ((h = alloc_handle(info.name, info.size, info.num_entries))
== NULL) {
close(sockfd);
sockfd = -1;
@@ -544,8 +295,11 @@ TC_INIT(const char *tablename)
/* Initialize current state */
h->info = info;
- //h->new_number = h->info.num_entries;
- //
+ 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->entries.size = h->info.size;
tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
@@ -559,29 +313,16 @@ 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;
-
- /* 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 */
-
+ if ((*h)->cache_chain_heads)
+ free((*h)->cache_chain_heads);
free(*h);
*h = NULL;
}
@@ -595,7 +336,6 @@ 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)
{
@@ -636,13 +376,180 @@ 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);
}
-#endif
+
+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;
+}
/* Does this chain exist? */
int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
@@ -650,7 +557,6 @@ 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)
@@ -687,38 +593,39 @@ 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)
{
- struct chain_head *firsthead = list_entry((*handle)->chains.next,
- struct chain_head, list);
- (*handle)->chain_iterator_cur = firsthead;
+ if ((*handle)->cache_chain_heads == NULL
+ && !populate_cache(*handle))
+ return NULL;
+
+ (*handle)->cache_chain_iteration
+ = &(*handle)->cache_chain_heads[0];
- return firsthead->name;
+ return (*handle)->cache_chain_iteration->name;
}
/* Iterator functions to run through the chains. Returns NULL at end. */
const char *
TC_NEXT_CHAIN(TC_HANDLE_T *handle)
{
- struct chain_head *next = list_entry(&(*handle)->chain_iterator_cur->list.next, struct chain_head, list);
- (*handle)->chain_iterator_cur = next;
+ (*handle)->cache_chain_iteration++;
- if (&next->list == &(*handle)->chains)
+ if ((*handle)->cache_chain_iteration - (*handle)->cache_chain_heads
+ == (*handle)->cache_num_chains)
return NULL;
- return next->name;
+ return (*handle)->cache_chain_iteration->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_head *c;
- struct rule_head *r;
+ struct chain_cache *c;
c = find_label(chain, *handle);
if (!c) {
@@ -727,26 +634,22 @@ TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
}
/* Empty chain: single return/policy rule */
- if (list_empty(&c->rules))
+ if (c->start_off == c->end_off)
return NULL;
- r = list_entry(c->rules.next, struct rule_head, list);
- (*handle)->rule_iterator_cur = r;
-
- return r->entry;
+ (*handle)->cache_rule_end = offset2entry(*handle, c->end_off);
+ return offset2entry(*handle, c->start_off);
}
/* Returns NULL when rules run out. */
const STRUCT_ENTRY *
TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
{
- struct rule_head *r = list_entry((*handle)->rule_iterator_cur->list.next, struct rule_head, list);
-
- if (&r->list == &r->chain->rules)
+ if ((void *)prev + prev->next_offset
+ == (void *)(*handle)->cache_rule_end)
return NULL;
- /* NOTE: prev is without any influence ! */
- return r->entry;
+ return (void *)prev + prev->next_offset;
}
#if 0
@@ -792,6 +695,8 @@ 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;
@@ -811,24 +716,21 @@ target_name(TC_HANDLE_T handle, const STRUCT_ENTRY *ce)
else if (spos == -NF_QUEUE-1)
return LABEL_QUEUE;
- fprintf(stderr, "ERROR: entry %p not a valid target (%d)\n",
- e, spos);
+ fprintf(stderr, "ERROR: off %lu/%u not a valid target (%i)\n",
+ entry2offset(handle, e), handle->entries.size,
+ spos);
abort();
}
-#if 0
-// jumpto = get_entry(handle, spos);
+ 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. */
@@ -859,31 +761,23 @@ 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)
+ if (hook != 0)
+ start = (*handle)->info.hook_entry[hook-1];
+ else
return NULL;
- chainh = find_label(chain, *handle);
- if (!chainh) {
- errno = ENOENT;
- return NULL;
- }
-
- ruleh = chainh->lastrule;
-
- e = ruleh->entry;
+ e = get_entry(*handle, get_chain_end(*handle, start));
*counters = e->counters;
return target_name(*handle, e);
}
-#if 0
-static int
+static inline int
correct_verdict(STRUCT_ENTRY *e,
char *base,
unsigned int offset, int delta_offset)
@@ -915,9 +809,149 @@ 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)
@@ -945,7 +979,7 @@ map_target(const TC_HANDLE_T handle,
unsigned int offset,
STRUCT_ENTRY_TARGET *old)
{
- STRUCT_ENTRY_TARGET *t = (STRUCT_ENTRY_TARGET *)GET_TARGET(e);
+ STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
/* Save old target (except data, which we don't change, except for
standard case, where we don't care). */
@@ -969,14 +1003,11 @@ map_target(const TC_HANDLE_T handle,
return 0;
} else {
/* Maybe it's an existing chain name. */
- struct chain_head *c;
+ struct chain_cache *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... */
@@ -997,32 +1028,18 @@ unmap_target(STRUCT_ENTRY *e, STRUCT_ENTRY_TARGET *old)
*t = *old;
}
-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'. */
+/* Insert the entry `fw' 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)
{
- struct chain_head *c;
- struct rule_head *prev;
+ unsigned int chainindex, offset;
+ STRUCT_ENTRY_TARGET old;
+ struct chain_cache *c;
+ STRUCT_ENTRY *tmp;
+ int ret;
iptc_fn = TC_INSERT_ENTRY;
if (!(c = find_label(chain, *handle))) {
@@ -1030,16 +1047,24 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
return 0;
}
- prev = ruleh_get_n(c, rulenum-1);
- if (!prev) {
+ chainindex = offset2index(*handle, c->start_off);
+
+ tmp = index2entry(*handle, chainindex + rulenum);
+ if (!tmp || tmp > offset2entry(*handle, c->end_off)) {
errno = E2BIG;
return 0;
}
+ offset = index2offset(*handle, chainindex + rulenum);
- if (append_entrycopy(e, prev))
- return 1;
+ /* Mapping target actually alters entry, but that's
+ transparent to the caller. */
+ if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
+ return 0;
- return 0;
+ ret = insert_rules(1, e->next_offset, e, offset,
+ chainindex + rulenum, rulenum == 0, handle);
+ unmap_target((STRUCT_ENTRY *)e, &old);
+ return ret;
}
/* Atomically replace rule `rulenum' in `chain' with `fw'. */
@@ -1049,8 +1074,11 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
unsigned int rulenum,
TC_HANDLE_T *handle)
{
- struct chain_head *c;
- struct rule_head *repl;
+ unsigned int chainindex, offset;
+ STRUCT_ENTRY_TARGET old;
+ struct chain_cache *c;
+ STRUCT_ENTRY *tmp;
+ int ret;
iptc_fn = TC_REPLACE_ENTRY;
@@ -1059,43 +1087,54 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
return 0;
}
- repl = ruleh_get_n(c, rulenum);
- if (!repl) {
+ chainindex = offset2index(*handle, c->start_off);
+
+ tmp = index2entry(*handle, chainindex + rulenum);
+ if (!tmp || tmp >= offset2entry(*handle, c->end_off)) {
errno = E2BIG;
return 0;
}
- if (!append_entrycopy(e, repl)) {
- errno = ENOMEM;
+ 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;
- }
- ruleh_free(repl);
- return 1;
+ if (!map_target(*handle, (STRUCT_ENTRY *)e, offset, &old))
+ return 0;
+
+ ret = insert_rules(1, e->next_offset, e, offset,
+ chainindex + rulenum, 1, handle);
+ unmap_target((STRUCT_ENTRY *)e, &old);
+ return ret;
}
-/* Append entry `e' to chain `chain'. Equivalent to insert with
+/* Append entry `fw' 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_head *c;
- struct rule_head *rhead;
+ struct chain_cache *c;
+ STRUCT_ENTRY_TARGET old;
+ int ret;
iptc_fn = TC_APPEND_ENTRY;
-
if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
- rhead = list_entry(c->rules.prev, struct rule_head, list);
- if(append_entrycopy(e, rhead))
- return 1;
-
- 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;
}
static inline int
@@ -1144,15 +1183,16 @@ is_same(const STRUCT_ENTRY *a,
const STRUCT_ENTRY *b,
unsigned char *matchmask);
-/* Delete the first rule in `chain' which matches `origfw'. */
+/* Delete the first rule in `chain' which matches `fw'. */
int
TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
const STRUCT_ENTRY *origfw,
unsigned char *matchmask,
TC_HANDLE_T *handle)
{
- struct chain_head *c;
- struct list_head *cur, *cur2;
+ unsigned int offset;
+ struct chain_cache *c;
+ STRUCT_ENTRY *e, *fw;
iptc_fn = TC_DELETE_ENTRY;
if (!(c = find_label(chain, *handle))) {
@@ -1160,15 +1200,40 @@ TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
return 0;
}
- 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;
+ 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;
}
}
+ free(fw);
errno = ENOENT;
return 0;
}
@@ -1179,25 +1244,33 @@ TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
unsigned int rulenum,
TC_HANDLE_T *handle)
{
- struct chain_head *chainh;
- struct rule_head *rhead;
+ unsigned int index;
+ int ret;
+ STRUCT_ENTRY *e;
+ struct chain_cache *c;
iptc_fn = TC_DELETE_NUM_ENTRY;
-
- if (!(chainh = find_label(chain, *handle))) {
+ if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
- rhead = ruleh_get_n(chainh, rulenum);
- if (!rhead) {
+ index = offset2index(*handle, c->start_off) + rulenum;
+
+ if (index >= offset2index(*handle, c->end_off)) {
errno = E2BIG;
return 0;
}
- ruleh_free(rhead);
+ e = index2entry(*handle, index);
+ if (e == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
- return 1;
+ ret = delete_rules(1, e->next_offset, entry2offset(*handle, e),
+ index, handle);
+ return ret;
}
/* Check the packet `fw' on chain `chain'. Returns the verdict, or
@@ -1215,40 +1288,46 @@ TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
int
TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
{
- struct list_head *cur, *cur2;
- struct chain_head *chainh;
+ unsigned int startindex, endindex;
+ STRUCT_ENTRY *startentry, *endentry;
+ struct chain_cache *c;
+ int ret;
- if (!(chainh = find_label(chain, *handle))) {
+ iptc_fn = TC_FLUSH_ENTRIES;
+ if (!(c = 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);
- 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;
+ ret = delete_rules(endindex - startindex,
+ (char *)endentry - (char *)startentry,
+ c->start_off, startindex,
+ handle);
+ return ret;
}
/* Zeroes the counters in a chain. */
int
TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
{
- struct chain_head *c;
- struct list_head *cur;
+ unsigned int i, end;
+ struct chain_cache *c;
if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
- 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;
+ 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;
}
set_changed(*handle);
@@ -1261,19 +1340,28 @@ TC_READ_COUNTER(const IPT_CHAINLABEL chain,
TC_HANDLE_T *handle)
{
STRUCT_ENTRY *e;
- struct chain_head *c;
- struct rule_head *r;
+ struct chain_cache *c;
+ unsigned int chainindex, end;
iptc_fn = TC_READ_COUNTER;
CHECK(*handle);
- if (!(c = find_label(chain, *handle) )
- || !(r = ruleh_get_n(c, rulenum))) {
+ if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return NULL;
}
- return &r->entry->counters;
+ 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;
}
int
@@ -1282,20 +1370,32 @@ TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
TC_HANDLE_T *handle)
{
STRUCT_ENTRY *e;
- struct chain_head *c;
- struct rule_head *r;
+ struct chain_cache *c;
+ unsigned int chainindex, end;
iptc_fn = TC_ZERO_COUNTER;
CHECK(*handle);
- if (!(c = find_label(chain, *handle))
- || !(r = ruleh_get_n(c, rulenum))) {
+ if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
- if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
- r->counter_map.maptype = COUNTER_MAP_ZEROED;
+ 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;
+ }
set_changed(*handle);
@@ -1309,20 +1409,31 @@ TC_SET_COUNTER(const IPT_CHAINLABEL chain,
TC_HANDLE_T *handle)
{
STRUCT_ENTRY *e;
- struct chain_head *c;
- struct rule_head *r;
+ struct chain_cache *c;
+ unsigned int chainindex, end;
iptc_fn = TC_SET_COUNTER;
CHECK(*handle);
- if (!(c = find_label(chain, *handle))
- || !(r = ruleh_get_n(c, rulenum))) {
+ if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
-
- r->counter_map.maptype = COUNTER_MAP_SET;
- memcpy(&r->entry->counters, counters, sizeof(STRUCT_COUNTERS));
+
+ 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));
set_changed(*handle);
@@ -1336,16 +1447,13 @@ int
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
{
int ret;
- struct chainstart {
+ struct {
STRUCT_ENTRY head;
struct ipt_error_target name;
- } *newc1;
- struct chainend {
STRUCT_ENTRY ret;
STRUCT_STANDARD_TARGET target;
- } *newc2;
- struct rule_head *newr1, *newr2;
- struct chain_head *chead;
+ } newc;
+ unsigned int destination;
iptc_fn = TC_CREATE_CHAIN;
@@ -1365,53 +1473,42 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
return 0;
}
- 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
+ memset(&newc, 0, sizeof(newc));
+ newc.head.target_offset = sizeof(STRUCT_ENTRY);
+ newc.head.next_offset
= sizeof(STRUCT_ENTRY)
+ ALIGN(sizeof(struct ipt_error_target));
- 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);
+ 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);
- newc2->ret.target_offset = sizeof(STRUCT_ENTRY);
- newc2->ret.next_offset
+ newc.ret.target_offset = sizeof(STRUCT_ENTRY);
+ newc.ret.next_offset
= sizeof(STRUCT_ENTRY)
+ ALIGN(sizeof(STRUCT_STANDARD_TARGET));
- strcpy(newc2->target.target.u.user.name, STANDARD_TARGET);
- newc2->target.target.u.target_size
+ strcpy(newc.target.target.u.user.name, STANDARD_TARGET);
+ newc.target.target.u.target_size
= ALIGN(sizeof(STRUCT_STANDARD_TARGET));
- newc2->target.verdict = RETURN;
+ newc.target.verdict = RETURN;
- list_prepend(&newr1->list, &chead->rules);
- chead->firstrule = newr1;
- list_append(&newr2->list, &chead->rules);
- chead->lastrule = newr2;
+ destination = index2offset(*handle, (*handle)->new_number -1);
- return 1;
+ /* Add just before terminal entry */
+ ret = insert_rules(2, sizeof(newc), &newc.head,
+ destination,
+ (*handle)->new_number - 1,
+ 0, handle);
+
+ 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;
}
-#if 0
static int
count_ref(STRUCT_ENTRY *e, unsigned int offset, unsigned int *ref)
{
@@ -1445,32 +1542,17 @@ 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_head *chainh;
+ struct chain_cache *c;
+ int ret;
+ STRUCT_ENTRY *start;
-#if 0
if (!TC_GET_REFERENCES(&references, chain, handle))
return 0;
@@ -1485,20 +1567,28 @@ TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
errno = EMLINK;
return 0;
}
-#endif
- if (!(chainh = find_label(chain, *handle))) {
+ if (!(c = find_label(chain, *handle))) {
errno = ENOENT;
return 0;
}
- if (!(count_rules(chainh) == 0)) {
+ if (c->start_off != c->end_off) {
errno = ENOTEMPTY;
return 0;
}
- chainh_free(chainh);
- return 1;
+ /* 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;
}
/* Renames a chain. */
@@ -1506,8 +1596,8 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
const IPT_CHAINLABEL newname,
TC_HANDLE_T *handle)
{
- struct chain_head *c;
- struct rule_head *ruleh;
+ unsigned int labeloff, labelidx;
+ struct chain_cache *c;
struct ipt_error_target *t;
iptc_fn = TC_RENAME_CHAIN;
@@ -1534,14 +1624,22 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
return 0;
}
- ruleh = list_entry(&c->rules.next, struct rule_head, list);
+ /* Need label index: preceeds chain start */
+ labelidx = offset2index(*handle, c->start_off) - 1;
+ labeloff = index2offset(*handle, labelidx);
t = (struct ipt_error_target *)
- GET_TARGET(ruleh->entry);
+ GET_TARGET(get_entry(*handle, labeloff));
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;
}
@@ -1552,10 +1650,8 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain,
STRUCT_COUNTERS *counters,
TC_HANDLE_T *handle)
{
- int ctrindex;
unsigned int hook;
- struct chain_head *chainh;
- struct rule_head *policyrh;
+ unsigned int policyoff, ctrindex;
STRUCT_ENTRY *e;
STRUCT_STANDARD_TARGET *t;
@@ -1568,18 +1664,15 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain,
} else
hook--;
- if (!(chainh = find_label(chain, *handle))) {
- errno = ENOENT;
- return 0;
- }
-
- policyrh = chainh->lastrule;
- if (policyrh) {
- printf("ERROR: Policy for `%s' non-existant", chain);
+ 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]);
return 0;
}
- t = (STRUCT_STANDARD_TARGET *)GET_TARGET(policyrh->entry);
+ e = get_entry(*handle, policyoff);
+ t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
if (strcmp(policy, LABEL_ACCEPT) == 0)
t->verdict = -NF_ACCEPT - 1;
@@ -1596,11 +1689,12 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain,
/* set byte and packet counters */
memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
- policyrh->counter_map.maptype = COUNTER_MAP_SET;
+ (*handle)->counter_map[ctrindex].maptype
+ = COUNTER_MAP_SET;
} else {
- policyrh->counter_map.maptype = COUNTER_MAP_NOMAP;
- policyrh->counter_map.mappos = 0;
+ (*handle)->counter_map[ctrindex]
+ = ((struct counter_map){ COUNTER_MAP_NOMAP, 0 });
}
set_changed(*handle);