summaryrefslogtreecommitdiffstats
path: root/userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff
diff options
context:
space:
mode:
Diffstat (limited to 'userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff')
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff2745
1 files changed, 2745 insertions, 0 deletions
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff
new file mode 100644
index 0000000..851b2c6
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre8.001.diff
@@ -0,0 +1,2745 @@
+--- 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...) \