--- ebtables-v2.0pre7/Makefile Thu Jun 6 19:18:29 2002 +++ ebtables-v2.0pre8.001/Makefile Thu Jun 27 18:53:55 2002 @@ -2,7 +2,7 @@ KERNEL_DIR?=/usr/src/linux PROGNAME:=ebtables -PROGVERSION:="2.0pre7 (June 2002)" +PROGVERSION:="2.0pre8 (June 2002)" MANDIR?=/usr/local/man CFLAGS:=-Wall -Wunused --- ebtables-v2.0pre7/ebtables.c Wed Jun 5 21:42:17 2002 +++ ebtables-v2.0pre8.001/ebtables.c Thu Jun 27 18:53:55 2002 @@ -34,17 +34,25 @@ #include #include #include "include/ebtables_u.h" +#include +#include +#include // here are the number-name correspondences kept for the ethernet // frame type field #define PROTOCOLFILE "/etc/ethertypes" -#define DATABASEHOOKNR NF_BR_NUMHOOKS +#ifndef PROC_SYS_MODPROBE +#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" +#endif + +#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", @@ -79,6 +87,10 @@ { "destination" , required_argument, 0, 'd' }, { "dst" , required_argument, 0, 'd' }, { "table" , required_argument, 0, 't' }, + { "modprobe" , required_argument, 0, 'M' }, + { "new-chain" , required_argument, 0, 'N' }, + { "rename-chain" , required_argument, 0, 'E' }, + { "delete-chain" , required_argument, 0, 'X' }, { 0 } }; @@ -89,10 +101,11 @@ "ACCEPT", "DROP", "CONTINUE", + "RETURN", }; -unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; -unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; +unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; +unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; @@ -326,10 +339,74 @@ tables = t; } -// used to parse /etc/etherproto +// blatently stolen (again) from iptables.c userspace program +// find out where the modprobe utility is located +static char *get_modprobe(void) +{ + int procfile; + char *ret; + + procfile = open(PROC_SYS_MODPROBE, O_RDONLY); + if (procfile < 0) + return NULL; + + ret = malloc(1024); + if (ret) { + switch (read(procfile, ret, 1024)) { + case -1: goto fail; + case 1024: goto fail; /* Partial read. Wierd */ + } + if (ret[strlen(ret)-1]=='\n') + ret[strlen(ret)-1]=0; + close(procfile); + return ret; + } + fail: + free(ret); + close(procfile); + return NULL; +} + +// I hate stealing, really... Lets call it a tribute. +int ebtables_insmod(const char *modname, const char *modprobe) +{ + char *buf = NULL; + char *argv[3]; + + // If they don't explicitly set it, read out of kernel + if (!modprobe) { + buf = get_modprobe(); + if (!buf) + return -1; + modprobe = buf; + } + + switch (fork()) { + case 0: + argv[0] = (char *)modprobe; + argv[1] = (char *)modname; + argv[2] = NULL; + execv(argv[0], argv); + + /* not usually reached */ + exit(0); + case -1: + return -1; + + default: /* parent */ + wait(NULL); + } + + free(buf); + return 0; +} + + +// used to parse /etc/ethertypes int disregard_whitespace(char *buffer, FILE *ifp) { int hlp; + buffer[0] = '\t'; while (buffer[0] == '\t' || buffer[0] == '\n' || buffer[0] == ' ') { hlp = fscanf(ifp, "%c", buffer); @@ -338,10 +415,11 @@ return 0; } -// used to parse /etc/etherproto +// used to parse /etc/ethertypes int disregard_tabspace(char *buffer, FILE *ifp) { int hlp; + buffer[0] = '\t'; while (buffer[0] == '\t' || buffer[0] == ' ') { hlp = fscanf(ifp, "%c", buffer); @@ -356,9 +434,10 @@ int i, hlp; char anotherhlp; - /* discard comment lines && whitespace*/ + // discard comment lines and whitespace while (1) { - if (disregard_whitespace(buffer, ifp)) return -1; + if (disregard_whitespace(buffer, ifp)) + return -1; if (buffer[0] == '#') while (1) { hlp = fscanf(ifp, "%c", &anotherhlp); @@ -367,17 +446,20 @@ if (anotherhlp == '\n') break; } - else break; + else + break; } // buffer[0] already contains the first letter for (i = 1; i < 21; i++) { hlp = fscanf(ifp, "%c", buffer + i); - if (hlp == EOF || hlp == 0) return -1; + if (hlp == EOF || hlp == 0) + return -1; if (buffer[i] == '\t' || buffer[i] == ' ') break; } - if (i == 21) return -1; + if (i == 21) + return -1; buffer[i] = '\0'; if (disregard_tabspace(value, ifp)) return -1; @@ -401,7 +483,8 @@ return 0; } -// helper function for list_em() +// translate a hexadecimal number to a protocol name, parsing /etc/ethertypes +// returns 0 on success int number_to_name(unsigned short proto, char *name) { FILE *ifp; @@ -425,7 +508,7 @@ } // 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; @@ -436,20 +519,21 @@ 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; - while (i >9) { + 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. + j = i + 1; while (j > 9) { digits++; j /= 10; @@ -461,22 +545,22 @@ // 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, "); + 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) && @@ -502,12 +586,12 @@ 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) && @@ -533,27 +617,31 @@ 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; @@ -573,30 +661,154 @@ w_l = w_l->next; } - printf("target: "); + printf("-j "); + if (strcmp(hlp->t->u.name, EBT_STANDARD_TARGET)) + printf("%s ", hlp->t->u.name); 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; } } +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; + i--; + } + 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(); + } + + // check for loops, starting from every base chain + 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; + entries2 = nr_to_chain(verdict + NF_BR_NUMHOOKS); + 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 + NF_BR_NUMHOOKS) + print_error("Loop from chain %s to chain %s", + nr_to_chain(chain_nr)->name, nr_to_chain(stack[k].chain_nr)->name); + // 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; + sp++; + j = -1; + e = entries2->entries; + chain_nr = verdict + NF_BR_NUMHOOKS; + entries = entries2; + continue; +letscontinue: + e = e->next; + } + // we are at the end of a standard chain + if (sp == 0) + continue; + // go back to the chain one level higher + sp--; + j = stack[sp].n; + chain_nr = stack[sp].chain_nr; + e = stack[sp].e; + entries = stack[sp].entries; + goto letscontinue; + } + free(stack); + return; +} + // parse the chain name and return the corresponding nr +// returns -1 on failure 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; } @@ -623,6 +835,9 @@ "--flush -F [chain] : Delete all rules in chain or in all chains\n" "--zero -Z [chain] : Put counters on zero in chain or in all chains\n" "--policy -P chain target : Change policy on chain to target\n" +"--new-chain -N chain : Create a user defined chain\n" +"--rename-chain -E old new : Rename a chain\n" +"--delete-chain -X chain : Delete a user defined chain\n" "Options:\n" "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n" "--src -s [!] address[/mask]: source mac address\n" @@ -631,6 +846,7 @@ "--out-if -o [!] name : network output interface name\n" "--logical-in [!] name : logical bridge input interface name\n" "--logical-out [!] name : logical bridge output interface name\n" +"--modprobe -M : try to insert modules using this command\n" "--version -V : print package version\n" "\n" , prog_name, @@ -661,22 +877,37 @@ 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); - return; + 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; + } + } + } } // execute command P 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 @@ -696,76 +927,105 @@ } // flush one chain or the complete table -static void flush_chains() +// -1 == nothing to do +// 0 == give back to kernel +static int 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); + return -1; 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; + return 0; } - if (replace.hook_entry[replace.selected_hook]->nentries == 0) - exit(0); + if (entries->nentries == 0) + return -1; 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; + cnt = counterchanges; + 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) - *cnt = CNT_NORM; - else + 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_DEL; + else + *cnt = CNT_NORM; 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; + return 0; +} // -1 == no match static int check_rule_exists(int rule_nr) @@ -776,32 +1036,33 @@ 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) - return 0; + if (rule_nr > entries->nentries) + return -1; // 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) { + && !strcmp(u_e->out, new_entry->out)) { + 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) @@ -863,7 +1124,7 @@ return -1; } -// execute command A +// execute command A or I static void add_rule(int rule_nr) { int i, j; @@ -871,18 +1132,18 @@ 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) - print_error("rule nr too high: %d > %d", rule_nr, - replace.hook_entry[replace.selected_hook]->nentries); + if (--rule_nr > entries->nentries) + print_error("rule nr too high: %d > %d", rule_nr + 1, + entries->nentries + 1); } 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 @@ -891,9 +1152,10 @@ 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++; } @@ -912,7 +1174,7 @@ // 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; @@ -921,7 +1183,7 @@ 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 @@ -936,6 +1198,20 @@ 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 @@ -944,9 +1220,10 @@ 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; @@ -954,9 +1231,11 @@ 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 @@ -981,7 +1260,7 @@ // 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; @@ -991,12 +1270,25 @@ 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 @@ -1005,15 +1297,16 @@ if (zerochain == -1) { // tell main() we don't update the counters - // this results in tricking the kernel to zero his counters, + // this results in tricking the kernel to zero its counters, // naively expecting userspace to update its counters. Muahahaha counterchanges = NULL; replace.num_counters = 0; } 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)); @@ -1021,14 +1314,16 @@ 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++; } @@ -1100,15 +1395,17 @@ exit(0); } -// set ethproto -int name_to_protocol(char *name) +// 0 == success +// 1 == success, but for the special 'protocol' LENGTH +// -1 == failure +int name_to_number(char *name, __u16 *proto) { FILE *ifp; char buffer[21], value[5], *bfr; unsigned short i; if (!strcasecmp("LENGTH", name)) { - new_entry->ethproto = 0; + *proto = 0; new_entry->bitmask |= EBT_802_3; return 1; } @@ -1121,7 +1418,7 @@ i = (unsigned short) strtol(value, &bfr, 16); if (*bfr != '\0') return -1; - new_entry->ethproto = i; + *proto = i; fclose(ifp); return 0; } @@ -1165,6 +1462,66 @@ return 0; } +// executes the final_check() function for all extensions used by the rule +void do_final_checks(struct ebt_u_entry *e, struct ebt_u_entries *entries) +{ + struct ebt_u_match_list *m_l; + struct ebt_u_watcher_list *w_l; + struct ebt_u_target *t; + struct ebt_u_match *m; + struct ebt_u_watcher *w; + + m_l = e->m_list; + w_l = e->w_list; + while (m_l) { + m = find_match(m_l->m->u.name); + m->final_check(e, m_l->m, replace.name, + entries->hook_mask, 1); + m_l = m_l->next; + } + while (w_l) { + w = find_watcher(w_l->w->u.name); + w->final_check(e, w_l->w, replace.name, + entries->hook_mask, 1); + w_l = w_l->next; + } + t = find_target(e->t->u.name); + t->final_check(e, e->t, replace.name, + entries->hook_mask, 1); +} + +// used for the -X command +void check_for_references(int chain_nr) +{ + int i = -1, j; + struct ebt_u_entries *entries; + struct ebt_u_entry *e; + + while (1) { + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) + continue; + else + break; + } + e = entries->entries; + j = 0; + while (e) { + j++; + if (strcmp(e->t->u.name, EBT_STANDARD_TARGET)) { + e = e->next; + continue; + } + if (((struct ebt_standard_target *)e->t)->verdict == chain_nr) + print_error("Can't delete the chain, it's referenced " + "in chain %s, rule %d", entries->name, j); + e = e->next; + } + } +} + int check_inverse(const char option[]) { if (strcmp(option, "!") == 0) { @@ -1199,13 +1556,15 @@ int c, i; // this special one for the -Z option (we can have -Z -L ) int zerochain = -1; - int policy = -1; + int policy = 0; int rule_nr = -1;// used for -D chain number struct ebt_u_target *t; struct ebt_u_match *m; 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 strcpy(replace.name, "filter"); @@ -1219,21 +1578,113 @@ // 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:", ebt_options, NULL)) != -1) { + "-A:D:I:N:E:X:L::Z::F::P:Vhi:o:j:p:b:s:d:t:M:", ebt_options, NULL)) != -1) { switch (c) { case 'A': // add a rule case 'D': // delete a rule case 'P': // define policy case 'I': // insert a rule + case 'N': // make a user defined chain + case 'E': // rename chain + case 'X': // delete chain replace.command = c; 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); + } + if (optarg[0] == '-') + print_error("No chain name specified"); + if (c == 'N') { + struct ebt_u_chain_list *cl, **cl2; + + if (get_hooknr(optarg) != -1) + print_error("Chain %s already exists", + optarg); + if (find_target(optarg)) + print_error("Target with name %s exists" + , optarg); + if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) + print_error("Chain name length can't exceed %d", + EBT_CHAIN_MAXNAMELEN - 1); + cl = (struct ebt_u_chain_list *) + malloc(sizeof(struct ebt_u_chain_list)); + if (!cl) + print_memory(); + cl->next = NULL; + cl->udc = (struct ebt_u_entries *) + malloc(sizeof(struct ebt_u_entries)); + if (!cl->udc) + print_memory(); + cl->udc->nentries = 0; + cl->udc->policy = EBT_ACCEPT; + cl->udc->counter_offset = replace.nentries; + cl->udc->hook_mask = 0; + strcpy(cl->udc->name, optarg); + cl->udc->entries = NULL; + cl->kernel_start = NULL; + // put the new chain at the end + cl2 = &replace.udc; + while (*cl2) + cl2 = &((*cl2)->next); + *cl2 = cl; + break; + } if ((replace.selected_hook = get_hooknr(optarg)) == -1) - print_error("Bad chain"); + print_error("Chain %s doesn't exist", optarg); + if (c == 'E') { + if (optind >= argc || argv[optind][0] == '-') + print_error("No new chain name specified"); + if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN) + print_error("Chain name len can't exceed %d", + EBT_CHAIN_MAXNAMELEN - 1); + if (get_hooknr(argv[optind]) != -1) + print_error("Chain %s already exists", + argv[optind]); + entries = to_chain(); + strcpy(entries->name, argv[optind]); + optind++; + break; + } + if (c == 'X') { + struct ebt_u_chain_list *cl, **cl2; + + if (replace.selected_hook < NF_BR_NUMHOOKS) + print_error("You can't remove a standard chain"); + // if the chain is referenced, don't delete it + check_for_references(replace.selected_hook - NF_BR_NUMHOOKS); + flush_chains(); + entries = to_chain(); + if (replace.udc->udc == entries) { + cl = replace.udc; + replace.udc = replace.udc->next; + free(cl->udc); + free(cl); + break; + } + cl2 = &(replace.udc); + while ((*cl2)->next->udc != entries) + cl2 = &((*cl2)->next); + cl = (*cl2)->next; + (*cl2)->next = (*cl2)->next->next; + free(cl->udc); + free(cl); + break; + } + if (c == 'D' && optind < argc && argv[optind][0] != '-') { rule_nr = strtol(argv[optind], &buffer, 10); @@ -1245,13 +1696,16 @@ if (c == 'P') { if (optind >= argc) print_error("No policy specified"); - for (i = 0; i < 2; i++) + policy = 0; + for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], standard_targets[i])) { - policy = i; + policy = -i -1; + if (policy == EBT_CONTINUE) + policy = 0; break; } - if (policy == -1) + if (policy == 0) print_error("Wrong policy"); optind++; } @@ -1286,6 +1740,15 @@ " 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); + } i = -1; if (optarg) { if ( (i = get_hooknr(optarg)) == -1 ) @@ -1312,6 +1775,12 @@ printf("%s, %s\n", prog_name, prog_version); exit(0); + case 'M': // modprobe + if (replace.command != 'h') + print_error("Please put the -M option earlier"); + modprobe = optarg; + break; + case 'h': // help if (replace.flags & OPT_COMMAND) print_error("Multiple commands not allowed"); @@ -1342,8 +1811,10 @@ 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) + if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) print_error("Table name too long"); strcpy(replace.name, optarg); break; @@ -1375,7 +1846,7 @@ print_error("No in-interface " "specified"); if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_error("Illegal interfacelength"); + print_error("Illegal interface length"); strcpy(new_entry->in, argv[optind - 1]); break; } @@ -1393,7 +1864,7 @@ print_error("No logical in-interface " "specified"); if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_error("Illegal interfacelength"); + print_error("Illegal interface length"); strcpy(new_entry->logical_in, argv[optind - 1]); break; } @@ -1437,7 +1908,6 @@ break; } if (c == 'j') { - check_option(&replace.flags, OPT_JUMP); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, @@ -1445,12 +1915,30 @@ t = find_target( EBT_STANDARD_TARGET); ((struct ebt_standard_target *) - t->t)->verdict = i; + t->t)->verdict = -i - 1; break; } - // must be an extension then - if (i == NUM_STANDARD_TARGETS) { + if (-i - 1 == EBT_RETURN) { + if (replace.selected_hook < NF_BR_NUMHOOKS) + print_error("Return target" + " only for user defined chains"); + } + if (i != NUM_STANDARD_TARGETS) + break; + if ((i = get_hooknr(optarg)) != -1) { + if (i < NF_BR_NUMHOOKS) + print_error("don't jump" + " to a standard chain"); + t = find_target( + EBT_STANDARD_TARGET); + ((struct ebt_standard_target *) + t->t)->verdict = i - NF_BR_NUMHOOKS; + break; + } + else { + // must be an extension then struct ebt_u_target *t; + t = find_target(optarg); // -j standard not allowed either if (!t || t == @@ -1504,10 +1992,14 @@ print_error("Problem with the specified " "protocol"); new_entry->ethproto = i; - if (*buffer != '\0') - if (name_to_protocol(argv[optind - 1]) == -1) + if (*buffer != '\0') { + if ((i = name_to_number(argv[optind - 1], + &new_entry->ethproto)) == -1) print_error("Problem with the specified" " protocol"); + if (i == 1) + new_entry->bitmask |= EBT_802_3; + } if (new_entry->ethproto < 1536 && !(new_entry->bitmask & EBT_802_3)) print_error("Sorry, protocols have values above" @@ -1527,7 +2019,7 @@ t = (struct ebt_u_target *)new_entry->t; if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) - continue; + goto check_extension; // is it a match_option? for (m = matches; m; m = m->next) @@ -1538,7 +2030,7 @@ if (m != NULL) { if (m->used == 0) add_match(m); - continue; + goto check_extension; } // is it a watcher option? @@ -1551,9 +2043,15 @@ print_error("Unknown argument"); if (w->used == 0) add_watcher(w); +check_extension: + if (replace.command != 'A' && replace.command != 'I' && + replace.command != 'D') + print_error("extensions only for -A, -I and -D"); } } + if ( !table && !(table = find_table(replace.name)) ) + print_error("Bad table name"); // database stuff before ebtables stuff if (replace.command == 'b') allowdb(allowbc); @@ -1570,41 +2068,38 @@ 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, 0); + 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, 0); + w_l = w_l->next; + } + t->final_check(new_entry, t->t, replace.name, + entries->hook_mask, 0); } - 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 - get_table(&replace); - // 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') { @@ -1616,12 +2111,38 @@ } if (replace.flags & OPT_ZERO) zero_counters(zerochain); - else if (replace.command == 'F') - flush_chains(); - else if (replace.command == 'A' || replace.command == 'I') + else if (replace.command == 'F') { + if (flush_chains() == -1) + exit(0); + } else if (replace.command == 'A' || replace.command == 'I') { add_rule(rule_nr); - else if (replace.command == 'D') + check_for_loops(); + // do the final_check(), for all entries + // needed when adding a rule that has a chain target + i = -1; + while (1) { + struct ebt_u_entry *e; + + i++; + entries = nr_to_chain(i); + if (!entries) { + if (i < NF_BR_NUMHOOKS) + continue; + else + break; + } + e = entries->entries; + while (e) { + // userspace extensions use host endian + e->ethproto = ntohs(e->ethproto); + do_final_checks(e, entries); + e->ethproto = htons(e->ethproto); + e = e->next; + } + } + } else if (replace.command == 'D') delete_rule(rule_nr); + // commands -N, -E, -X fall through if (table->check) table->check(&replace); --- ebtables-v2.0pre7/communication.c Wed Jun 5 20:17:25 2002 +++ ebtables-v2.0pre8.001/communication.c Thu Jun 27 18:53:55 2002 @@ -42,9 +42,11 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 + NF_BR_NUMHOOKS]; + } 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 @@ 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 @@ "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,33 +410,82 @@ } 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 -void get_table(struct ebt_u_replace *u_repl) +int get_table(struct ebt_u_replace *u_repl) { int i, j, k, hook; socklen_t optlen; @@ -380,9 +497,7 @@ optlen = sizeof(struct ebt_replace); strcpy(repl.name, u_repl->name); if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen)) - print_error("The %s table is not supported by the kernel," - " consider recompiling your kernel or try insmod ebt_%s", - repl.name, repl.name); + return -1; if ( !(repl.entries = (char *) malloc(repl.entries_size)) ) print_memory(); @@ -407,17 +522,20 @@ 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; } void get_dbinfo(struct brdb_dbinfo *nr) @@ -425,7 +543,7 @@ socklen_t optlen = sizeof(struct brdb_dbinfo); get_sockfd(); - + if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen)) print_error("Sorry, br_db code probably not in kernel, " "try insmod br_db"); --- ebtables-v2.0pre7/extensions/ebt_redirect.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_redirect.c Thu Jun 27 18:53:55 2002 @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "../include/ebtables_u.h" #include @@ -33,7 +32,6 @@ return; } - #define OPT_REDIRECT_TARGET 0x01 static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, @@ -48,7 +46,7 @@ check_option(flags, OPT_REDIRECT_TARGET); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, standard_targets[i])) { - redirectinfo->target = i; + redirectinfo->target = -i - 1; break; } if (i == NUM_STANDARD_TARGETS) @@ -61,10 +59,11 @@ } static void final_check(const struct ebt_u_entry *entry, - const struct ebt_entry_target *target, const char *name, unsigned int hook) + const struct ebt_entry_target *target, const char *name, + unsigned int hook_mask, unsigned int time) { - if ( (hook != NF_BR_PRE_ROUTING || strcmp(name, "nat")) && - (hook != NF_BR_BROUTING || strcmp(name, "broute")) ) + if ( ((hook_mask & ~(1 << NF_BR_PRE_ROUTING)) || strcmp(name, "nat")) && + ((hook_mask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute")) ) print_error("Wrong chain for redirect"); } @@ -74,8 +73,10 @@ struct ebt_redirect_info *redirectinfo = (struct ebt_redirect_info *)target->data; - printf("redirect"); - printf(" --redirect-target %s", standard_targets[redirectinfo->target]); + if (redirectinfo->target == EBT_ACCEPT) + return; + printf(" --redirect-target %s", + standard_targets[-redirectinfo->target - 1]); } static int compare(const struct ebt_entry_target *t1, --- ebtables-v2.0pre7/extensions/ebt_nat.c Wed Jun 5 21:43:11 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_nat.c Thu Jun 27 18:53:55 2002 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "../include/ebtables_u.h" #include @@ -89,7 +88,7 @@ check_option(flags, OPT_SNAT_TARGET); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, standard_targets[i])) { - natinfo->target = i; + natinfo->target = -i - 1; break; } if (i == NUM_STANDARD_TARGETS) @@ -124,7 +123,7 @@ check_option(flags, OPT_DNAT_TARGET); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, standard_targets[i])) { - natinfo->target = i; + natinfo->target = -i - 1; break; } if (i == NUM_STANDARD_TARGETS) @@ -137,22 +136,24 @@ } static void final_check_s(const struct ebt_u_entry *entry, - const struct ebt_entry_target *target, const char *name, unsigned int hook) + const struct ebt_entry_target *target, const char *name, + unsigned int hook_mask, unsigned int time) { - if (hook != NF_BR_POST_ROUTING || strcmp(name, "nat")) + if (!(hook_mask & (1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat")) print_error("Wrong chain for snat"); - if (to_source_supplied == 0) + if (time == 0 && to_source_supplied == 0) print_error("No snat address supplied"); } static void final_check_d(const struct ebt_u_entry *entry, - const struct ebt_entry_target *target, const char *name, unsigned int hook) + const struct ebt_entry_target *target, const char *name, + unsigned int hook_mask, unsigned int time) { - if ( ((hook != NF_BR_PRE_ROUTING && hook != NF_BR_LOCAL_OUT) || + if (((hook_mask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT))) || strcmp(name, "nat")) && - (hook != NF_BR_BROUTING || strcmp(name, "broute")) ) + ((hook_mask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute"))) print_error("Wrong chain for dnat"); - if (to_dest_supplied == 0) + if (time == 0 && to_dest_supplied == 0) print_error("No dnat address supplied"); } @@ -161,9 +162,9 @@ { struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; - printf("snat - to: "); + printf("--to-src "); printf("%s", ether_ntoa((struct ether_addr *)natinfo->mac)); - printf(" --snat-target %s", standard_targets[natinfo->target]); + printf(" --snat-target %s", standard_targets[-natinfo->target - 1]); } static void print_d(const struct ebt_u_entry *entry, @@ -171,9 +172,9 @@ { struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; - printf("dnat - to: "); + printf("--to-dst "); printf("%s", ether_ntoa((struct ether_addr *)natinfo->mac)); - printf(" --dnat-target %s", standard_targets[natinfo->target]); + printf(" --dnat-target %s", standard_targets[-natinfo->target - 1]); } static int compare(const struct ebt_entry_target *t1, --- ebtables-v2.0pre7/extensions/ebt_ip.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_ip.c Thu Jun 27 18:53:55 2002 @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "../include/ebtables_u.h" #include @@ -156,7 +155,7 @@ unsigned int *flags, struct ebt_entry_match **match) { struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data; - char *end, *buffer; + char *end; int i; switch (c) { @@ -194,7 +193,7 @@ if (optind > argc) print_error("Missing ip tos argument"); i = strtol(argv[optind - 1], &end, 16); - if (i < 0 || i > 255 || *buffer != '\0') + if (i < 0 || i > 255 || *end != '\0') print_error("Problem with specified ip tos"); ipinfo->tos = i; ipinfo->bitmask |= EBT_IP_TOS; @@ -219,7 +218,8 @@ } static void final_check(const struct ebt_u_entry *entry, - const struct ebt_entry_match *match, const char *name, unsigned int hook) + const struct ebt_entry_match *match, const char *name, + unsigned int hook_mask, unsigned int time) { if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || entry->ethproto != ETH_P_IP) @@ -234,34 +234,34 @@ int j; if (ipinfo->bitmask & EBT_IP_SOURCE) { - printf("source ip: "); + printf("--ip-src "); if (ipinfo->invflags & EBT_IP_SOURCE) printf("! "); for (j = 0; j < 4; j++) printf("%d%s",((unsigned char *)&ipinfo->saddr)[j], (j == 3) ? "" : "."); - printf("%s, ", mask_to_dotted(ipinfo->smsk)); + printf("%s ", mask_to_dotted(ipinfo->smsk)); } if (ipinfo->bitmask & EBT_IP_DEST) { - printf("dest ip: "); + printf("--ip-dst "); if (ipinfo->invflags & EBT_IP_DEST) printf("! "); for (j = 0; j < 4; j++) printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j], (j == 3) ? "" : "."); - printf("%s, ", mask_to_dotted(ipinfo->dmsk)); + printf("%s ", mask_to_dotted(ipinfo->dmsk)); } if (ipinfo->bitmask & EBT_IP_TOS) { - printf("ip TOS: "); + printf("--ip-tos "); if (ipinfo->invflags & EBT_IP_TOS) printf("! "); - printf("0x%02X, ", ipinfo->tos); + printf("0x%02X ", ipinfo->tos); } if (ipinfo->bitmask & EBT_IP_PROTO) { - printf("ip proto: "); + printf("--ip-proto "); if (ipinfo->invflags & EBT_IP_DEST) printf("! "); - printf("%d, ", ipinfo->protocol); + printf("%d ", ipinfo->protocol); } } --- ebtables-v2.0pre7/extensions/ebt_arp.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_arp.c Thu Jun 27 18:53:55 2002 @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "../include/ebtables_u.h" #include @@ -76,9 +75,8 @@ #define OPT_PTYPE 0x04 #define OPT_IP_S 0x08 #define OPT_IP_D 0x10 -static int parse(int c, char **argv, int argc, - const struct ebt_u_entry *entry, unsigned int *flags, - struct ebt_entry_match **match) +static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_match **match) { struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data; int i; @@ -178,7 +176,8 @@ } static void final_check(const struct ebt_u_entry *entry, -const struct ebt_entry_match *match, const char *name, unsigned int hook) + const struct ebt_entry_match *match, const char *name, + unsigned int hook_mask, unsigned int time) { if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 || (entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP)) @@ -195,40 +194,40 @@ int i; if (arpinfo->bitmask & EBT_ARP_OPCODE) { - printf("arp opcode: "); + printf("--arp-op "); if (arpinfo->invflags & EBT_ARP_OPCODE) printf("! "); printf("%d ", ntohs(arpinfo->opcode)); } if (arpinfo->bitmask & EBT_ARP_HTYPE) { - printf("arp htype: "); + printf("--arp-htype "); if (arpinfo->invflags & EBT_ARP_HTYPE) printf("! "); printf("%d ", ntohs(arpinfo->htype)); } if (arpinfo->bitmask & EBT_ARP_PTYPE) { - printf("arp ptype: "); + printf("--arp-ptype "); if (arpinfo->invflags & EBT_ARP_PTYPE) printf("! "); printf("0x%x ", ntohs(arpinfo->ptype)); } if (arpinfo->bitmask & EBT_ARP_SRC_IP) { - printf("arp src IP "); + printf("--arp-ip-src "); if (arpinfo->invflags & EBT_ARP_SRC_IP) printf("! "); for (i = 0; i < 4; i++) printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i], (i == 3) ? "" : "."); - printf("%s, ", mask_to_dotted(arpinfo->smsk)); + printf("%s ", mask_to_dotted(arpinfo->smsk)); } if (arpinfo->bitmask & EBT_ARP_DST_IP) { - printf("arp dst IP "); + printf("--arp-ip-dst "); if (arpinfo->invflags & EBT_ARP_DST_IP) printf("! "); for (i = 0; i < 4; i++) printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i], (i == 3) ? "" : "."); - printf("%s, ", mask_to_dotted(arpinfo->dmsk)); + printf("%s ", mask_to_dotted(arpinfo->dmsk)); } } --- ebtables-v2.0pre7/extensions/ebt_vlan.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_vlan.c Thu Jun 27 18:53:55 2002 @@ -1,44 +1,68 @@ /* - * Summary: ebt_vlan userspace module - * - * Description: 802.1Q Virtual LAN match support module for ebtables project. - * Enable to match 802.1Q VLAN tagged frames by VLAN numeric - * identifier (12-bites field) and frame priority (3-bites field) + * Summary: ebt_vlan - IEEE 802.1Q extension module for userspace + * + * Description: 802.1Q Virtual LAN match support module for ebtables project. + * Enables to match 802.1Q: + * 1) VLAN-tagged frames by VLAN numeric identifier (12 - bits field) + * 2) Priority-tagged frames by user_priority (3 bits field) + * 3) Encapsulated Frame by ethernet protocol type/length * * Authors: * Bart De Schuymer - * Nick Fedchik - * - * May, 2002 + * Nick Fedchik + * June, 2002 + * + * License: GNU GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #include -#include #include #include #include -#include +#include #include #include "../include/ebtables_u.h" #include -#define VLAN_ID '1' -#define VLAN_PRIO '2' - +#define GET_BITMASK(_MASK_) vlaninfo->bitmask & _MASK_ +#define SET_BITMASK(_MASK_) vlaninfo->bitmask |= _MASK_ +#define INV_FLAG(_inv_flag_) (vlaninfo->invflags & _inv_flag_) ? "!" : "" + +#define VLAN_ID 0 +#define VLAN_PRIO 1 +#define VLAN_ENCAP 2 static struct option opts[] = { - {"vlan-id", required_argument, 0, VLAN_ID}, - {"vlan-prio", required_argument, 0, VLAN_PRIO}, - {0} + {"vlan-id", required_argument, NULL, VLAN_ID}, + {"vlan-prio", required_argument, NULL, VLAN_PRIO}, + {"vlan-encap", required_argument, NULL, VLAN_ENCAP}, + {NULL} }; + /* - * Print out help for ebtables -h vlan + * Print out local help by "ebtables -h vlan" */ static void print_help () { - printf ("802.1Q VLAN options:\n" - "--vlan-id [!] id : VLAN ID 1-4095 (integer)\n" - "--vlan-prio [!] prio : VLAN Priority 0-7 (integer)\n"); + printf ("802.1Q VLAN extension options:\n" + "--vlan-id [!]id : VLAN-tagged frame identifier, 0,1-4094 (integer)\n" + "--vlan-prio [!]prio : Priority-tagged frame user_priority, 0-7 (integer)\n" + "--vlan-encap [!]proto : Encapsulated protocol (hexadecimal)\n"); } /* @@ -49,40 +73,58 @@ struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data; /* - * Just clean initial values + * Set initial values */ - vlaninfo->id = 0; + vlaninfo->id = 1; /* Default VID for VLAN-tagged 802.1Q frames */ vlaninfo->prio = 0; + vlaninfo->encap = 0; vlaninfo->invflags = 0; vlaninfo->bitmask = 0; } +/* + * option flags definition + */ #define OPT_VLAN_ID 0x01 #define OPT_VLAN_PRIO 0x02 +#define OPT_VLAN_ENCAP 0x04 + +/* + * Parse passed arguments values (ranges, flags, etc...) + * int c - parameter number from static struct option opts[] + * int argc - total amout of arguments (std argc value) + * + */ static int -parse (int c, char **argv, int argc, - const struct ebt_u_entry *entry, unsigned int *flags, - struct ebt_entry_match **match) +parse (int c, + char **argv, + int argc, + const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_match **match) { struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data; - unsigned short i; + unsigned long i; char *end; - + __u16 encap; switch (c) { case VLAN_ID: + /* + * ebtables.c:check_option(unsigned int *flags, unsigned int mask) + * checking for multiple usage of same option + */ check_option (flags, OPT_VLAN_ID); /* - * Check If we got inversed arg for VID, + * Check If we got inversed arg for vlan-id option, * otherwise unset inversion flag */ if (check_inverse (optarg)) vlaninfo->invflags |= EBT_VLAN_ID; /* - * Check arg value presense + * Check arg value presence */ if (optind > argc) - print_error ("Missing VLAN ID argument\n"); + print_error ("Missing VLAN ID argument value\n"); /* * Convert argv to long int, * set *end to end of argv string, @@ -90,15 +132,19 @@ */ (unsigned short) i = strtol (argv[optind - 1], &end, 10); /* - * Check arg val range + * Check arg val range */ - if (i < 1 || i >= 4096 || *end != '\0') { - i = 0; + if (i > 4094 || *end != '\0') print_error - ("Problem with specified VLAN ID range\n"); - } + ("Specified VLAN ID is out of range (0-4094)\n"); + /* + * Set up parameter value + */ vlaninfo->id = i; - vlaninfo->bitmask|=EBT_VLAN_ID; + /* + * Set up parameter presence flag + */ + SET_BITMASK (EBT_VLAN_ID); break; case VLAN_PRIO: @@ -107,25 +153,58 @@ vlaninfo->invflags |= EBT_VLAN_PRIO; if (optind > argc) print_error - ("Missing VLAN Priority level argument\n"); + ("Missing user_priority argument value\n"); /* * Convert argv to long int, * set *end to end of argv string, * base set 10 for decimal only */ - (unsigned short) i = strtol (argv[optind - 1], &end, 10); + (unsigned char) i = strtol (argv[optind - 1], &end, 10); /* * Check arg val range */ - if (i >= 8 || *end != '\0') { - i = 0; + if (i >= 8 || *end != '\0') print_error - ("Problem with specified VLAN Priority range\n"); - } + ("Specified user_priority is out of range (0-7)\n"); + /* + * Set up parameter value + */ vlaninfo->prio = i; - vlaninfo->bitmask|=EBT_VLAN_PRIO; + /* + * Set up parameter presence flag + */ + SET_BITMASK (EBT_VLAN_PRIO); break; + case VLAN_ENCAP: + check_option (flags, OPT_VLAN_ENCAP); + if (check_inverse (optarg)) + vlaninfo->invflags |= EBT_VLAN_ENCAP; + if (optind > argc) + print_error + ("Missing encapsulated frame type argument value\n"); + /* + * Parameter can be decimal, hexadecimal, or string. + * Check arg val range (still raw area) + */ + (unsigned short) encap = strtol (argv[optind - 1], &end, 16); + if (*end == '\0' && (encap < ETH_ZLEN || encap > 0xFFFF)) + print_error + ("Specified encapsulated frame type is out of range\n"); + if (*end != '\0') + if (name_to_number (argv[optind - 1], &encap) == -1) + print_error + ("Problem with the specified encapsulated" + "protocol\n"); + /* + * Set up parameter value (network notation) + */ + vlaninfo->encap = htons (encap); + /* + * Set up parameter presence flag + */ + SET_BITMASK (EBT_VLAN_ENCAP); + break; default: return 0; } @@ -133,19 +212,31 @@ } /* - * Final check + * Final check - logical conditions */ static void final_check (const struct ebt_u_entry *entry, const struct ebt_entry_match *match, - const char *name, unsigned int hook) + const char *name, unsigned int hook, unsigned int time) { + + struct ebt_vlan_info *vlaninfo = + (struct ebt_vlan_info *) match->data; /* - * Is any proto supplied there? Or specified proto isn't 802.1Q? + * Is any proto param specified there? Or specified proto isn't 802.1Q? */ if (entry->bitmask & EBT_NOPROTO || entry->ethproto != ETH_P_8021Q) print_error - ("For matching 802.1Q VLAN the protocol must be specified as 802_1Q\n"); + ("For use 802.1Q extension the protocol must be specified as 802_1Q\n"); + /* + * Check if specified vlan-id=0 (priority-tagged frame condition) + * when vlan-prio was specified. + */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { + if (vlaninfo->id && GET_BITMASK (EBT_VLAN_ID)) + print_error + ("For use user_priority the specified vlan-id must be 0\n"); + } } /* @@ -158,21 +249,36 @@ struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data; + char ethertype_name[21]; /* * Print VLAN ID if they are specified */ - if (vlaninfo->bitmask & EBT_VLAN_ID) { - printf ("vlan id: %s%d, ", - vlaninfo->invflags & EBT_VLAN_ID ? "!" : "", - vlaninfo->id); + if (GET_BITMASK (EBT_VLAN_ID)) { + printf ("--%s %s%d ", + opts[VLAN_ID].name, + INV_FLAG (EBT_VLAN_ID), vlaninfo->id); } /* - * Print VLAN priority if they are specified + * Print user priority if they are specified */ - if (vlaninfo->bitmask & EBT_VLAN_PRIO) { - printf ("vlan prio: %s%d, ", - vlaninfo->invflags & EBT_VLAN_PRIO ? "!" : "", - vlaninfo->prio); + if (GET_BITMASK (EBT_VLAN_PRIO)) { + printf ("--%s %s%d ", + opts[VLAN_PRIO].name, + INV_FLAG (EBT_VLAN_PRIO), vlaninfo->prio); + } + /* + * Print encapsulated frame type if they are specified + */ + if (GET_BITMASK (EBT_VLAN_ENCAP)) { + printf ("--%s %s", + opts[VLAN_ENCAP].name, INV_FLAG (EBT_VLAN_ENCAP)); + bzero (ethertype_name, 21); + if (!number_to_name + (ntohs (vlaninfo->encap), ethertype_name)) { + printf ("%s ", ethertype_name); + } else { + printf ("%2.4X ", ntohs (vlaninfo->encap)); + } } } @@ -207,6 +313,13 @@ */ if (vlaninfo1->bitmask & EBT_VLAN_PRIO) { if (vlaninfo1->prio != vlaninfo2->prio) + return 0; + }; + /* + * Compare VLAN Encap if they are present + */ + if (vlaninfo1->bitmask & EBT_VLAN_ENCAP) { + if (vlaninfo1->encap != vlaninfo2->encap) return 0; }; return 1; --- ebtables-v2.0pre7/extensions/ebt_log.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_log.c Thu Jun 27 18:53:55 2002 @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "../include/ebtables_u.h" #include @@ -143,7 +142,8 @@ } static void final_check(const struct ebt_u_entry *entry, - const struct ebt_entry_watcher *watcher, const char *name, unsigned int hook) + const struct ebt_entry_watcher *watcher, const char *name, + unsigned int hook_mask, unsigned int time) { return; } @@ -153,13 +153,13 @@ { struct ebt_log_info *loginfo = (struct ebt_log_info *)watcher->data; - printf("log: log-level = %s - log-prefix = \"%s\"", + printf("--log-level %s --log-prefix \"%s\"", eight_priority[loginfo->loglevel].c_name, loginfo->prefix); if (loginfo->bitmask & EBT_LOG_IP) - printf(" - log-ip"); + printf(" --log-ip"); if (loginfo->bitmask & EBT_LOG_ARP) - printf(" - log-arp"); + printf(" --log-arp"); printf(" "); } --- ebtables-v2.0pre7/extensions/ebt_standard.c Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/extensions/ebt_standard.c Thu Jun 27 18:53:55 2002 @@ -1,6 +1,6 @@ #include +#include #include -#include #include #include "../include/ebtables_u.h" @@ -26,21 +26,34 @@ } static void final_check(const struct ebt_u_entry *entry, - const struct ebt_entry_target *target, const char *name, unsigned int hook) + const struct ebt_entry_target *target, const char *name, + unsigned int hook_mask, unsigned int time) { } +struct ebt_u_entries *nr_to_chain(int nr); static void print(const struct ebt_u_entry *entry, const struct ebt_entry_target *target) { - __u8 verdict = ((struct ebt_standard_target *)target)->verdict; + int verdict = ((struct ebt_standard_target *)target)->verdict; + if (verdict >= 0) { + struct ebt_u_entries *entries; + + entries = nr_to_chain(verdict + NF_BR_NUMHOOKS); + printf("%s", entries->name); + return; + } if (verdict == EBT_CONTINUE) - printf("Continue "); - else if (verdict == EBT_ACCEPT) - printf("Accept "); + printf("CONTINUE "); + else if (verdict == EBT_ACCEPT) + printf("ACCEPT "); + else if (verdict == EBT_DROP) + printf("DROP "); + else if (verdict == EBT_RETURN) + printf("RETURN "); else - printf("Drop "); + print_error("BUG: Bad standard target"); // this is a bug } static int compare(const struct ebt_entry_target *t1, --- ebtables-v2.0pre7/ChangeLog Thu Jun 6 19:22:14 2002 +++ ebtables-v2.0pre8.001/ChangeLog Thu Jun 27 18:53:55 2002 @@ -1,6 +1,14 @@ -20020606 - * more useful message when the kernel can't find an ebtables module - * some minor code clean-up (no real impact). +20020625 + * user defined chains support: added -N, -X, -E options. +20020621 + * some unlogged changes (due to lazyness) + * change the output for -L to make it look like it would look when + the user inputs the command. + * try to autoload modules + * some minor bugfixes + * add user defined chains support (without new commands yet, + deliberately) + * comparing rules didn't take the logical devices into account 20020520 * update help for -s and -d * add VLAN in ethertypes --- ebtables-v2.0pre7/ebtables.8 Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/ebtables.8 Thu Jun 27 18:53:55 2002 @@ -1,4 +1,4 @@ -.TH EBTABLES 8 "01 May 2002" +.TH EBTABLES 8 "26 June 2002" .\" .\" Man page written by Bart De Schuymer .\" It is based on the iptables man page. @@ -21,14 +21,18 @@ .\" .\" .SH NAME -ebtables(v.2.0) \- ethernet bridge packet table administration +ebtables (v.2.0) \- ethernet bridge packet table administration .SH SYNOPSIS -.BR "ebtables -[ADI] " "chain rule-specification [options]" +.BR "ebtables -[ADI] " "chain rule-specification " [ options ] .br .BR "ebtables -P " "chain target" .br .BR "ebtables -[FLZ] [" "chain" "]" .br +.BR "ebtables -[NX] " chain +.br +.BR "ebtables -E " "old-chain-name new-chain-name" +.br .B "ebtables -L DB" .br .BR "ebtables -[b] [" "y/n" "]" @@ -53,6 +57,7 @@ .IR ACCEPT , .IR DROP , .IR CONTINUE , +.IR RETURN , an extention. .PP .I ACCEPT @@ -61,7 +66,11 @@ means the frame has to be dropped. .I CONTINUE means the next rule has to be checked. This can be handy to know how many -frames pass a certain point in the chain or to log those frames. For the +frames pass a certain point in the chain or to log those frames. +.I RETURN +means stop traversing this chain and resume at the next rule in the +previous (calling) chain. +For the other targets see the .B "TARGET EXTENSIONS" section. @@ -70,7 +79,7 @@ .TP .B "-t, --table" This option specifies the frame matching table which the command should -operate on. The tables are: +operate on. If specified it should be the first option. The tables are: .BR filter , this is the default table and contains three chains: .B INPUT @@ -154,7 +163,23 @@ .B ACCEPT , either .BR DROP . -.SS PARAMETERS +.TP +.B "-N, --new-chain" +Create a new user-defined chain by the given name. +.TP +.B "-X, --delete-chain" +Delete the specified user-defined chain. There must be no references to the +chain, +.B ebtables +will complain if there are. +.TP +.B "-E, --rename-chain" +Rename the specified chain to the new name. This has no effect on the +structure of the table. It is also allowed to rename a base chain, f.e. +if you like PREBRIDGING more than PREROUTING. Be sure to talk about the +standard chain names when you would ask a question on a mailing list. +.SS +PARAMETERS The following parameters make up a rule specification (as used in the add and delete commands). A "!" argument before the specification inverts the test for that specification. Apart from these standard parameters, there are others, see @@ -265,6 +290,10 @@ .BR CONTINUE , or a target extension, see .BR "TARGET EXTENSIONS" . +.TP +.BR "-M, --modprobe " "\fIcommand\fP" +When talking to the kernel, use this +.IR command " to try to automatically load missing kernel modules." .SH MATCH EXTENSIONS .B ebtables extensions are precompiled into the userspace tool. So there is no need @@ -316,16 +345,23 @@ .BR "--arp-ip-dst " "[!] \fIaddress\fP[/\fImask\fP]" The ARP IP destination address specification. .SS vlan -Specify 802.1Q VLAN specific fields. These will only work if the protocol equals -.BR 802_1Q . -For more details see +Specify 802.1Q Tag Control Information fields. These will only work if the protocol equals +.BR 802_1Q. +Also see extension help by .BR "ebtables -h vlan" . .TP .BR "--vlan-id " "[!] \fIid\fP" -The VLAN identifier (decimal number from 0 to 4095). +The VLAN identifier field, VID (decimal number from 0 to 4094). .TP .BR "--vlan-prio " "[!] \fIprio\fP" -The VLAN priority type, this can be a decimal number from 0 to 7. The default value is 0. +The user_priority field, this can be a decimal number from 0 to 7. +Required VID to be 0 (null VID) or not specified vlan-id parameter (in this case VID deliberately be set to 0). +.TP +.BR "--vlan-encap " "[!] \fItype\fP" +The encapsulated ethernet frame type/length, this can be a hexadecimal number from 0x0000 to 0xFFFF. +Usually it's 0x0800 (IPv4). See also +.B /etc/ethertypes +file. .SH WATCHER EXTENSION(S) Watchers are things that only look at frames passing by. These watchers only see the frame if the frame passes all the matches of the rule. @@ -380,7 +416,8 @@ knows what to do. The default target is ACCEPT. Making it CONTINUE could let you use multiple target extensions on the same frame. Making it DROP doesn't -make sense, but you could do that too. +make sense, but you could do that too. RETURN is also allowed. Note +that using RETURN in a base chain will result in the CONTINUE behaviour. .TP .B dnat The @@ -405,7 +442,8 @@ The default target is ACCEPT. Making it CONTINUE could let you use multiple target extensions on the same frame. Making it DROP only makes sense in the BROUTING chain but using the redirect target is more logical -there. +there. RETURN is also allowed. Note +that using RETURN in a base chain will result in the CONTINUE behaviour. .TP .B redirect The @@ -423,7 +461,8 @@ knows what to do. The default target is ACCEPT. Making it CONTINUE could let you use multiple target extensions on the same frame. Making it DROP in the -BROUTING chain will let the frames be routed. +BROUTING chain will let the frames be routed. RETURN is also allowed. Note +that using RETURN in a base chain will result in the CONTINUE behaviour. .SH FILES .I /etc/ethertypes .SH BUGS --- ebtables-v2.0pre7/ethertypes Mon Jun 3 19:54:55 2002 +++ ebtables-v2.0pre8.001/ethertypes Thu Jun 27 18:53:55 2002 @@ -7,7 +7,7 @@ # programs using this file should not be case sensitive # that's all :-)) IPV4 0800 put your comments behind, on the same line, after a tab -X25 0800 or whitespace +X25 0805 or whitespace ARP 0806 802_1Q 8100 802.1Q Virtual LAN tagged frame IPX 8137 @@ -30,5 +30,4 @@ PPP_SES 8864 PPPoE session messages ATMMPOA 884C MultiProtocol over ATM ATMFATE 8884 Frame-based ATM Transport over Ethernet - - +LOOP 9000 --- ebtables-v2.0pre7/include/ebtables_u.h Wed Jun 5 21:43:27 2002 +++ ebtables-v2.0pre8.001/include/ebtables_u.h Thu Jun 27 18:53:55 2002 @@ -28,11 +28,23 @@ struct ebt_u_entries { - __u8 policy; + int policy; __u32 nentries; + // counter offset for this chain + unsigned int counter_offset; + // used for udc + unsigned int hook_mask; + char name[EBT_CHAIN_MAXNAMELEN]; struct ebt_u_entry *entries; }; +struct ebt_u_chain_list +{ + struct ebt_u_entries *udc; + struct ebt_u_chain_list *next; + // this is only used internally, in communications.c + char *kernel_start; +}; struct ebt_u_replace { @@ -41,8 +53,8 @@ // nr of rules in the table unsigned int nentries; struct ebt_u_entries *hook_entry[NF_BR_NUMHOOKS]; - // how many counters in front of it? - unsigned int counter_entry[NF_BR_NUMHOOKS]; + // user defined chains (udc) list + struct ebt_u_chain_list *udc; // nr of counters userspace expects back unsigned int num_counters; // where the kernel will put the old counters @@ -107,7 +119,7 @@ struct ebt_entry_match **match); void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, - const char *name, unsigned int hook); + const char *name, unsigned int hook_mask, unsigned int time); void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_match *match); int (*compare)(const struct ebt_entry_match *m1, @@ -134,7 +146,7 @@ struct ebt_entry_watcher **watcher); void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watch, const char *name, - unsigned int hook); + unsigned int hook_mask, unsigned int time); void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_watcher *watcher); int (*compare)(const struct ebt_entry_watcher *w1, @@ -158,7 +170,7 @@ struct ebt_entry_target **target); void (*final_check)(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, - unsigned int hook); + unsigned int hook_mask, unsigned int time); void (*print)(const struct ebt_u_entry *entry, const struct ebt_entry_target *target); int (*compare)(const struct ebt_entry_target *t1, @@ -175,7 +187,7 @@ void register_match(struct ebt_u_match *); void register_watcher(struct ebt_u_watcher *); void register_target(struct ebt_u_target *t); -void get_table(struct ebt_u_replace *repl); +int get_table(struct ebt_u_replace *repl); struct ebt_u_target *find_target(const char *name); struct ebt_u_match *find_match(const char *name); struct ebt_u_watcher *find_watcher(const char *name); @@ -185,7 +197,8 @@ void get_dbinfo(struct brdb_dbinfo *nr); void get_db(int len, struct brdb_dbentry *db); void deliver_allowdb(__u16 *decision); -int name_to_protocol(char *name); +int name_to_number(char *name, __u16 *proto); +int number_to_name(unsigned short proto, char *name); void check_option(unsigned int *flags, unsigned int mask); int check_inverse(const char option[]); #define print_bug(format, args...) \