| --- 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 <netinet/ether.h> |
| #include <asm/types.h> |
| #include "include/ebtables_u.h" |
| +#include <unistd.h> |
| +#include <fcntl.h> |
| +#include <sys/wait.h> |
| |
| // 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 <this> -L <that>) |
| 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 <string.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_redirect.h> |
| @@ -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 <sys/socket.h> |
| #include <netinet/in.h> |
| #include <netinet/ether.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_nat.h> |
| @@ -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 <sys/socket.h> |
| #include <netinet/in.h> |
| #include <string.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_ip.h> |
| @@ -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 <stdlib.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_arp.h> |
| @@ -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 <bart.de.schuymer@pandora.be> |
| - * Nick Fedchik <nick@fedchik.org.ua> |
| - * |
| - * May, 2002 |
| + * Nick Fedchik <nick@fedchik.org.ua> |
| + * 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 <stdio.h> |
| -#include <string.h> |
| #include <stdlib.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| +#include <string.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_vlan.h> |
| |
| -#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 <stdlib.h> |
| #include <string.h> |
| #include <sys/socket.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #include "../include/ebtables_u.h" |
| #include <linux/netfilter_bridge/ebt_log.h> |
| @@ -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 <stdio.h> |
| +#include <stdlib.h> |
| #include <sys/socket.h> |
| -#include <linux/netfilter_bridge/ebtables.h> |
| #include <getopt.h> |
| #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 <bart.de.schuymer@pandora.be> |
| .\" 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...) \ |