summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--userspace/patches/incremental-patches/ebtables-v2.0pre10.001.diff790
1 files changed, 790 insertions, 0 deletions
diff --git a/userspace/patches/incremental-patches/ebtables-v2.0pre10.001.diff b/userspace/patches/incremental-patches/ebtables-v2.0pre10.001.diff
new file mode 100644
index 0000000..86f7e36
--- /dev/null
+++ b/userspace/patches/incremental-patches/ebtables-v2.0pre10.001.diff
@@ -0,0 +1,790 @@
+--- ebtables-v2.0pre9/Makefile Sun Jul 7 16:29:50 2002
++++ ebtables-v2.0pre10.001/Makefile Wed Jul 10 22:12:36 2002
+@@ -2,7 +2,7 @@
+
+ KERNEL_DIR?=/usr/src/linux
+ PROGNAME:=ebtables
+-PROGVERSION:="2.0pre9 (July 2002)"
++PROGVERSION:="2.0pre10 (July 2002)"
+
+ MANDIR?=/usr/local/man
+ CFLAGS:=-Wall -Wunused
+@@ -51,9 +51,12 @@
+ /etc/ethertypes: ethertypes
+ mkdir -p $(@D)
+ install -m 0644 -o root -g root $< $@
++.PHONY: exec
++exec: ebtables
++ install -m 0755 -o root -g root $< /sbin/ebtables
+
+ install: $(MANDIR)/man8/ebtables.8 $(KERNEL_INCLUDES) \
+- ebtables /etc/ethertypes
++ ebtables /etc/ethertypes exec
+
+ clean:
+ rm -f ebtables
+--- ebtables-v2.0pre9/ebtables.c Sat Jun 29 11:41:57 2002
++++ ebtables-v2.0pre10.001/ebtables.c Mon Jul 15 22:14:59 2002
+@@ -62,11 +62,17 @@
+ };
+
+ // default command line options
+-static struct option ebt_original_options[] = {
++// do not mess around with the already assigned numbers unless
++// you know what you are doing
++static struct option ebt_original_options[] =
++{
+ { "append" , required_argument, 0, 'A' },
+ { "insert" , required_argument, 0, 'I' },
+ { "delete" , required_argument, 0, 'D' },
+ { "list" , optional_argument, 0, 'L' },
++ { "Lc" , no_argument , 0, 4 },
++ { "Ln" , no_argument , 0, 5 },
++ { "Lx" , no_argument , 0, 6 },
+ { "zero" , optional_argument, 0, 'Z' },
+ { "flush" , optional_argument, 0, 'F' },
+ { "policy" , required_argument, 0, 'P' },
+@@ -91,13 +97,19 @@
+ { "new-chain" , required_argument, 0, 'N' },
+ { "rename-chain" , required_argument, 0, 'E' },
+ { "delete-chain" , required_argument, 0, 'X' },
++ { "atomic-init" , required_argument, 0, 7 },
++ { "atomic-commit" , required_argument, 0, 8 },
++ { "atomic" , required_argument, 0, 9 },
++ { "atomic-save" , required_argument, 0, 10 },
++ { "init-table" , no_argument , 0, 11 },
+ { 0 }
+ };
+
+ static struct option *ebt_options = ebt_original_options;
+
+ // yup, all the possible target names
+-char* standard_targets[NUM_STANDARD_TARGETS] = {
++char* standard_targets[NUM_STANDARD_TARGETS] =
++{
+ "ACCEPT",
+ "DROP",
+ "CONTINUE",
+@@ -169,7 +181,7 @@
+ // Same holds for the struct ebt_match and struct ebt_watcher pointers
+ struct ebt_u_entry *new_entry;
+
+-void initialize_entry(struct ebt_u_entry *e)
++static void initialize_entry(struct ebt_u_entry *e)
+ {
+ e->bitmask = EBT_NOPROTO;
+ e->invflags = 0;
+@@ -188,7 +200,7 @@
+ }
+
+ // this doesn't free e, becoz the calling function might need e->next
+-void free_u_entry(struct ebt_u_entry *e)
++static void free_u_entry(struct ebt_u_entry *e)
+ {
+ struct ebt_u_match_list *m_l, *m_l2;
+ struct ebt_u_watcher_list *w_l, *w_l2;
+@@ -403,7 +415,7 @@
+
+
+ // used to parse /etc/ethertypes
+-int disregard_whitespace(char *buffer, FILE *ifp)
++static int disregard_whitespace(char *buffer, FILE *ifp)
+ {
+ int hlp;
+
+@@ -416,7 +428,7 @@
+ }
+
+ // used to parse /etc/ethertypes
+-int disregard_tabspace(char *buffer, FILE *ifp)
++static int disregard_tabspace(char *buffer, FILE *ifp)
+ {
+ int hlp;
+
+@@ -429,7 +441,7 @@
+ }
+
+ // helper function: processes a line of data from the file /etc/ethertypes
+-int get_a_line(char *buffer, char *value, FILE *ifp)
++static int get_a_line(char *buffer, char *value, FILE *ifp)
+ {
+ int i, hlp;
+ char anotherhlp;
+@@ -507,6 +519,11 @@
+ }
+ }
+
++// we use replace.flags, so we can't use the following values:
++// 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
++#define LIST_N 0x04
++#define LIST_C 0x08
++#define LIST_X 0x10
+ // helper function for list_rules()
+ static void list_em(struct ebt_u_entries *entries)
+ {
+@@ -520,9 +537,14 @@
+ char name[21];
+
+ 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);
++ if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
++ printf("ebtables -t %s -P %s %s\n", replace.name,
++ entries->name, standard_targets[-entries->policy - 1]);
++ } else if (!(replace.flags & LIST_X)) {
++ printf("\nBridge chain: %s\nPolicy: %s\n", entries->name,
++ standard_targets[-entries->policy - 1]);
++ printf("nr. of entries: %d \n", entries->nentries);
++ }
+
+ i = entries->nentries;
+ while (i > 9) {
+@@ -531,16 +553,21 @@
+ }
+
+ 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;
+- }
+- for (j = 0; j < space - digits; j++)
+- printf(" ");
+- printf("%d. ", i + 1);
++ if (replace.flags & LIST_N) {
++ digits = 0;
++ // A little work to get nice rule numbers.
++ j = i + 1;
++ while (j > 9) {
++ digits++;
++ j /= 10;
++ }
++ for (j = 0; j < space - digits; j++)
++ printf(" ");
++ printf("%d. ", i + 1);
++ }
++ if (replace.flags & LIST_X)
++ printf("ebtables -t %s -A %s ",
++ replace.name, entries->name);
+
+ // Don't print anything about the protocol if no protocol was
+ // specified, obviously this means any protocol will do.
+@@ -668,8 +695,9 @@
+ if (!t)
+ print_bug("Target not found");
+ t->print(hlp, hlp->t);
+- printf(", count = %llu",
+- replace.counters[entries->counter_offset + i].pcnt);
++ if (replace.flags & LIST_C)
++ printf(", count = %llu",
++ replace.counters[entries->counter_offset + i].pcnt);
+ printf("\n");
+ hlp = hlp->next;
+ }
+@@ -710,7 +738,7 @@
+ struct ebt_u_entries *entries;
+ };
+
+-void check_for_loops()
++static void check_for_loops()
+ {
+ int chain_nr , i, j , k, sp = 0, verdict;
+ struct ebt_u_entries *entries, *entries2;
+@@ -813,7 +841,7 @@
+ }
+
+ // yup, print out help
+-void print_help()
++static void print_help()
+ {
+ struct ebt_u_match_list *m_l;
+ struct ebt_u_watcher_list *w_l;
+@@ -833,11 +861,16 @@
+ "--list -L [chain] : List the rules in a chain or in all chains\n"
+ "--list -L "DATABASEHOOKNAME" : List the database (if present)\n"
+ "--flush -F [chain] : Delete all rules in chain or in all chains\n"
++"--init-table : Replace the kernel table with the initial table\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"
++"--atomic-commit file : update the kernel w/ the table contained in file\n"
++"--atomic-init file : put the initial kernel table into file\n"
++"--atomic-save file : put the current kernel table into file\n"
++"--atomic file : write changes to file instead of kernel\n"
+ "Options:\n"
+ "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
+ "--src -s [!] address[/mask]: source mac address\n"
+@@ -846,7 +879,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"
++"--modprobe -M program : try to insert modules using this program\n"
+ "--version -V : print package version\n"
+ "\n" ,
+ prog_name,
+@@ -876,12 +909,28 @@
+ {
+ int i;
+
+- printf("Bridge table: %s\n", table->name);
++ if (!(replace.flags & LIST_X))
++ printf("Bridge table: %s\n", table->name);
+ if (replace.selected_hook != -1) {
+ list_em(to_chain());
+ } else {
+ struct ebt_u_chain_list *cl = replace.udc;
+
++ // create new chains and rename standard chains when necessary
++ if (replace.flags & LIST_X) {
++ while (cl) {
++ printf("ebtables -t %s -N %s\n", replace.name,
++ cl->udc->name);
++ cl = cl->next;
++ }
++ cl = replace.udc;
++ for (i = 0; i < NF_BR_NUMHOOKS; i++)
++ if (replace.valid_hooks & (1 << i) &&
++ strcmp(replace.hook_entry[i]->name, hooknames[i]))
++ printf("ebtables -t %s -E %s %s\n",
++ replace.name, hooknames[i],
++ replace.hook_entry[i]->name);
++ }
+ i = 0;
+ while (1) {
+ if (i < NF_BR_NUMHOOKS) {
+@@ -1292,7 +1341,7 @@
+ }
+
+ // execute command Z
+-void zero_counters(int zerochain)
++static void zero_counters(int zerochain)
+ {
+
+ if (zerochain == -1) {
+@@ -1463,7 +1512,7 @@
+ }
+
+ // 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)
++static 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;
+@@ -1491,7 +1540,7 @@
+ }
+
+ // used for the -X command
+-void check_for_references(int chain_nr)
++static void check_for_references(int chain_nr)
+ {
+ int i = -1, j;
+ struct ebt_u_entries *entries;
+@@ -1571,6 +1620,7 @@
+ replace.flags = 0;
+ replace.selected_hook = -1;
+ replace.command = 'h';
++ replace.filename = NULL;
+
+ new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+ if (!new_entry)
+@@ -1579,7 +1629,8 @@
+ 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
++ // '-t' ,'-M' and --atomic (if specified) have to come
++ // before '-A' and the like
+
+ // getopt saves the day
+ while ((c = getopt_long(argc, argv,
+@@ -2013,8 +2064,78 @@
+ allowbc = *optarg;
+ break;
+
+- default:
++ case 4 : // Lc
++ check_option(&replace.flags, LIST_C);
++ if (replace.selected_hook == DATABASEHOOKNR)
++ print_error("--Lc not valid for listing"
++ " the database");
++ if (replace.command != 'L')
++ print_error("Use --Lc with -L");
++ if (replace.flags & LIST_X)
++ print_error("--Lx not compatible with --Lc");
++ replace.flags |= LIST_C;
++ break;
++ case 5 : // Ln
++ check_option(&replace.flags, LIST_N);
++ if (replace.selected_hook == DATABASEHOOKNR)
++ print_error("--Ln not valid for listing"
++ " the database");
++ if (replace.command != 'L')
++ print_error("Use --Ln with -L");
++ if (replace.flags & LIST_X)
++ print_error("--Lx not compatible with --Ln");
++ replace.flags |= LIST_N;
++ break;
++ case 6 : // Lx
++ check_option(&replace.flags, LIST_X);
++ if (replace.selected_hook == DATABASEHOOKNR)
++ print_error("--Lx not valid for listing"
++ " the database");
++ if (replace.command != 'L')
++ print_error("Use --Lx with -L");
++ if (replace.flags & LIST_C)
++ print_error("--Lx not compatible with --Lc");
++ if (replace.flags & LIST_N)
++ print_error("--Lx not compatible with --Ln");
++ replace.flags |= LIST_X;
++ break;
++ case 8 : // atomic-commit
++ replace.command = c;
++ if (replace.flags & OPT_COMMAND)
++ print_error("Multiple commands not allowed");
++ replace.flags |= OPT_COMMAND;
++ replace.filename = (char *)malloc(strlen(optarg) + 1);
++ strcpy(replace.filename, optarg);
++ // get the information from the file
++ get_table(&replace);
++ replace.num_counters = 0;
++ free(replace.filename);
++ replace.filename = NULL;
++ break;
++ case 7 : // atomic-init
++ case 10: // atomic-save
++ case 11: // init-table
++ 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");
++ if (get_table(&replace)) {
++ ebtables_insmod("ebtables", modprobe);
++ if (get_table(&replace))
++ print_error("can't initialize ebtables "
++ "table %s", replace.name);
++ }
++ replace.num_counters = 0;
++ if (c == 11)
++ break;
++ case 9 : // atomic
++ replace.filename = (char *)malloc(strlen(optarg) + 1);
++ strcpy(replace.filename, optarg);
++ break;
+
++ default:
+ // is it a target option?
+ t = (struct ebt_u_target *)new_entry->t;
+ if ((t->parse(c - t->option_offset, argv, argc,
+@@ -2142,7 +2263,8 @@
+ }
+ } else if (replace.command == 'D')
+ delete_rule(rule_nr);
+- // commands -N, -E, -X fall through
++ // commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
++ // --init-table fall through
+
+ if (table->check)
+ table->check(&replace);
+--- ebtables-v2.0pre9/communication.c Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0pre10.001/communication.c Mon Jul 15 22:35:14 2002
+@@ -27,7 +27,7 @@
+
+ int sockfd = -1;
+
+-void get_sockfd()
++static void get_sockfd()
+ {
+ if (sockfd == -1) {
+ sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
+@@ -209,6 +209,47 @@
+ return new;
+ }
+
++static void store_table_in_file(char *filename, struct ebt_replace *repl)
++{
++ char *command, *data;
++ int size;
++ FILE *file;
++
++ // start from an empty file with right priviliges
++ command = (char *)malloc(strlen(filename) + 15);
++ if (!command)
++ print_memory();
++ strcpy(command, "cat /dev/null>");
++ strcpy(command + 14, filename);
++ if (system(command))
++ print_error("Couldn't create file %s", filename);
++ strcpy(command, "chmod 600 ");
++ strcpy(command + 10, filename);
++ if (system(command))
++ print_error("Couldn't chmod file %s", filename);
++ free(command);
++
++ size = sizeof(struct ebt_replace) + repl->entries_size +
++ repl->nentries * sizeof(struct ebt_counter);
++ data = (char *)malloc(size);
++ if (!data)
++ print_memory();
++ memcpy(data, repl, sizeof(struct ebt_replace));
++ memcpy(data + sizeof(struct ebt_replace), repl->entries,
++ repl->entries_size);
++ // initialize counters to zero, deliver_counters() can update them
++ memset(data + sizeof(struct ebt_replace) + repl->entries_size,
++ 0, repl->nentries * sizeof(struct ebt_counter));
++ if (!(file = fopen(filename, "wb")))
++ print_error("Couldn't open file %s", filename);
++ if (fwrite(data, sizeof(char), size, file) != size) {
++ fclose(file);
++ print_error("Couldn't write everything to file %s", filename);
++ }
++ fclose(file);
++ free(data);
++}
++
+ void deliver_table(struct ebt_u_replace *u_repl)
+ {
+ socklen_t optlen;
+@@ -216,15 +257,43 @@
+
+ // translate the struct ebt_u_replace to a struct ebt_replace
+ repl = translate_user2kernel(u_repl);
+- get_sockfd();
+ // give the data to the kernel
+ optlen = sizeof(struct ebt_replace) + repl->entries_size;
++ if (u_repl->filename != NULL) {
++ store_table_in_file(u_repl->filename, repl);
++ return;
++ }
++ get_sockfd();
+ if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
+ print_error("The kernel doesn't support a certain ebtables"
+ " extension, consider recompiling your kernel or insmod"
+ " the extension");
+ }
+
++static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
++{
++ int size = repl->nentries * sizeof(struct ebt_counter);
++ int entries_size;
++ struct ebt_replace hlp;
++ FILE *file;
++
++ if (!(file = fopen(filename, "r+b")))
++ print_error("Could not open file %s", filename);
++ // find out entries_size and then set the file pointer to the counters
++ if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
++ || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
++ sizeof(unsigned int) ||
++ fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
++ fclose(file);
++ print_error("File %s is corrupt", filename);
++ }
++ if (fwrite(repl->counters, sizeof(char), size, file) != size) {
++ fclose(file);
++ print_error("Could not write everything to file %s", filename);
++ }
++ fclose(file);
++}
++
+ // gets executed after deliver_table
+ void
+ deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
+@@ -273,6 +342,10 @@
+ free(u_repl->counters);
+ u_repl->counters = newcounters;
+ u_repl->num_counters = u_repl->nentries;
++ if (u_repl->filename != NULL) {
++ store_counters_in_file(u_repl->filename, u_repl);
++ return;
++ }
+ optlen = u_repl->nentries * sizeof(struct ebt_counter) +
+ sizeof(struct ebt_replace);
+ // now put the stuff in the kernel's struct ebt_replace
+@@ -484,37 +557,119 @@
+ return 0;
+ }
+
+-// talk with kernel to receive the kernel's table
+-int get_table(struct ebt_u_replace *u_repl)
++static void retrieve_from_file(char *filename, struct ebt_replace *repl,
++ char command)
+ {
+- int i, j, k, hook;
+- socklen_t optlen;
+- struct ebt_replace repl;
+- struct ebt_u_entry **u_e;
++ FILE *file;
++ char *hlp;
++ int size;
++
++ if (!(file = fopen(filename, "r+b")))
++ print_error("Could not open file %s", filename);
++ // make sure table name is right if command isn't -L or --atomic-commit
++ if (command != 'L' && command != 8) {
++ hlp = (char *)malloc(strlen(repl->name));
++ if (!hlp)
++ print_memory();
++ strcpy(hlp, repl->name);
++ }
++ if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
++ != sizeof(struct ebt_replace))
++ print_error("File %s is corrupt", filename);
++ if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
++ fclose(file);
++ print_error("File %s contains wrong table name or is corrupt",
++ filename);
++ } else
++ if (!find_table(repl->name)) {
++ fclose(file);
++ print_error("File %s contains invalid table name",
++ filename);
++ }
+
+- get_sockfd();
++ size = sizeof(struct ebt_replace) +
++ repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
++ fseek(file, 0, SEEK_END);
++ if (size != ftell(file)) {
++ fclose(file);
++ print_error("File %s has wrong size", filename);
++ }
++ repl->entries = (char *)malloc(repl->entries_size);
++ if (!repl->entries)
++ print_memory();
++ if (repl->nentries) {
++ repl->counters = (struct ebt_counter *)
++ malloc(repl->nentries * sizeof(struct ebt_counter));
++ if (!repl->counters)
++ print_memory();
++ } else
++ repl->counters = NULL;
++ // copy entries and counters
++ if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
++ fread(repl->entries, sizeof(char), repl->entries_size, file)
++ != repl->entries_size ||
++ fseek(file, sizeof(struct ebt_replace) + repl->entries_size, SEEK_SET)
++ || fread(repl->counters, sizeof(char),
++ repl->nentries * sizeof(struct ebt_counter), file)
++ != repl->nentries * sizeof(struct ebt_counter)) {
++ fclose(file);
++ print_error("File %s is corrupt", filename);
++ }
++ fclose(file);
++}
++
++static int retrieve_from_kernel(struct ebt_replace *repl, char command)
++{
++ socklen_t optlen;
++ int optname;
+
+ optlen = sizeof(struct ebt_replace);
+- strcpy(repl.name, u_repl->name);
+- if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
++ get_sockfd();
++ // --atomic-init || --init-table
++ if (command == 7 || command == 11)
++ optname = EBT_SO_GET_INIT_INFO;
++ else
++ optname = EBT_SO_GET_INFO;
++ if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
+ return -1;
+
+- if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
++ if ( !(repl->entries = (char *) malloc(repl->entries_size)) )
+ print_memory();
+- if (repl.nentries) {
+- if (!(repl.counters = (struct ebt_counter *)
+- malloc(repl.nentries * sizeof(struct ebt_counter))) )
++ if (repl->nentries) {
++ if (!(repl->counters = (struct ebt_counter *)
++ malloc(repl->nentries * sizeof(struct ebt_counter))) )
+ print_memory();
+ }
+ else
+- repl.counters = NULL;
++ repl->counters = NULL;
+
+ // we want to receive the counters
+- repl.num_counters = repl.nentries;
+- optlen += repl.entries_size + repl.num_counters *
++ repl->num_counters = repl->nentries;
++ optlen += repl->entries_size + repl->num_counters *
+ sizeof(struct ebt_counter);
+- if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_ENTRIES, &repl, &optlen))
++ if (command == 7 || command == 11)
++ optname = EBT_SO_GET_INIT_ENTRIES;
++ else
++ optname = EBT_SO_GET_ENTRIES;
++ if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
+ print_bug("hmm, what is wrong??? bug#1");
++
++ return 0;
++}
++
++// talk with kernel to receive the kernel's table
++int get_table(struct ebt_u_replace *u_repl)
++{
++ int i, j, k, hook;
++ struct ebt_replace repl;
++ struct ebt_u_entry **u_e;
++
++ strcpy(repl.name, u_repl->name);
++ if (u_repl->filename != NULL)
++ retrieve_from_file(u_repl->filename, &repl, u_repl->command);
++ else
++ if (retrieve_from_kernel(&repl, u_repl->command) == -1)
++ return -1;
+
+ // translate the struct ebt_replace to a struct ebt_u_replace
+ memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
+--- ebtables-v2.0pre9/ChangeLog Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0pre10.001/ChangeLog Sun Jul 14 21:30:18 2002
+@@ -1,3 +1,8 @@
++20020714
++ * added --atomic options
++20020710
++ * some unlogged changes (due to lazyness)
++ * added --Lc, --Ln, --Lx
+ 20020625
+ * user defined chains support: added -N, -X, -E options.
+ 20020621
+--- ebtables-v2.0pre9/ebtables.8 Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0pre10.001/ebtables.8 Mon Jul 15 21:45:55 2002
+@@ -37,6 +37,14 @@
+ .br
+ .BR "ebtables -[b] [" "y/n" "]"
+ .br
++.BR "ebtables --init-table"
++.br
++.BR "ebtables --atomic-init " file
++.br
++.BR "ebtables --atomic-save " file
++.br
++.BR "ebtables --atomic-commit " file
++.br
+ .SH DESCRIPTION
+ .B ebtables
+ is used to set up, maintain, and inspect the tables of Ethernet frame
+@@ -148,11 +156,34 @@
+ database is independent from the rest of
+ .B ebtables
+ and is in a different kernel module.
++.br
++The following three options change the output when not listing the
++database:
++.br
++.B "--Ln"
++.br
++Puts rule numbers in front of every rule.
++.br
++.B "--Lc"
++.br
++Puts the counter value at the end of every rule.
++.br
++.B "--Lx"
++.br
++The output is directly usable as executable commands in a script, to be
++run f.e. at bootup. This option is incompatible with the previous two
++options. When no chain name was specified for the
++.B "-L"
++command, all necessary commands for making the user defined chains and
++renaming the standard chains will be made.
+ .TP
+ .B "-F, --flush"
+ Flush the selected chain. If no chain is selected, every chain will be
+ flushed. This does not change the policy of the chain.
+ .TP
++.B "--init-table"
++Replace the current table data by the initial table data.
++.TP
+ .B "-Z, --zero"
+ Put the counters of the selected chain on zero. If no chain is selected, all the counters
+ are put on zero. This can be used in conjunction with the -L command (see above).
+@@ -178,6 +209,30 @@
+ 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.
++.TP
++.B "--atomic-init"
++Copy the kernel's initial data of the table to the specified
++file. This can be used as the first action, after which rules are added
++to the file.
++.TP
++.B "--atomic-save"
++Copy the kernel's current data of the table to the specified
++file. This can be used as the first action, after which rules are added
++to the file.
++.TP
++.B "--atomic-commit"
++Replace the kernel table data with the data contained in the specified
++file. This is a useful command that allows you to put all your rules of a
++certain table into the kernel at once, saving the kernel a lot of precious
++time. The file which contains the table data is constructed by using
++either the
++.B "--atomic-init"
++or the
++.B "--atomic-save"
++command to get a starting file. After that, using the
++.B "--atomic"
++option when constructing rules allows you to extend the file and build up
++the complete wanted table.
+ .SS
+ PARAMETERS
+ The following parameters make up a rule specification (as used in the add
+@@ -280,8 +335,8 @@
+ .B ebtables
+ will try to write help about those extensions. E.g. ebtables -h snat log ip arp.
+ .TP
+-.BR "-b --db " "[\fIy/n\fP]"
+-.IR "" "Enable (" y ") or disable (" n ") the database."
++.BR "-b --db [" "y/n" "]"
++Enable (y) or disable (n) the database.
+ .TP
+ .BR "-j, --jump " "\fItarget\fP"
+ The target of the rule. This is one of the following values:
+@@ -291,9 +346,15 @@
+ 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."
++.BR "--atomic " file
++Let the command operate on the specified file. The data of the table to
++operate on will be extracted from the file and the result of the operation
++will be saved back into the file. If specified, this option should come
++before the command specification.
++.TP
++.BR "-M, --modprobe " "program"
++When talking to the kernel, use this program 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
+--- ebtables-v2.0pre9/include/ebtables_u.h Thu Jun 27 18:53:55 2002
++++ ebtables-v2.0pre10.001/include/ebtables_u.h Sat Jul 13 21:13:46 2002
+@@ -66,6 +66,8 @@
+ char command;
+ // here we stick the hook to do our thing on (can be -1 if unspecified)
+ int selected_hook;
++ // used for the atomic option
++ char *filename;
+ };
+
+ struct ebt_u_table
+@@ -191,6 +193,7 @@
+ 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);
++struct ebt_u_table *find_table(char *name);
+ void deliver_counters(struct ebt_u_replace *repl,
+ unsigned short * counterchanges);
+ void deliver_table(struct ebt_u_replace *repl);