From cd54b43d64f35286514cd7742dde0f1e1e2b8843 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Sun, 23 Jun 2002 08:01:47 +0000 Subject: base patch for user defined chains support --- userspace/ebtables2/communication.c | 187 ++++++++++++--- userspace/ebtables2/ebtables.c | 452 +++++++++++++++++++++++++++--------- 2 files changed, 496 insertions(+), 143 deletions(-) (limited to 'userspace') diff --git a/userspace/ebtables2/communication.c b/userspace/ebtables2/communication.c index a919e7b..c59ca22 100644 --- a/userspace/ebtables2/communication.c +++ b/userspace/ebtables2/communication.c @@ -42,9 +42,11 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) struct ebt_u_entry *e; struct ebt_u_match_list *m_l; struct ebt_u_watcher_list *w_l; + struct ebt_u_chain_list *cl; + struct ebt_u_entries *entries; char *p, *base; int i, j; - unsigned int entries_size = 0; + unsigned int entries_size = 0, *chain_offsets; new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace)); if (!new) @@ -54,15 +56,34 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) new->nentries = u_repl->nentries; new->num_counters = u_repl->num_counters; new->counters = u_repl->counters; - memcpy(new->counter_entry, u_repl->counter_entry, - sizeof(new->counter_entry)); + // determine nr of udc + i = 0; + cl = u_repl->udc; + while (cl) { + i++; + cl = cl->next; + } + i += NF_BR_NUMHOOKS; + chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int)); // determine size - for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(new->valid_hooks & (1 << i))) - continue; + i = 0; + cl = u_repl->udc; + while (1) { + if (i < NF_BR_NUMHOOKS) { + if (!(new->valid_hooks & (1 << i))) { + i++; + continue; + } + entries = u_repl->hook_entry[i]; + } else { + if (!cl) + break; + entries = cl->udc; + } + chain_offsets[i] = entries_size; entries_size += sizeof(struct ebt_entries); j = 0; - e = u_repl->hook_entry[i]->entries; + e = entries->entries; while (e) { j++; entries_size += sizeof(struct ebt_entry); @@ -83,9 +104,12 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) e = e->next; } // a little sanity check - if (j != u_repl->hook_entry[i]->nentries) + if (j != entries->nentries) print_bug("Wrong nentries: %d != %d, hook = %s", j, - u_repl->hook_entry[i]->nentries, hooknames[i]); + entries->nentries, entries->name); + if (i >= NF_BR_NUMHOOKS) + cl = cl->next; + i++; } new->entries_size = entries_size; @@ -95,18 +119,31 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) // put everything in one block p = new->entries; - for (i = 0; i < NF_BR_NUMHOOKS; i++) { + i = 0; + cl = u_repl->udc; + while (1) { struct ebt_entries *hlp; - if (!(new->valid_hooks & (1 << i))) - continue; hlp = (struct ebt_entries *)p; - new->hook_entry[i] = hlp; - hlp->nentries = u_repl->hook_entry[i]->nentries; - hlp->policy = u_repl->hook_entry[i]->policy; + if (i < NF_BR_NUMHOOKS) { + if (!(new->valid_hooks & (1 << i))) { + i++; + continue; + } + entries = u_repl->hook_entry[i]; + new->hook_entry[i] = hlp; + } else { + if (!cl) + break; + entries = cl->udc; + } + hlp->nentries = entries->nentries; + hlp->policy = entries->policy; + strcpy(hlp->name, entries->name); + hlp->counter_offset = entries->counter_offset; hlp->distinguisher = 0; // make the kernel see the light p += sizeof(struct ebt_entries); - e = u_repl->hook_entry[i]->entries; + e = entries->entries; while (e) { struct ebt_entry *tmp = (struct ebt_entry *)p; @@ -148,16 +185,27 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) tmp->target_offset = p - base; memcpy(p, e->t, e->t->target_size + sizeof(struct ebt_entry_target)); + if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) { + struct ebt_standard_target *st = + (struct ebt_standard_target *)p; + // translate the jump to a udc + if (st->verdict >= 0) + st->verdict = chain_offsets[st->verdict]; + } p += e->t->target_size + sizeof(struct ebt_entry_target); tmp->next_offset = p - base; e = e->next; } + if (i >= NF_BR_NUMHOOKS) + cl = cl->next; + i++; } // sanity check if (p - new->entries != new->entries_size) print_bug("Entries_size bug"); + free(chain_offsets); return new; } @@ -287,7 +335,7 @@ ebt_translate_watcher(struct ebt_entry_watcher *w, static int ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl, - unsigned int valid_hooks) + unsigned int valid_hooks, char *base) { // an entry if (e->bitmask & EBT_ENTRY_OR_ENTRIES) { @@ -332,6 +380,26 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, "userspace tool", t->u.name); memcpy(new->t, t, t->target_size + sizeof(struct ebt_entry_target)); + // deal with jumps to udc + if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) { + char *tmp = base; + int verdict = ((struct ebt_standard_target *)t)->verdict; + int i; + struct ebt_u_chain_list *cl; + + if (verdict >= 0) { + tmp += verdict; + cl = u_repl->udc; + i = 0; + while (cl && cl->kernel_start != tmp) { + i++; + cl = cl->next; + } + if (!cl) + print_bug("can't find udc for jump"); + ((struct ebt_standard_target *)new->t)->verdict = i; + } + } // I love pointers **u_e = new; @@ -342,29 +410,78 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, } else { // a new chain int i; struct ebt_entries *entries = (struct ebt_entries *)e; - struct ebt_u_entries *new; + struct ebt_u_chain_list *cl; - for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) - if (valid_hooks & (1 << i)) - break; - if (i >= NF_BR_NUMHOOKS) - print_bug("Not enough valid hooks"); - *hook = i; if (*n != *cnt) print_bug("Nr of entries in the chain is wrong"); *n = entries->nentries; *cnt = 0; - new = (struct ebt_u_entries *) - malloc(sizeof(struct ebt_u_entries)); - if (!new) - print_memory(); + for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) + if (valid_hooks & (1 << i)) + break; + *hook = i; + // makes use of fact that standard chains come before udc + if (i >= NF_BR_NUMHOOKS) { // udc + i -= NF_BR_NUMHOOKS; + cl = u_repl->udc; + while (i-- > 0) + cl = cl->next; + *u_e = &(cl->udc->entries); + } else { + *u_e = &(u_repl->hook_entry[*hook]->entries); + } + return 0; + } +} + +// initialize all chain headers +static int +ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, + struct ebt_u_replace *u_repl, unsigned int valid_hooks) +{ + int i; + struct ebt_entries *entries = (struct ebt_entries *)e; + struct ebt_u_entries *new; + struct ebt_u_chain_list **chain_list; + + if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { + for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) + if (valid_hooks & (1 << i)) + break; + // makes use of fact that standard chains come before udc + if (i >= NF_BR_NUMHOOKS) { // udc + chain_list = &u_repl->udc; + // add in the back + while (*chain_list) + chain_list = &((*chain_list)->next); + *chain_list = (struct ebt_u_chain_list *) + malloc(sizeof(struct ebt_u_chain_list)); + if (!(*chain_list)) + print_memory(); + (*chain_list)->next = NULL; + (*chain_list)->udc = (struct ebt_u_entries *) + malloc(sizeof(struct ebt_u_entries)); + if (!((*chain_list)->udc)) + print_memory(); + new = (*chain_list)->udc; + // ebt_translate_entry depends on this for knowing + // to which chain is being jumped + (*chain_list)->kernel_start = (char *)e; + } else { + *hook = i; + new = (struct ebt_u_entries *) + malloc(sizeof(struct ebt_u_entries)); + if (!new) + print_memory(); + u_repl->hook_entry[*hook] = new; + } new->nentries = entries->nentries; new->policy = entries->policy; new->entries = NULL; - u_repl->hook_entry[*hook] = new; - *u_e = &new->entries; - return 0; + new->counter_offset = entries->counter_offset; + strcpy(new->name, entries->name); } + return 0; } // talk with kernel to receive the kernel's table @@ -405,15 +522,17 @@ int get_table(struct ebt_u_replace *u_repl) u_repl->nentries = repl.nentries; u_repl->num_counters = repl.num_counters; u_repl->counters = repl.counters; - memcpy(u_repl->counter_entry, repl.counter_entry, - sizeof(repl.counter_entry)); + u_repl->udc = NULL; hook = -1; + EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains, + &hook, u_repl, u_repl->valid_hooks); i = 0; // holds the expected nr. of entries for the chain j = 0; // holds the up to now counted entries for the chain k = 0; // holds the total nr. of entries, // should equal u_repl->nentries afterwards + hook = -1; EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry, - &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks); + &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries); if (k != u_repl->nentries) print_bug("Wrong total nentries"); return 0; diff --git a/userspace/ebtables2/ebtables.c b/userspace/ebtables2/ebtables.c index 0233cfe..2fc217c 100644 --- a/userspace/ebtables2/ebtables.c +++ b/userspace/ebtables2/ebtables.c @@ -46,12 +46,13 @@ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif -#define DATABASEHOOKNR NF_BR_NUMHOOKS +#define DATABASEHOOKNR -2 #define DATABASEHOOKNAME "DB" static char *prog_name = PROGNAME; static char *prog_version = PROGVERSION; -char* hooknames[NF_BR_NUMHOOKS] = { +char *hooknames[NF_BR_NUMHOOKS] = +{ [NF_BR_PRE_ROUTING]"PREROUTING", [NF_BR_LOCAL_IN]"INPUT", [NF_BR_FORWARD]"FORWARD", @@ -97,6 +98,7 @@ char* standard_targets[NUM_STANDARD_TARGETS] = { "ACCEPT", "DROP", "CONTINUE", + "RETURN", }; unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; @@ -496,7 +498,7 @@ int number_to_name(unsigned short proto, char *name) } // helper function for list_rules() -static void list_em(int hooknr) +static void list_em(struct ebt_u_entries *entries) { int i, j, space = 0, digits; struct ebt_u_entry *hlp; @@ -507,18 +509,18 @@ static void list_em(int hooknr) struct ebt_u_target *t; char name[21]; - hlp = replace.hook_entry[hooknr]->entries; - printf("\nBridge chain: %s\nPolicy: %s\n", hooknames[hooknr], - standard_targets[replace.hook_entry[hooknr]->policy]); - printf("nr. of entries: %d \n", replace.hook_entry[hooknr]->nentries); + hlp = entries->entries; + printf("\nBridge chain: %s\nPolicy: %s\n", entries->name, + standard_targets[-entries->policy - 1]); + printf("nr. of entries: %d \n", entries->nentries); - i = replace.hook_entry[hooknr]->nentries; + i = entries->nentries; while (i >9) { space++; i /= 10; } - for (i = 0; i < replace.hook_entry[hooknr]->nentries; i++) { + for (i = 0; i < entries->nentries; i++) { digits = 0; // A little work to get nice rule numbers. while (j > 9) { @@ -532,22 +534,22 @@ static void list_em(int hooknr) // Don't print anything about the protocol if no protocol was // specified, obviously this means any protocol will do. if (!(hlp->bitmask & EBT_NOPROTO)) { - printf("eth proto: "); + printf("-p "); if (hlp->invflags & EBT_IPROTO) printf("! "); if (hlp->bitmask & EBT_802_3) printf("Length, "); else { if (number_to_name(ntohs(hlp->ethproto), name)) - printf("0x%x, ", ntohs(hlp->ethproto)); + printf("0x%x ", ntohs(hlp->ethproto)); else - printf("%s, ", name); + printf("%s ", name); } } if (hlp->bitmask & EBT_SOURCEMAC) { char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - printf("source mac: "); + printf("-s "); if (hlp->invflags & EBT_ISOURCE) printf("! "); if (!memcmp(hlp->sourcemac, mac_type_unicast, 6) && @@ -573,12 +575,12 @@ static void list_em(int hooknr) hlp->sourcemsk)); } endsrc: - printf(", "); + printf(" "); } if (hlp->bitmask & EBT_DESTMAC) { char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - printf("dest mac: "); + printf("-d "); if (hlp->invflags & EBT_IDEST) printf("! "); if (!memcmp(hlp->destmac, mac_type_unicast, 6) && @@ -604,27 +606,31 @@ endsrc: hlp->destmsk)); } enddst: - printf(", "); + printf(" "); } if (hlp->in[0] != '\0') { + printf("-i "); if (hlp->invflags & EBT_IIN) printf("! "); - printf("in-if: %s, ", hlp->in); + printf("%s ", hlp->in); } if (hlp->logical_in[0] != '\0') { + printf("--logical-in "); if (hlp->invflags & EBT_ILOGICALIN) printf("! "); - printf("logical in-if: %s, ", hlp->logical_in); + printf("%s ", hlp->logical_in); } if (hlp->logical_out[0] != '\0') { + printf("--logical-out "); if (hlp->invflags & EBT_ILOGICALOUT) printf("! "); - printf("logical out-if: %s, ", hlp->logical_out); + printf("%s, ", hlp->logical_out); } if (hlp->out[0] != '\0') { + printf("-o "); if (hlp->invflags & EBT_IOUT) printf("! "); - printf("out-if: %s, ", hlp->out); + printf("%s, ", hlp->out); } m_l = hlp->m_list; @@ -644,30 +650,151 @@ enddst: w_l = w_l->next; } - printf("target: "); + printf("-j "); t = find_target(hlp->t->u.name); if (!t) print_bug("Target not found"); t->print(hlp, hlp->t); printf(", count = %llu", - replace.counters[replace.counter_entry[hooknr] + i].pcnt); + replace.counters[entries->counter_offset + i].pcnt); printf("\n"); hlp = hlp->next; } } +static struct ebt_u_entries *nr_to_chain(int nr) +{ + if (nr == -1) + return NULL; + if (nr < NF_BR_NUMHOOKS) + return replace.hook_entry[nr]; + else { + int i; + struct ebt_u_chain_list *cl = replace.udc; + + i = nr - NF_BR_NUMHOOKS; + while (i > 0 && cl) + cl = cl->next; + if (cl) + return cl->udc; + else + return NULL; + } +} + +static struct ebt_u_entries *to_chain() +{ + return nr_to_chain(replace.selected_hook); +} + +struct ebt_u_stack +{ + int chain_nr; + int n; + struct ebt_u_entry *e; + struct ebt_u_entries *entries; +}; + +void check_for_loops() +{ + int chain_nr , i, j , k, sp = 0, verdict; + struct ebt_u_entries *entries, *entries2; + struct ebt_u_stack *stack = NULL; + struct ebt_u_entry *e; + + i = -1; + // initialize hook_mask to 0 + while (1) { + i++; + if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i))) + continue; + entries = nr_to_chain(i); + if (!entries) + break; + entries->hook_mask = 0; + } + if (i > NF_BR_NUMHOOKS) { + stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) * + sizeof(struct ebt_u_stack)); + if (!stack) + print_memory(); + } + + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if (!(replace.valid_hooks & (1 << i))) + continue; + entries = nr_to_chain(i); + entries->hook_mask = (1 << i); + chain_nr = i; + + e = entries->entries; + for (j = 0; j < entries->nentries; j++) { + if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) + goto letscontinue; + verdict = ((struct ebt_standard_target *)(e->t))->verdict; + if (verdict < 0) + goto letscontinue; + // no jumping to a standard chain + if (verdict < NF_BR_NUMHOOKS) + goto error; + entries2 = nr_to_chain(verdict); + entries2->hook_mask |= entries->hook_mask; + // now see if we've been here before + for (k = 0; k < sp; k++) + if (stack[k].chain_nr == verdict) + goto error; + // jump to the chain, make sure we know how to get back + stack[sp].chain_nr = chain_nr; + stack[sp].n = j; + stack[sp].entries = entries; + stack[sp++].e = e; + j = -1; + e = entries2->entries; + chain_nr = verdict; + entries = entries2; + continue; +letscontinue: + e = e->next; + } + // we are in a standard chain + if (sp == 0) + continue; + // go back to the chain one level lower + sp--; + j = stack[sp].n; + chain_nr = stack[sp].chain_nr; + e = stack[sp].e; + entries = stack[sp].entries; + goto letscontinue; + } + free(stack); + return; +error: + print_error("Loop"); +} + // parse the chain name and return the corresponding nr int get_hooknr(char* arg) { int i; + struct ebt_u_chain_list *cl = replace.udc; // database is special case (not really a chain) if (!strcmp(arg, DATABASEHOOKNAME)) return DATABASEHOOKNR; - for (i = 0; i < NF_BR_NUMHOOKS; i++) - if (!strcmp(arg, hooknames[i])) + for (i = 0; i < NF_BR_NUMHOOKS; i++) { + if (!(replace.valid_hooks & (1 << i))) + continue; + if (!strcmp(arg, replace.hook_entry[i]->name)) + return i; + } + while(cl) { + if (!strcmp(arg, cl->udc->name)) return i; + i++; + cl = cl->next; + } return -1; } @@ -733,11 +860,26 @@ static void list_rules() int i; printf("Bridge table: %s\n", table->name); - if (replace.selected_hook != -1) list_em(replace.selected_hook); - else - for (i = 0; i < NF_BR_NUMHOOKS; i++) - if (replace.valid_hooks & (1 << i)) - list_em(i); + if (replace.selected_hook != -1) { + list_em(to_chain()); + } else { + struct ebt_u_chain_list *cl = replace.udc; + + i = 0; + while (1) { + if (i < NF_BR_NUMHOOKS) { + if (replace.valid_hooks & (1 << i)) + list_em(replace.hook_entry[i]); + i++; + continue; + } else { + if (!cl) + break; + list_em(cl->udc); + cl = cl->next; + } + } + } return; } @@ -745,10 +887,11 @@ static void list_rules() static void change_policy(int policy) { int i; + struct ebt_u_entries *entries = to_chain(); // don't do anything if the policy is the same - if (replace.hook_entry[replace.selected_hook]->policy != policy) { - replace.hook_entry[replace.selected_hook]->policy = policy; + if (entries->policy != policy) { + entries->policy = policy; replace.num_counters = replace.nentries; if (replace.nentries) { // '+ 1' for the CNT_END @@ -770,74 +913,100 @@ static void change_policy(int policy) // flush one chain or the complete table static void flush_chains() { - int i, j, oldnentries; + int i, j, oldnentries, numdel; unsigned short *cnt; struct ebt_u_entry *u_e, *tmp; + struct ebt_u_entries *entries = to_chain(); // flush whole table - if (replace.selected_hook == -1) { + if (!entries) { if (replace.nentries == 0) exit(0); replace.nentries = 0; // no need for the kernel to give us counters back replace.num_counters = 0; + // free everything and zero (n)entries - for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(replace.valid_hooks & (1 << i))) - continue; - replace.hook_entry[i]->nentries = 0; - u_e = replace.hook_entry[i]->entries; + i = -1; + while (1) { + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) + continue; + else + break; + } + entries->nentries = 0; + entries->counter_offset = 0; + u_e = entries->entries; + entries->entries = NULL; while (u_e) { free_u_entry(u_e); tmp = u_e->next; free(u_e); u_e = tmp; } - replace.hook_entry[i]->entries = NULL; } return; } - if (replace.hook_entry[replace.selected_hook]->nentries == 0) + if (entries->nentries == 0) exit(0); oldnentries = replace.nentries; - replace.nentries = replace.nentries - - replace.hook_entry[replace.selected_hook]->nentries; + replace.nentries -= entries->nentries; + numdel = entries->nentries; - // delete the counters belonging to the specified chain if (replace.nentries) { // +1 for CNT_END if ( !(counterchanges = (unsigned short *) malloc((oldnentries + 1) * sizeof(unsigned short))) ) print_memory(); cnt = counterchanges; - for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(replace.valid_hooks & (1 << i))) + } + // delete the counters belonging to the specified chain, + // update counter_offset + i = -1; + while (1) { + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) continue; - for (j = 0; j < replace.hook_entry[i]->nentries; j++) { - if (i != replace.selected_hook) + else + break; + } + if (i > replace.selected_hook) + entries->counter_offset -= numdel; + if (replace.nentries) { + for (j = 0; j < entries->nentries; j++) { + if (i == replace.selected_hook) *cnt = CNT_NORM; else *cnt = CNT_DEL; cnt++; } } + } + + if (replace.nentries) { *cnt = CNT_END; replace.num_counters = oldnentries; } else replace.num_counters = 0; - replace.hook_entry[replace.selected_hook]->nentries = 0; - u_e = replace.hook_entry[replace.selected_hook]->entries; + entries = to_chain(); + entries->nentries = 0; + u_e = entries->entries; while (u_e) { free_u_entry(u_e); tmp = u_e->next; free(u_e); u_e = tmp; } - replace.hook_entry[replace.selected_hook]->entries = NULL; -} + entries->entries = NULL; +} // -1 == no match static int check_rule_exists(int rule_nr) @@ -848,32 +1017,34 @@ static int check_rule_exists(int rule_nr) struct ebt_u_watcher_list *w_l, *w_l2; struct ebt_u_watcher *w; struct ebt_u_target *t = (struct ebt_u_target *)new_entry->t; + struct ebt_u_entries *entries = to_chain(); int i, j, k; // handle '-D chain rulenr' command if (rule_nr != -1) { - if (rule_nr > - replace.hook_entry[replace.selected_hook]->nentries) + if (rule_nr > entries->nentries) return 0; // user starts counting from 1 return rule_nr - 1; } - u_e = replace.hook_entry[replace.selected_hook]->entries; + u_e = entries->entries; // check for an existing rule (if there are duplicate rules, // take the first occurance) - for (i = 0; i < replace.hook_entry[replace.selected_hook]->nentries; - i++, u_e = u_e->next) { + for (i = 0; i < entries->nentries; i++, u_e = u_e->next) { if (!u_e) print_bug("Hmm, trouble"); if ( u_e->ethproto == new_entry->ethproto && !strcmp(u_e->in, new_entry->in) && !strcmp(u_e->out, new_entry->out) && u_e->bitmask == new_entry->bitmask) { + if (strcmp(u_e->logical_in, new_entry->logical_in) || + strcmp(u_e->logical_out, new_entry->logical_out)) + continue; if (new_entry->bitmask & EBT_SOURCEMAC && - strcmp(u_e->sourcemac, new_entry->sourcemac)) + memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN)) continue; if (new_entry->bitmask & EBT_DESTMAC && - strcmp(u_e->destmac, new_entry->destmac)) + memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN)) continue; if (new_entry->bitmask != u_e->bitmask || new_entry->invflags != u_e->invflags) @@ -943,18 +1114,18 @@ static void add_rule(int rule_nr) unsigned short *cnt; struct ebt_u_match_list *m_l; struct ebt_u_watcher_list *w_l; + struct ebt_u_entries *entries = to_chain(), *entries2; if (rule_nr != -1) { // command -I - if (--rule_nr > - replace.hook_entry[replace.selected_hook]->nentries) + if (--rule_nr > entries->nentries) print_error("rule nr too high: %d > %d", rule_nr, - replace.hook_entry[replace.selected_hook]->nentries); + entries->nentries); } else - rule_nr = replace.hook_entry[replace.selected_hook]->nentries; + rule_nr = entries->nentries; // we're adding one rule replace.num_counters = replace.nentries; replace.nentries++; - replace.hook_entry[replace.selected_hook]->nentries++; + entries->nentries++; // handle counter stuff // +1 for CNT_END @@ -963,9 +1134,10 @@ static void add_rule(int rule_nr) print_memory(); cnt = counterchanges; for (i = 0; i < replace.selected_hook; i++) { - if (!(replace.valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace.valid_hooks & (1 << i))) continue; - for (j = 0; j < replace.hook_entry[i]->nentries; j++) { + entries2 = nr_to_chain(i); + for (j = 0; j < entries2->nentries; j++) { *cnt = CNT_NORM; cnt++; } @@ -984,7 +1156,7 @@ static void add_rule(int rule_nr) // go to the right position in the chain u_e2 = NULL; - u_e = replace.hook_entry[replace.selected_hook]->entries; + u_e = entries->entries; for (i = 0; i < rule_nr; i++) { u_e2 = u_e; u_e = u_e->next; @@ -993,7 +1165,7 @@ static void add_rule(int rule_nr) if (u_e2) u_e2->next = new_entry; else - replace.hook_entry[replace.selected_hook]->entries = new_entry; + entries->entries = new_entry; new_entry->next = u_e; // put the ebt_[match, watcher, target] pointers in place @@ -1008,6 +1180,20 @@ static void add_rule(int rule_nr) w_l = w_l->next; } new_entry->t = ((struct ebt_u_target *)new_entry->t)->t; + + // update the counter_offset of chains behind this one + i = replace.selected_hook; + while (1) { + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) + continue; + else + break; + } else + entries->counter_offset++; + } } // execute command D @@ -1016,9 +1202,10 @@ static void delete_rule(int rule_nr) int i, j, lentmp = 0; unsigned short *cnt; struct ebt_u_entry *u_e, *u_e2; + struct ebt_u_entries *entries = to_chain(), *entries2; if ( (i = check_rule_exists(rule_nr)) == -1 ) - print_error("Sorry, rule does not exists"); + print_error("Sorry, rule does not exist"); // we're deleting a rule replace.num_counters = replace.nentries; @@ -1026,9 +1213,11 @@ static void delete_rule(int rule_nr) if (replace.nentries) { for (j = 0; j < replace.selected_hook; j++) { - if (!(replace.valid_hooks & (1 << j))) + if (j < NF_BR_NUMHOOKS && + !(replace.valid_hooks & (1 << j))) continue; - lentmp += replace.hook_entry[j]->nentries; + entries2 = nr_to_chain(j); + lentmp += entries2->nentries; } lentmp += i; // +1 for CNT_END @@ -1053,7 +1242,7 @@ static void delete_rule(int rule_nr) // go to the right position in the chain u_e2 = NULL; - u_e = replace.hook_entry[replace.selected_hook]->entries; + u_e = entries->entries; for (j = 0; j < i; j++) { u_e2 = u_e; u_e = u_e->next; @@ -1063,12 +1252,25 @@ static void delete_rule(int rule_nr) if (u_e2) u_e2->next = u_e->next; else - replace.hook_entry[replace.selected_hook]->entries = u_e->next; + entries->entries = u_e->next; - replace.hook_entry[replace.selected_hook]->nentries--; + entries->nentries--; // free everything free_u_entry(u_e); free(u_e); + // update the counter_offset of chains behind this one + i = replace.selected_hook; + while (1) { + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) + continue; + else + break; + } else + entries->counter_offset--; + } } // execute command Z @@ -1084,8 +1286,9 @@ void zero_counters(int zerochain) } else { int i, j; unsigned short *cnt; + struct ebt_u_entries *entries = nr_to_chain(zerochain), *e2; - if (replace.hook_entry[zerochain]->nentries == 0) + if (entries->nentries == 0) exit(0); counterchanges = (unsigned short *) malloc((replace.nentries + 1) * sizeof(unsigned short)); @@ -1093,14 +1296,16 @@ void zero_counters(int zerochain) print_memory(); cnt = counterchanges; for (i = 0; i < zerochain; i++) { - if (!(replace.valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && + !(replace.valid_hooks & (1 << i))) continue; - for (j = 0; j < replace.hook_entry[i]->nentries; j++) { + e2 = nr_to_chain(i); + for (j = 0; j < e2->nentries; j++) { *cnt = CNT_NORM; cnt++; } } - for (i = 0; i < replace.hook_entry[zerochain]->nentries; i++) { + for (i = 0; i < entries->nentries; i++) { *cnt = CNT_ZERO; cnt++; } @@ -1278,6 +1483,7 @@ int main(int argc, char *argv[]) struct ebt_u_watcher *w; struct ebt_u_match_list *m_l; struct ebt_u_watcher_list *w_l; + struct ebt_u_entries *entries; const char *modprobe = NULL; // initialize the table name, OPT_ flags, selected hook and command @@ -1292,6 +1498,9 @@ int main(int argc, char *argv[]) // put some sane values in our new entry initialize_entry(new_entry); + // The scenario induced by this loop makes that: + // '-t' and '-M' (if specified) have to come before '-A' and the like + // getopt saves the day while ((c = getopt_long(argc, argv, "-A:D:I:L::Z::F::P:Vhi:o:j:p:b:s:d:t:M:", ebt_options, NULL)) != -1) { @@ -1305,6 +1514,16 @@ int main(int argc, char *argv[]) if (replace.flags & OPT_COMMAND) print_error("Multiple commands not allowed"); replace.flags |= OPT_COMMAND; + if ( !(table = find_table(replace.name)) ) + print_error("Bad table name"); + // get the kernel's information + if (get_table(&replace)) { + ebtables_insmod("ebtables", modprobe); + if (get_table(&replace)) + print_error("can't initialize ebtables " + "table %s", replace.name); + } + // here we already need the kernel table if ((replace.selected_hook = get_hooknr(optarg)) == -1) print_error("Bad chain"); if (c == 'D' && optind < argc && @@ -1318,10 +1537,10 @@ int main(int argc, char *argv[]) if (c == 'P') { if (optind >= argc) print_error("No policy specified"); - for (i = 0; i < 2; i++) + for (i = 0; i < 4; i++) if (!strcmp(argv[optind], standard_targets[i])) { - policy = i; + policy = -i -1; break; } if (policy == -1) @@ -1360,6 +1579,15 @@ int main(int argc, char *argv[]) replace.flags |= OPT_COMMAND; } i = -1; + if ( !(table = find_table(replace.name)) ) + print_error("Bad table name"); + // get the kernel's information + if (get_table(&replace)) { + ebtables_insmod("ebtables", modprobe); + if (get_table(&replace)) + print_error("can't initialize ebtables " + "table %s", replace.name); + } if (optarg) { if ( (i = get_hooknr(optarg)) == -1 ) print_error("Bad chain"); @@ -1386,6 +1614,8 @@ int main(int argc, char *argv[]) exit(0); case 'M': // modprobe + if (replace.command != 'h') + print_error("Please put the -M option earlier"); modprobe = optarg; break; @@ -1419,6 +1649,8 @@ int main(int argc, char *argv[]) break; case 't': // table + if (replace.command != 'h') + print_error("Please put the -t option first"); check_option(&replace.flags, OPT_TABLE); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN) print_error("Table name too long"); @@ -1522,9 +1754,14 @@ int main(int argc, char *argv[]) t = find_target( EBT_STANDARD_TARGET); ((struct ebt_standard_target *) - t->t)->verdict = i; + t->t)->verdict = -i - 1; break; } + if (-i - 1 == EBT_RETURN) { + if (replace.selected_hook < NF_BR_NUMHOOKS) + print_error("Return target" + " only for user defined chains"); + } // must be an extension then if (i == NUM_STANDARD_TARGETS) { struct ebt_u_target *t; @@ -1626,6 +1863,9 @@ int main(int argc, char *argv[]) if (w == NULL) print_error("Unknown argument"); + if (replace.command != 'A' && replace.command != 'I' && + replace.command != 'D') + print_error("extensions only for -A, -I and -D"); if (w->used == 0) add_watcher(w); } @@ -1647,46 +1887,39 @@ int main(int argc, char *argv[]) print_error("Not enough information"); } - if ( !(table = find_table(replace.name)) ) - print_error("Bad table name"); - // do this after parsing everything, so we can print specific info if (replace.command == 'h' && !(replace.flags & OPT_ZERO)) print_help(); // do the final checks - m_l = new_entry->m_list; - w_l = new_entry->w_list; - t = (struct ebt_u_target *)new_entry->t; - while (m_l) { - m = (struct ebt_u_match *)(m_l->m); - m->final_check(new_entry, m->m, replace.name, - replace.selected_hook); - m_l = m_l->next; - } - while (w_l) { - w = (struct ebt_u_watcher *)(w_l->w); - w->final_check(new_entry, w->w, replace.name, - replace.selected_hook); - w_l = w_l->next; + if (replace.command == 'A' || replace.command == 'I' || + replace.command == 'D') { + // this will put the hook_mask right for the chains + check_for_loops(); + entries = to_chain(); + m_l = new_entry->m_list; + w_l = new_entry->w_list; + t = (struct ebt_u_target *)new_entry->t; + while (m_l) { + m = (struct ebt_u_match *)(m_l->m); + m->final_check(new_entry, m->m, replace.name, + entries->hook_mask); + m_l = m_l->next; + } + while (w_l) { + w = (struct ebt_u_watcher *)(w_l->w); + w->final_check(new_entry, w->w, replace.name, + entries->hook_mask); + w_l = w_l->next; + } + t->final_check(new_entry, t->t, replace.name, + entries->hook_mask); } - t->final_check(new_entry, t->t, replace.name, replace.selected_hook); // so, the extensions can work with the host endian // the kernel does not have to do this ofcourse new_entry->ethproto = htons(new_entry->ethproto); - // get the kernel's information - if (get_table(&replace)) { - ebtables_insmod("ebtables", modprobe); - if (get_table(&replace)) - print_error("can't initialize ebtables table %s", - replace.name); - } - // check if selected_hook is a valid_hook - if (replace.selected_hook >= 0 && - !(replace.valid_hooks & (1 << replace.selected_hook))) - print_error("Bad chain name"); if (replace.command == 'P') change_policy(policy); else if (replace.command == 'L') { @@ -1712,5 +1945,6 @@ int main(int argc, char *argv[]) if (counterchanges) deliver_counters(&replace, counterchanges); +// list_rules(); return 0; } -- cgit v1.2.3