summaryrefslogtreecommitdiffstats
path: root/libiptc/libiptc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libiptc/libiptc.c')
-rw-r--r--libiptc/libiptc.c1190
1 files changed, 548 insertions, 642 deletions
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 <laforge@netfilter.org>:
* - Reimplementation of chain cache to use offsets instead of entries
* 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
- * - 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 <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;
@@ -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);