From 6622a01ea3874e189d877c954f791259b8e6a504 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 19 Jan 2005 21:09:05 +0000 Subject: add ebtablesu scheme, along with general cleanup --- ChangeLog | 7 + INSTALL | 10 +- Makefile | 50 ++- communication.c | 235 ++++++----- ebtables-standalone.c | 14 + ebtables.8 | 84 +++- ebtables.c | 1063 +++++++++++++++++++++--------------------------- ebtablesd.c | 367 +++++++++++++++++ ebtablesu.c | 61 +++ extensions/ebt_ip.c | 2 +- extensions/ebt_limit.c | 18 +- extensions/ebt_vlan.c | 9 +- include/ebtables_u.h | 18 +- libebtc.c | 535 ++++++++++-------------- 14 files changed, 1429 insertions(+), 1044 deletions(-) create mode 100644 ebtables-standalone.c create mode 100644 ebtablesd.c create mode 100644 ebtablesu.c diff --git a/ChangeLog b/ChangeLog index d52160e..af1fe66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +20051701 + Since last entry: + * added ulog watcher + * made the ebtables code modular (make library functions). + * added the ebtablesd/ebtablesu scheme to allow faster + addition of rules (and to test the modular code). + * some small fixes 20031102 Since last entry: * added arpreply and among modules diff --git a/INSTALL b/INSTALL index 2d1e42f..371cbe4 100644 --- a/INSTALL +++ b/INSTALL @@ -17,9 +17,13 @@ WHAT GETS INSTALLED? The Makefile will append /man8/ebtables.8. - ethertypes is by default placed in /etc/, if you want to change this, include ETHERTYPESPATH=<>. -- the userspace program ebtables is compiled and the executable is copied - by default to /usr/sbin/ebtables. If you want to put the executable - somewhere else, include BINPATH=<>. +- The pipe used for communication by ebtablesd and ebtablesu is by + default the file /etc/ebtables-v$(PROGVERSION)/ebtablesd_pipe. To + change the directory, include PIPE_DIR=<>. There is no option + to change the name of the pipe. +- the userspace programs ebtables ebtablesu and ebtablesd are compiled and + the executables are copied by default to /usr/sbin/ebtables. If you want + to put the executables somewhere else, include BINPATH=<>. That's all diff --git a/Makefile b/Makefile index e519c4e..671de96 100644 --- a/Makefile +++ b/Makefile @@ -38,15 +38,30 @@ KERNEL_INCLUDES?=include/ ETHERTYPESPATH?=$(ETCDIR) ETHERTYPESFILE:=$(ETHERTYPESPATH)/ethertypes -BINFILE:=$(BINDIR)/ebtables +PIPE_DIR?=. +PIPE=$(PIPE_DIR)/ebtablesd_pipe +EBTD_CMDLINE_MAXLN?=2048 +EBTD_ARGC_MAX?=50 + +BINFILE_EBT:=$(BINDIR)/$(PROGNAME) +BINFILE_EBTD:=$(BINDIR)/$(PROGNAME)d +BINFILE_EBTU:=$(BINDIR)/$(PROGNAME)u PROGSPECS:=-DPROGVERSION=\"$(PROGVERSION)\" \ -DPROGNAME=\"$(PROGNAME)\" \ -DPROGDATE=\"$(PROGDATE)\" \ -D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\" +PROGSPECSD:=-DPROGVERSION=\"$(PROGVERSION)\" \ + -DPROGNAME=\"$(PROGNAME)\" \ + -DPROGDATE=\"$(PROGDATE)\" \ + -D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\" \ + -DEBTD_CMDLINE_MAXLN=$(EBTD_CMDLINE_MAXLN) \ + -DEBTD_ARGC_MAX=$(EBTD_ARGC_MAX) \ + -DEBTD_PIPE=\"$(PIPE)\" \ + -DEBTD_PIPE_DIR=\"$(PIPE_DIR)\" -all: ebtables +all: ebtables daemon communication.o: communication.c include/ebtables_u.h $(CC) $(CFLAGS) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES) @@ -63,11 +78,28 @@ getethertype.o: getethertype.c include/ethernetdb.h ebtables.o: ebtables.c include/ebtables_u.h $(CC) $(CFLAGS) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES) -ebtables: $(OBJECTS) +ebtables-standalone.o: ebtables-standalone.c ebtables.c include/ebtables_u.h + $(CC) $(CFLAGS) $(PROGSPECS) -c $< ebtables.c -o $@ -I$(KERNEL_INCLUDES) + +ebtables: $(OBJECTS) ebtables-standalone.o $(LD) -shared -soname libebtc.so -o libebtc.so -lc $(OBJECTS2) - $(CC) $(CFLAGS) -o $@ ebtables.o -I$(KERNEL_INCLUDES) -L/root/ \ + $(CC) $(CFLAGS) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L/root/ \ -L. -Lextensions/ -lebtc $(EXT_LIBSI) - + +ebtablesu: ebtablesu.c + $(CC) $(CFLAGS) $(PROGSPECSD) $< -o $@ + +ebtablesd.o: ebtablesd.c ebtables.c include/ebtables_u.h + $(CC) $(CFLAGS) $(PROGSPECSD) -c $< ebtables.c -o $@ -I$(KERNEL_INCLUDES) + +ebtablesd: $(OBJECTS) ebtablesd.o + $(LD) -shared -soname libebtc.so -o libebtc.so -lc $(OBJECTS2) + $(CC) $(CFLAGS) -o $@ ebtablesd.o -I$(KERNEL_INCLUDES) -L/root/ \ + -L. -Lextensions/ -lebtc $(EXT_LIBSI) + +.PHONY: daemon +daemon: ebtablesd ebtablesu + $(MANDIR)/man8/ebtables.8: ebtables.8 mkdir -p $(@D) install -m 0644 -o root -g root $< $@ @@ -77,9 +109,11 @@ $(ETHERTYPESFILE): ethertypes install -m 0644 -o root -g root $< $@ .PHONY: exec -exec: ebtables +exec: ebtables daemon mkdir -p $(BINDIR) - install -m 0755 -o root -g root $< $(BINFILE) + install -m 0755 -o root -g root $(PROGNAME) $(BINFILE_EBT) + install -m 0755 -o root -g root $(PROGNAME)d $(BINFILE_EBTD) + install -m 0755 -o root -g root $(PROGNAME)u $(BINFILE_EBTU) .PHONY: install install: $(MANDIR)/man8/ebtables.8 $(ETHERTYPESFILE) exec @@ -89,7 +123,7 @@ install: $(MANDIR)/man8/ebtables.8 $(ETHERTYPESFILE) exec .PHONY: clean clean: - rm -f ebtables + rm -f ebtables ebtablesd ebtablesu rm -f *.o *.c~ *.so rm -f extensions/*.o extensions/*.c~ extensions/*.so diff --git a/communication.c b/communication.c index af00fa2..81fca22 100644 --- a/communication.c +++ b/communication.c @@ -31,15 +31,19 @@ extern char* hooknames[NF_BR_NUMHOOKS]; int sockfd = -1; -static void get_sockfd() +static int get_sockfd() { + int ret = 0; if (sockfd == -1) { sockfd = socket(AF_INET, SOCK_RAW, PF_INET); - if (sockfd < 0) + if (sockfd < 0) { ebt_print_error("Problem getting a socket, " "you probably don't have the right " "permissions"); + ret = -1; + } } + return ret; } static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) @@ -62,7 +66,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) new->nentries = u_repl->nentries; new->num_counters = u_repl->num_counters; new->counters = sparc_cast u_repl->counters; - /* determine nr of udc */ + /* Determine nr of udc */ i = 0; cl = u_repl->udc; while (cl) { @@ -71,7 +75,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) } i += NF_BR_NUMHOOKS; chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int)); - /* determine size */ + /* Determine size */ i = 0; cl = u_repl->udc; while (1) { @@ -109,7 +113,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) sizeof(struct ebt_entry_target); e = e->next; } - /* a little sanity check */ + /* A little sanity check */ if (j != entries->nentries) ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j, entries->nentries, entries->name); @@ -123,7 +127,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) if (!p) ebt_print_memory(); - /* put everything in one block */ + /* Put everything in one block */ new->entries = sparc_cast p; i = 0; cl = u_repl->udc; @@ -147,7 +151,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) hlp->policy = entries->policy; strcpy(hlp->name, entries->name); hlp->counter_offset = entries->counter_offset; - hlp->distinguisher = 0; /* make the kernel see the light */ + hlp->distinguisher = 0; /* Make the kernel see the light */ p += sizeof(struct ebt_entries); e = entries->entries; while (e) { @@ -192,7 +196,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) 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 */ + /* Translate the jump to a udc */ if (st->verdict >= 0) st->verdict = chain_offsets [st->verdict + NF_BR_NUMHOOKS]; @@ -207,7 +211,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) i++; } - /* sanity check */ + /* Sanity check */ if (p - (char *)new->entries != new->entries_size) ebt_print_bug("Entries_size bug"); free(chain_offsets); @@ -220,19 +224,22 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl) int size; FILE *file; - /* start from an empty file with right priviliges */ + /* Start from an empty file with right priviliges */ command = (char *)malloc(strlen(filename) + 15); if (!command) ebt_print_memory(); strcpy(command, "cat /dev/null>"); strcpy(command + 14, filename); - if (system(command)) + if (system(command)) { ebt_print_error("Couldn't create file %s", filename); + goto free_command; + } strcpy(command, "chmod 600 "); strcpy(command + 10, filename); - if (system(command)) + if (system(command)) { ebt_print_error("Couldn't chmod file %s", filename); - free(command); + goto free_command; + } size = sizeof(struct ebt_replace) + repl->entries_size + repl->nentries * sizeof(struct ebt_counter); @@ -242,18 +249,20 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl) memcpy(data, repl, sizeof(struct ebt_replace)); memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries, repl->entries_size); - /* initialize counters to zero, deliver_counters() can update them */ + /* 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"))) + if (!(file = fopen(filename, "wb"))) { ebt_print_error("Couldn't open file %s", filename); - if (fwrite(data, sizeof(char), size, file) != size) { - fclose(file); + goto free_data; + } else if (fwrite(data, sizeof(char), size, file) != size) ebt_print_error("Couldn't write everything to file %s", filename); - } fclose(file); +free_data: free(data); +free_command: + free(command); } void ebt_deliver_table(struct ebt_u_replace *u_repl) @@ -261,19 +270,20 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl) socklen_t optlen; struct ebt_replace *repl; - /* translate the struct ebt_u_replace to a struct ebt_replace */ + /* Translate the struct ebt_u_replace to a struct ebt_replace */ repl = translate_user2kernel(u_repl); if (u_repl->filename != NULL) { store_table_in_file(u_repl->filename, repl); return; } - /* give the data to the kernel */ + /* Give the data to the kernel */ optlen = sizeof(struct ebt_replace) + repl->entries_size; - get_sockfd(); + if (get_sockfd()) + return; if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen)) return; - if (u_repl->command == 8) { /* the ebtables module may not - * yet be loaded with --atomic-commit */ + if (u_repl->command == 8) { /* The ebtables module may not + * yet be loaded with --atomic-commit */ ebtables_insmod("ebtables"); if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen)) @@ -285,41 +295,46 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl) " the extension"); } -static void store_counters_in_file(char *filename, struct ebt_u_replace *repl) +static int store_counters_in_file(char *filename, struct ebt_u_replace *repl) { - int size = repl->nentries * sizeof(struct ebt_counter); + int size = repl->nentries * sizeof(struct ebt_counter), ret = 0; unsigned int entries_size; struct ebt_replace hlp; FILE *file; - if (!(file = fopen(filename, "r+b"))) + if (!(file = fopen(filename, "r+b"))) { ebt_print_error("Could not open file %s", filename); - /* - * find out entries_size and then set the file pointer to the - * counters - */ + return -1; + } + /* 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); ebt_print_error("File %s is corrupt", filename); + ret = -1; + goto close_file; } if (fwrite(repl->counters, sizeof(char), size, file) != size) { - fclose(file); ebt_print_error("Could not write everything to file %s", filename); + ret = -1; } +close_file: fclose(file); + return 0; } -/* gets executed after ebt_deliver_table */ -void ebt_deliver_counters(struct ebt_u_replace *u_repl) +/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel + * and resets the counterchanges to CNT_NORM */ +void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style) { struct ebt_counter *old, *new, *newcounters; socklen_t optlen; struct ebt_replace repl; - struct ebt_cntchanges *cc = u_repl->counterchanges; + struct ebt_cntchanges *cc = u_repl->counterchanges, *cc2, **cc3; + int i; if (u_repl->nentries == 0) return; @@ -333,24 +348,22 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl) new = newcounters; while (cc) { if (cc->type == CNT_NORM) { - /* - *'normal' rule, meaning we didn't do anything to it - * So, we just copy - */ + /* 'Normal' rule, meaning we didn't do anything to it + * So, we just copy */ new->pcnt = old->pcnt; new->bcnt = old->bcnt; - /* we've used an old counter */ + /* We've used an old counter */ old++; - /* we've set a new counter */ + /* We've set a new counter */ new++; } else if (cc->type == CNT_DEL) { - /* don't use this old counter */ + /* Don't use this old counter */ old++; } else if (cc->type == CNT_ADD) { - /* new counter, let it stay 0 */ + /* New counter, let it stay 0 */ new++; } else { - /* zero it (let it stay 0) */ + /* Zero it (let it stay 0) */ old++; new++; } @@ -366,20 +379,38 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl) } optlen = u_repl->nentries * sizeof(struct ebt_counter) + sizeof(struct ebt_replace); - /* now put the stuff in the kernel's struct ebt_replace */ + /* Now put the stuff in the kernel's struct ebt_replace */ repl.counters = sparc_cast u_repl->counters; repl.num_counters = u_repl->num_counters; memcpy(repl.name, u_repl->name, sizeof(repl.name)); - get_sockfd(); + if (get_sockfd()) + return; if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen)) ebt_print_bug("Couldn't update kernel counters"); + + if (exec_style != EXEC_STYLE_DAEMON) + return; + /* Reset the counterchanges to CNT_NORM */ + cc = u_repl->counterchanges; + for (i = 0; i < u_repl->nentries; i++) { + cc->type = CNT_NORM; + cc3 = &cc->next; + cc = cc->next; + } + *cc3 = NULL; + while (cc) { + cc2 = cc->next; + free(cc); + cc = cc2; + } } static int ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l) { struct ebt_u_match_list *new; + int ret = 0; new = (struct ebt_u_match_list *) malloc(sizeof(struct ebt_u_match_list)); @@ -393,10 +424,12 @@ ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l) new->next = NULL; **l = new; *l = &new->next; - if (ebt_find_match(new->m->u.name) == NULL) + if (ebt_find_match(new->m->u.name) == NULL) { ebt_print_error("Kernel match %s unsupported by userspace tool", new->m->u.name); - return 0; + ret = -1; + } + return ret; } static int @@ -404,6 +437,7 @@ ebt_translate_watcher(struct ebt_entry_watcher *w, struct ebt_u_watcher_list ***l) { struct ebt_u_watcher_list *new; + int ret = 0; new = (struct ebt_u_watcher_list *) malloc(sizeof(struct ebt_u_watcher_list)); @@ -417,10 +451,12 @@ ebt_translate_watcher(struct ebt_entry_watcher *w, new->next = NULL; **l = new; *l = &new->next; - if (ebt_find_watcher(new->w->u.name) == NULL) + if (ebt_find_watcher(new->w->u.name) == NULL) { ebt_print_error("Kernel watcher %s unsupported by userspace " "tool", new->w->u.name); - return 0; + ret = -1; + } + return ret; } static int @@ -428,7 +464,7 @@ 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, char *base) { - /* an entry */ + /* An entry */ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) { struct ebt_u_entry *new; struct ebt_u_match_list **m_l; @@ -440,7 +476,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, ebt_print_memory(); new->bitmask = e->bitmask; /* - * plain userspace code doesn't know about + * Plain userspace code doesn't know about * EBT_ENTRY_OR_ENTRIES */ new->bitmask &= ~EBT_ENTRY_OR_ENTRIES; @@ -467,12 +503,14 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, malloc(t->target_size + sizeof(struct ebt_entry_target)); if (!new->t) ebt_print_memory(); - if (ebt_find_target(t->u.name) == NULL) + if (ebt_find_target(t->u.name) == NULL) { ebt_print_error("Kernel target %s unsupported by " "userspace tool", t->u.name); + return -1; + } memcpy(new->t, t, t->target_size + sizeof(struct ebt_entry_target)); - /* deal with jumps to udc */ + /* Deal with jumps to udc */ if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) { char *tmp = base; int verdict = ((struct ebt_standard_target *)t)->verdict; @@ -488,7 +526,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, cl = cl->next; } if (!cl) - ebt_print_bug("can't find udc for " + ebt_print_bug("Can't find udc for " "jump"); ((struct ebt_standard_target *)new->t)->verdict = i; } @@ -500,7 +538,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, (*cnt)++; (*totalcnt)++; return 0; - } else { /* a new chain */ + } else { /* A new chain */ int i; struct ebt_entries *entries = (struct ebt_entries *)e; struct ebt_u_chain_list *cl; @@ -513,8 +551,8 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, if (valid_hooks & (1 << i)) break; *hook = i; - /* makes use of fact that standard chains come before udc */ - if (i >= NF_BR_NUMHOOKS) { /* udc */ + /* 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) @@ -526,7 +564,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, } } -/* initialize all chain headers */ +/* 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) @@ -540,10 +578,10 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, 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 */ + /* 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 */ + /* Add in the back */ while (*chain_list) chain_list = &((*chain_list)->next); *chain_list = (struct ebt_u_chain_list *) @@ -556,10 +594,8 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, if (!((*chain_list)->udc)) ebt_print_memory(); new = (*chain_list)->udc; - /* - * ebt_translate_entry depends on this for knowing - * to which chain is being jumped - */ + /* ebt_translate_entry depends on this for knowing + * to which chain is being jumped */ (*chain_list)->kernel_start = (char *)e; } else { *hook = i; @@ -578,19 +614,19 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, return 0; } -static void retrieve_from_file(char *filename, struct ebt_replace *repl, +static int retrieve_from_file(char *filename, struct ebt_replace *repl, char command) { FILE *file; char *hlp = NULL, *entries; struct ebt_counter *counters; - int size; + int size, ret = 0; - if (!(file = fopen(filename, "r+b"))) + if (!(file = fopen(filename, "r+b"))) { ebt_print_error("Could not open file %s", filename); - /* - * make sure table name is right if command isn't -L or --atomic-commit - */ + return -1; + } + /* 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) + 1); if (!hlp) @@ -598,25 +634,30 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, strcpy(hlp, repl->name); } if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file) - != sizeof(struct ebt_replace)) + != sizeof(struct ebt_replace)) { ebt_print_error("File %s is corrupt", filename); + ret = -1; + goto close_file; + } if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) { - fclose(file); ebt_print_error("File %s contains wrong table name or is " "corrupt", filename); - free(hlp); + ret = -1; + goto close_file; } else if (!ebt_find_table(repl->name)) { - fclose(file); ebt_print_error("File %s contains invalid table name", filename); + ret = -1; + goto close_file; } 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); ebt_print_error("File %s has wrong size", filename); + ret -1; + goto close_file; } entries = (char *)malloc(repl->entries_size); if (!entries) @@ -630,7 +671,7 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, ebt_print_memory(); } else repl->counters = sparc_cast NULL; - /* copy entries and counters */ + /* Copy entries and counters */ if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) || fread((char *)repl->entries, sizeof(char), repl->entries_size, file) != repl->entries_size || @@ -639,10 +680,15 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, || fread((char *)repl->counters, sizeof(char), repl->nentries * sizeof(struct ebt_counter), file) != repl->nentries * sizeof(struct ebt_counter)) { - fclose(file); ebt_print_error("File %s is corrupt", filename); + free(entries); + repl->entries = NULL; + ret = -1; } +close_file: fclose(file); + free(hlp); + return ret; } static int retrieve_from_kernel(struct ebt_replace *repl, char command, @@ -653,7 +699,8 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, char *entries; optlen = sizeof(struct ebt_replace); - get_sockfd(); + if (get_sockfd()) + return -1; /* --atomic-init || --init-table */ if (init) optname = EBT_SO_GET_INIT_INFO; @@ -676,7 +723,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, else repl->counters = sparc_cast NULL; - /* we want to receive the counters */ + /* We want to receive the counters */ repl->num_counters = repl->nentries; optlen += repl->entries_size + repl->num_counters * sizeof(struct ebt_counter); @@ -685,7 +732,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, else optname = EBT_SO_GET_ENTRIES; if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen)) - ebt_print_bug("hmm, what is wrong??? bug#1"); + ebt_print_bug("Hmm, what is wrong??? bug#1"); return 0; } @@ -701,17 +748,16 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init) strcpy(repl.name, u_repl->name); if (u_repl->filename != NULL) { if (init) - ebt_print_bug("getting initial table data from a " + ebt_print_bug("Getting initial table data from a " "file is impossible"); - retrieve_from_file(u_repl->filename, &repl, u_repl->command); - /* - * -L with a wrong table name should be dealt with silently - */ + if (retrieve_from_file(u_repl->filename, &repl, u_repl->command)) + return -1; + /* -L with a wrong table name should be dealt with silently */ strcpy(u_repl->name, repl.name); - } else if (retrieve_from_kernel(&repl, u_repl->command, init) == -1) + } else if (retrieve_from_kernel(&repl, u_repl->command, init)) return -1; - /* translate the struct ebt_replace to a struct ebt_u_replace */ + /* Translate the struct ebt_replace to a struct ebt_u_replace */ u_repl->valid_hooks = repl.valid_hooks; u_repl->nentries = repl.nentries; u_repl->num_counters = repl.num_counters; @@ -729,14 +775,13 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init) prev_cc = &(new_cc->next); } hook = -1; + /* FIXME: Clean up when an error is encountered */ 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 */ - /* - * holds the total nr. of entries, - * should equal u_repl->nentries afterwards - */ + i = 0; /* Holds the expected nr. of entries for the chain */ + j = 0; /* Holds the up to now counted entries for the chain */ + /* Holds the total nr. of entries, + * should equal u_repl->nentries afterwards */ k = 0; hook = -1; EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size, diff --git a/ebtables-standalone.c b/ebtables-standalone.c new file mode 100644 index 0000000..d349d39 --- /dev/null +++ b/ebtables-standalone.c @@ -0,0 +1,14 @@ +#include +#include "include/ebtables_u.h" + +static struct ebt_u_replace replace; +void ebt_early_init_once(); + +int main(int argc, char *argv[]) +{ + ebt_silent = 0; + ebt_early_init_once(); + strcpy(replace.name, "filter"); + do_command(argc, argv, EXEC_STYLE_PRG, &replace); + return 0; +} diff --git a/ebtables.8 b/ebtables.8 index 24a27a4..1dc8cd5 100644 --- a/ebtables.8 +++ b/ebtables.8 @@ -24,31 +24,43 @@ .\" .\" .SH NAME -ebtables (v.2.0.7) \- Ethernet bridge frame table administration +ebtables (v.2.0.7), ebtablesd, ebtablesu \- Ethernet bridge frame table administration .SH SYNOPSIS -.BR "ebtables " [ "-t table" ] " -" [ ADI ] " chain rule specification " [ "match extensions" "] [" "watcher extensions" ] " target" +.BR "ebtables " [ -t " table ] " - [ ADI "] chain rule specification [match extensions] [watcher extensions] target" .br -.BR "ebtables " [ "-t table" ] " -P chain ACCEPT " | " DROP " | " RETURN" +.BR "ebtables " [ -t " table ] " -P " chain " ACCEPT " | " DROP " | " RETURN .br -.BR "ebtables " [ "-t table" ] " -F " [ chain ] +.BR "ebtables " [ -t " table ] " -F " [chain]" .br -.BR "ebtables " [ "-t table" ] " -Z " [ chain ] +.BR "ebtables " [ -t " table ] " -Z " [chain]" .br -.BR "ebtables " [ "-t table" ] " -L " [ -Z "] [" " chain" "] [ [ [" --Ln "] [" --Lc "] ] | [" --Lx "] ] [" --Lmac2 "]" +.BR "ebtables " [ -t " table ] " -L " [" -Z "] [chain] [ [ [" --Ln "] [" --Lc "] ] | [" --Lx "] ] [" --Lmac2 ] .br -.BR "ebtables " [ "-t table" ] " -N chain " [ "-P ACCEPT " | " DROP " | " RETURN" ] +.BR "ebtables " [ -t " table ] " -N " chain [" "-P ACCEPT " | " DROP " | " RETURN" ] .br -.BR "ebtables " [ "-t table" ] " -X " [ chain ] +.BR "ebtables " [ -t " table ] " -X " [chain]" .br -.BR "ebtables " [ "-t table" ] " -E old-chain-name new-chain-name" +.BR "ebtables " [ -t " table ] " -E " old-chain-name new-chain-name" .br -.BR "ebtables " [ "-t table" ] " --init-table" +.BR "ebtables " [ -t " table ] " --init-table .br -.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-commit" +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit .br -.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-init" +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init .br -.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-save" +.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save +.br +.BR "ebtablesu open " table +.br +.BR "ebtablesu fopen " "table file" +.br +.BR "ebtablesu free " table +.br +.BR "ebtablesu commit " table +.br +.BR "ebtablesu fcommit " "table file" +.br +.B ebtablesu quit .br .SH DESCRIPTION .B ebtables @@ -59,6 +71,52 @@ It is analogous to the .B iptables application, but less complicated, due to the fact that the Ethernet protocol is much simpler than the IP protocol. +.br +.BR ebtablesu " and " ebtablesd " can be used to speed up adding rules using a script when the" +.B --atomic-commit +option is not satisfactory. The +.BR open " command makes ebtablesd open the specified kernel table for processing" +.BR "" "in userspace (multiple tables can be open in the same time). The " fopen +command opens the table from the specified file. +.BR "" "The " free " command removes the specified table out of the memory of ebtablesd." +No data is written to a file or to the kernel. +.BR "" "The " commit " command stores the table from the memory of ebtablesd to the kernel." +.BR "" "The " fcommit " command stores the table from the memory of ebtablesd to the specified file." +This file can be read later, e.g. with +.BR "ebtables --atomic-file " file " -L" . +.BR "" "The " quit " command lets ebtablesd finish gracefully." +All commands, options and extensions that ebtables uses can be used with ebtablesu, except for +.BR --init-table ", " --atomic-file ", " --atomic-commit ", " --atomic-init ", " --atomic-save " and " -h . +.br +Example usage: +.br +# ebtablesd& +.br +# ebtablesu open filter +.br +# ebtablesu -A FORWARD -j DROP +.br +# ebtablesu commit filter +.br +# ebtablesu quit +.br +Alternatively, the commands can be echo'ed directly to the pipe used by ebtablesd, +which has default location /tmp/ebtables-vx.y.z/ebtablesd_pipe, where +x.y.z is the ebtables version (e.g. 2.0.7). Using echo instead of ebtablesu is +much faster because echo is a bash built-in command. Commands like cat can be used +too, of course. +.br +Example usage: +.br +# (./ebtablesd&) ; PIPE=/tmp/ebtables-v2.0.7/ebtablesd_pipe ; sleep 1 +.br +# echo "ebtablesu open filter" >> $PIPE +.br +# echo "ebtablesu -A FORWARD -j DROP" >> $PIPE +.br +# echo "ebtablesu commit filter" >> $PIPE +.br +# echo "ebtablesu quit" >> $PIPE .SS CHAINS There are three ebtables tables with built-in chains in the Linux kernel. These tables are used to divide functionality into diff --git a/ebtables.c b/ebtables.c index 8b0dd80..2d0cd61 100644 --- a/ebtables.c +++ b/ebtables.c @@ -3,7 +3,7 @@ * * Author: Bart De Schuymer * - * This code is stongly inspired on the iptables code which is + * This code was stongly inspired on the iptables code which is * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling * * This program is free software; you can redistribute it and/or @@ -33,11 +33,8 @@ #include #include -/* - * default command line options - * do not mess around with the already assigned numbers unless - * you know what you are doing - */ +/* dDfault command line 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' }, @@ -82,29 +79,23 @@ static struct option ebt_original_options[] = static struct option *ebt_options = ebt_original_options; -/* - * holds all the data - */ -static struct ebt_u_replace replace; +/* Holds all the data */ +static struct ebt_u_replace *replace; -/* - * the chosen table - */ +/* The chosen table */ static struct ebt_u_table *table = NULL; -/* - * The pointers in here are special: +/* The pointers in here are special: * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer. * instead of making yet a few other structs, we just do a cast. * We need a struct ebt_u_target pointer because we know the address of the data * they point to won't change. We want to allow that the struct ebt_u_target.t * member can change. - * Same holds for the struct ebt_match and struct ebt_watcher pointers - */ -struct ebt_u_entry *new_entry; + * Same holds for the struct ebt_match and struct ebt_watcher pointers */ +static struct ebt_u_entry *new_entry; -static int global_option_offset = 0; +static int global_option_offset; #define OPTION_OFFSET 256 static struct option * merge_options(struct option *oldopts, const struct option *newopts, @@ -130,7 +121,7 @@ merge_options(struct option *oldopts, const struct option *newopts, merge[num_old + i].val += *options_offset; } memset(merge + num_old + num_new, 0, sizeof(struct option)); - /* only free dynamically allocated stuff */ + /* Only free dynamically allocated stuff */ if (oldopts != ebt_original_options) free(oldopts); @@ -155,7 +146,7 @@ static void merge_target(struct ebt_u_target *t) (ebt_options, t->extra_ops, &(t->option_offset)); } -/* be backwards compatible, so don't use '+' in kernel */ +/* Be backwards compatible, so don't use '+' in kernel */ #define IF_WILDCARD 1 static void print_iface(const char *iface) { @@ -168,18 +159,14 @@ static void print_iface(const char *iface) *c = IF_WILDCARD; } -/* - * we use replace.flags, so we can't use the following values: - * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO - */ +/* 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 #define LIST_MAC2 0x20 -/* - * helper function for list_rules() - */ +/* Helper function for list_rules() */ static void list_em(struct ebt_u_entries *entries) { int i, j, space = 0, digits; @@ -190,13 +177,13 @@ static void list_em(struct ebt_u_entries *entries) struct ebt_u_watcher *w; struct ebt_u_target *t; - if (replace.flags & LIST_MAC2) + if (replace->flags & LIST_MAC2) ebt_printstyle_mac = 2; hlp = entries->entries; - if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) { - printf("ebtables -t %s -P %s %s\n", replace.name, + if (replace->flags & LIST_X && entries->policy != EBT_ACCEPT) { + printf("ebtables -t %s -P %s %s\n", replace->name, entries->name, ebt_standard_targets[-entries->policy - 1]); - } else if (!(replace.flags & LIST_X)) { + } else if (!(replace->flags & LIST_X)) { printf("\nBridge chain: %s, entries: %d, policy: %s\n", entries->name, entries->nentries, ebt_standard_targets[-entries->policy - 1]); @@ -209,7 +196,7 @@ static void list_em(struct ebt_u_entries *entries) } for (i = 0; i < entries->nentries; i++) { - if (replace.flags & LIST_N) { + if (replace->flags & LIST_N) { digits = 0; /* A little work to get nice rule numbers. */ j = i + 1; @@ -221,18 +208,16 @@ static void list_em(struct ebt_u_entries *entries) printf(" "); printf("%d. ", i + 1); } - if (replace.flags & LIST_X) + if (replace->flags & LIST_X) printf("ebtables -t %s -A %s ", - replace.name, entries->name); + replace->name, entries->name); /* The standard target's print() uses this to find out * the name of a udc */ - hlp->replace = &replace; + hlp->replace = replace; - /* - * Don't print anything about the protocol if no protocol was - * specified, obviously this means any protocol will do. - */ + /* 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("-p "); if (hlp->invflags & EBT_IPROTO) @@ -311,12 +296,12 @@ static void list_em(struct ebt_u_entries *entries) printf("%s ", hlp->t->u.name); t = ebt_find_target(hlp->t->u.name); if (!t) - ebt_print_bug("Target not found"); + ebt_print_bug("Target '%s' not found", hlp->t->u.name); t->print(hlp, hlp->t); - if (replace.flags & LIST_C) + if (replace->flags & LIST_C) printf(", pcnt = %llu -- bcnt = %llu", - replace.counters[entries->counter_offset + i].pcnt, - replace.counters[entries->counter_offset + i].bcnt); + replace->counters[entries->counter_offset + i].pcnt, + replace->counters[entries->counter_offset + i].bcnt); printf("\n"); hlp = hlp->next; } @@ -356,10 +341,10 @@ static void print_help() "--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n" "--src -s [!] address[/mask]: source mac address\n" "--dst -d [!] address[/mask]: destination mac address\n" -"--in-if -i [!] name : network input interface name\n" -"--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" +"--in-if -i [!] name[+] : network input interface name\n" +"--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 program : try to insert modules using this program\n" "--version -V : print package version\n\n" "Environment variable:\n" @@ -384,43 +369,39 @@ ATOMIC_ENV_VARIABLE " : if set (see above) will equal its value" exit(0); } -/* - * execute command L - */ +/* Execute command L */ static void list_rules() { int i; - if (!(replace.flags & LIST_X)) + if (!(replace->flags & LIST_X)) printf("Bridge table: %s\n", table->name); - if (replace.selected_chain != -1) { - list_em(ebt_to_chain(&replace)); + if (replace->selected_chain != -1) { + list_em(ebt_to_chain(replace)); } else { - struct ebt_u_chain_list *cl = replace.udc; + struct ebt_u_chain_list *cl = replace->udc; - /* - * create new chains and rename standard chains when necessary - */ - if (replace.flags & LIST_X) { + /* 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, + printf("ebtables -t %s -N %s\n", replace->name, cl->udc->name); cl = cl->next; } - cl = replace.udc; + cl = replace->udc; for (i = 0; i < NF_BR_NUMHOOKS; i++) - if (replace.valid_hooks & (1 << i) && - strcmp(replace.hook_entry[i]->name, + if (replace->valid_hooks & (1 << i) && + strcmp(replace->hook_entry[i]->name, ebt_hooknames[i])) printf("ebtables -t %s -E %s %s\n", - replace.name, ebt_hooknames[i], - replace.hook_entry[i]->name); + replace->name, ebt_hooknames[i], + replace->hook_entry[i]->name); } i = 0; while (1) { if (i < NF_BR_NUMHOOKS) { - if (replace.valid_hooks & (1 << i)) - list_em(replace.hook_entry[i]); + if (replace->valid_hooks & (1 << i)) + list_em(replace->hook_entry[i]); i++; continue; } else { @@ -440,7 +421,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end) if (colon) { *colon = '\0'; if (*(colon + 1) == '\0') - *rule_nr_end = -1; /* until the last rule */ + *rule_nr_end = -1; /* Until the last rule */ else { *rule_nr_end = strtol(colon + 1, &buffer, 10); if (*buffer != '\0' || *rule_nr_end == 0) @@ -448,7 +429,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end) } } if (colon == argv) - *rule_nr = 1; /* beginning with the first rule */ + *rule_nr = 1; /* Beginning with the first rule */ else { *rule_nr = strtol(argv, &buffer, 10); if (*buffer != '\0' || *rule_nr == 0) @@ -459,7 +440,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end) return 0; } -static void parse_iface(char *iface, char *option) +static int parse_iface(char *iface, char *option) { char *c; @@ -467,15 +448,33 @@ static void parse_iface(char *iface, char *option) if (*(c + 1) != '\0') { ebt_print_error("Spurious characters after '+' " "wildcard for %s", option); + return -1; } else *c = IF_WILDCARD; } + return 0; +} + +void ebt_early_init_once() +{ + ebt_iterate_matches(merge_match); + ebt_iterate_watchers(merge_watcher); + ebt_iterate_targets(merge_target); } -#define print_if_l_error ebt_print_error("Interface name length must be less " \ - "than %d", IFNAMSIZ) -#define print_epoto_error(__proto) ebt_print_error("Problem with the specified"\ - " Ethernet protocol (%s), perhaps "_PATH_ETHERTYPES " is missing", __proto); +#define ebt_print_error2(format, args...) {__ebt_print_error(format, ##args); \ + return -1;} +#define ebt_check_option2(flags,mask) \ +({ebt_check_option(flags,mask); \ + if (ebt_errormsg[0] != '\0') \ + return -1;}) +#define ebt_check_inverse2(option) \ +({int __ret = ebt_check_inverse(option); \ +if (ebt_errormsg[0] != '\0') \ + return -1; \ +__ret;}) +#define OPT_COMMANDS (replace->flags & OPT_COMMAND || replace->flags & OPT_ZERO) + #define OPT_COMMAND 0x01 #define OPT_TABLE 0x02 #define OPT_IN 0x04 @@ -487,20 +486,17 @@ static void parse_iface(char *iface, char *option) #define OPT_ZERO 0x100 #define OPT_LOGICALIN 0x200 #define OPT_LOGICALOUT 0x400 -#define OPT_KERNELDATA 0x800 /* if set, we already have loaded the table - * in userspace */ -/* the main thing */ -int main(int argc, char *argv[]) +#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */ +int do_command(int argc, char *argv[], int exec_style, + struct ebt_u_replace *replace_) { char *buffer; int c, i; - /* - * this special one for the -Z option (we can have -Z -L ) - */ + /* Needed for the -Z option (we can have -Z -L ) */ int zerochain = -1; int policy = 0; - int rule_nr = 0; /* used for -[D,I] */ - int rule_nr_end = 0; /* used for -I */ + int rule_nr = 0; + int rule_nr_end = 0; struct ebt_u_target *t; struct ebt_u_match *m; struct ebt_u_watcher *w; @@ -509,592 +505,476 @@ int main(int argc, char *argv[]) struct ebt_u_entries *entries; opterr = 0; + ebt_modprobe = NULL; + + replace = replace_; + + /* The daemon doesn't use the environment variable */ + if (exec_style == EXEC_STYLE_PRG) { + buffer = getenv(ATOMIC_ENV_VARIABLE); + if (buffer) { + replace->filename = malloc(strlen(buffer) + 1); + if (!replace->filename) + ebt_print_memory(); + strcpy(replace->filename, buffer); + buffer = NULL; + } + } - ebt_iterate_matches(merge_match); - ebt_iterate_watchers(merge_watcher); - ebt_iterate_targets(merge_target); + replace->flags &= OPT_KERNELDATA; /* ebtablesd needs OPT_KERNELDATA */ + replace->selected_chain = -1; + replace->command = 'h'; - buffer = getenv(ATOMIC_ENV_VARIABLE); - if (buffer) { - replace.filename = malloc(strlen(buffer)+1); - if (!replace.filename) + if (!new_entry) { + new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); + if (!new_entry) ebt_print_memory(); - memcpy(replace.filename, buffer, strlen(buffer)+1); - buffer = NULL; } - /* - * initialize the table name, OPT_ flags, selected hook and command - */ - strcpy(replace.name, "filter"); - replace.flags = 0; - replace.selected_chain = -1; - replace.command = 'h'; - replace.counterchanges = NULL; - - new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); - if (!new_entry) - ebt_print_memory(); - /* - * put some sane values in our new entry - */ + /* Put some sane values in our new entry */ ebt_initialize_entry(new_entry); - new_entry->replace = &replace; + new_entry->replace = replace; - /* - * The scenario induced by this loop makes that: + /* The scenario induced by this loop makes that: * '-t' ,'-M' and --atomic (if specified) have to come - * before '-A' and the like - */ + * before '-A' and the like */ - /* - * getopt saves the day - */ + /* Getopt saves the day */ while ((c = getopt_long(argc, argv, "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:p: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 */ + 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 */ /* We allow -N chainname -P policy */ - if (replace.command == 'N' && c == 'P') { - replace.command = c; - optind--; + if (replace->command == 'N' && c == 'P') { + replace->command = c; + optind--; /* No table specified */ goto handle_P; } - replace.command = c; - replace.flags |= OPT_COMMAND; - if (!(replace.flags & OPT_KERNELDATA)) { - ebt_get_kernel_table(&replace, table, 0); - replace.flags |= OPT_KERNELDATA; - } - if (optarg && (optarg[0] == '-' || - !strcmp(optarg, "!"))) - ebt_print_error("No chain name specified"); + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + + replace->command = c; + replace->flags |= OPT_COMMAND; + if (!(replace->flags & OPT_KERNELDATA)) + ebt_get_kernel_table(replace, 0); + if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!"))) + ebt_print_error2("No chain name specified"); if (c == 'N') { - ebt_new_chain(&replace, optarg, EBT_ACCEPT); + ebt_new_chain(replace, optarg, EBT_ACCEPT); /* This is needed to get -N x -P y working */ - replace.selected_chain = - ebt_get_chainnr(&replace, optarg); + replace->selected_chain = ebt_get_chainnr(replace, optarg); break; - } - if (c == 'X') { - char *opt; - - if (!optarg && (optind >= argc || - (argv[optind][0] == '-' - && strcmp(argv[optind], "!")))) { - replace.selected_chain = -1; - ebt_delete_chain(&replace); + } else if (c == 'X') { + if (optind >= argc) { + replace->selected_chain = -1; + ebt_delete_chain(replace); break; } - if (optarg) - opt = optarg; - else { - opt = argv[optind]; - optind++; - } - if ((replace.selected_chain = - ebt_get_chainnr(&replace, opt)) == -1) - ebt_print_error("Chain %s doesn't " - "exist", opt); - ebt_delete_chain(&replace); + + if (optind < argc - 1) + ebt_print_error2("No extra options allowed with -X"); + + if ((replace->selected_chain = ebt_get_chainnr(replace, argv[optind])) == -1) + ebt_print_error2("Chain %s doesn't exist", argv[optind]); + ebt_delete_chain(replace); + if (ebt_errormsg[0] != '\0') + return -1; + optind++; break; } - if ((replace.selected_chain = - ebt_get_chainnr(&replace, optarg)) == -1) - ebt_print_error("Chain %s doesn't exist", - optarg); + if ((replace->selected_chain = ebt_get_chainnr(replace, optarg)) == -1) + ebt_print_error2("Chain %s doesn't exist", optarg); if (c == 'E') { - if (optind >= argc || argv[optind][0] == '-' || - !strcmp(argv[optind], "!")) - ebt_print_error("No new chain name " - "specified"); + if (optind >= argc) + ebt_print_error2("No new chain name specified"); + if (optind < argc - 1) + ebt_print_error2("No extra options allowed with -E"); if (strlen(argv[optind])>=EBT_CHAIN_MAXNAMELEN) - ebt_print_error("Chain name len can't " - "exceed %d", - EBT_CHAIN_MAXNAMELEN - 1); - if (ebt_get_chainnr(&replace, argv[optind]) != - -1) - ebt_print_error("Chain %s already " - "exists", argv[optind]); + ebt_print_error2("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); + if (ebt_get_chainnr(replace, argv[optind]) != -1) + ebt_print_error2("Chain %s already exists", argv[optind]); if (ebt_find_target(argv[optind])) - ebt_print_error("Target with name %s " - "exists", argv[optind]); - ebt_rename_chain(&replace, argv[optind]); + ebt_print_error2("Target with name %s exists", argv[optind]); + ebt_rename_chain(replace, argv[optind]); optind++; break; - } - - if (c == 'D' && optind < argc && - (argv[optind][0] != '-' || - (argv[optind][1] >= '0' && - argv[optind][1] <= '9'))) { - if (parse_delete_rule(argv[optind], - &rule_nr, &rule_nr_end)) - ebt_print_error("Problem with the " - "specified rule number(s)"); + } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { + if (optind != argc - 1) + ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]"); + if (parse_delete_rule(argv[optind], &rule_nr, &rule_nr_end)) + ebt_print_error2("Problem with the specified rule number(s)"); optind++; - } - if (c == 'I') { - if (optind >= argc || - (argv[optind][0] == '-' && - (argv[optind][1] < '0' || - argv[optind][1] > '9'))) - ebt_print_error("No rulenr for -I" - " specified"); + } else if (c == 'I') { + if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) + ebt_print_error2("No rulenr for -I specified"); rule_nr = strtol(argv[optind], &buffer, 10); if (*buffer != '\0') - ebt_print_error("Problem with the " - "specified rule number"); + ebt_print_error2("Problem with the specified rule number"); optind++; - } - if (c == 'P') { + } else if (c == 'P') { handle_P: if (optind >= argc) - ebt_print_error("No policy specified"); - policy = 0; + ebt_print_error2("No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) - if (!strcmp(argv[optind], - ebt_standard_targets[i])) { + if (!strcmp(argv[optind], ebt_standard_targets[i])) { policy = -i -1; if (policy == EBT_CONTINUE) - policy = 0; + ebt_print_error2("Wrong policy: '%s'", argv[optind]); break; } - if (policy == 0) - ebt_print_error("Wrong policy"); optind++; } break; - - case 'L': /* list */ - case 'F': /* flush */ - case 'Z': /* zero counters */ + case 'L': /* List */ + case 'F': /* Flush */ + case 'Z': /* Zero counters */ if (c == 'Z') { - if (replace.flags & OPT_ZERO) - ebt_print_error("Multiple commands" - " not allowed"); - if ( (replace.flags & OPT_COMMAND && - replace.command != 'L')) - ebt_print_error("command -Z only " - "allowed together with command -L"); - replace.flags |= OPT_ZERO; + if ((replace->flags & OPT_ZERO) || (replace->flags & OPT_COMMAND && replace->command != 'L')) +print_zero: + ebt_print_error2("Command -Z only allowed together with command -L"); + replace->flags |= OPT_ZERO; } else { - replace.command = c; - if (replace.flags & OPT_COMMAND) - ebt_print_error("Multiple commands" - " not allowed"); - replace.flags |= OPT_COMMAND; + replace->command = c; + if (replace->flags & OPT_COMMAND) + ebt_print_error2("Multiple commands are not allowed"); + replace->flags |= OPT_COMMAND; + if (replace->flags & OPT_ZERO) + goto print_zero; } - ebt_get_kernel_table(&replace, table, 0); + +#ifdef SILENT_DAEMON + if (c== 'L' && exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("-L not supported in daemon mode not supported in daemon mode"); +#endif + + if (!(replace->flags & OPT_KERNELDATA)) + ebt_get_kernel_table(replace, 0); i = -1; - if (optarg) { - if ( (i = ebt_get_chainnr(&replace, optarg)) == - -1 ) - ebt_print_error("Bad chain"); - } else - if (optind < argc && argv[optind][0] != '-') { - if ((i = ebt_get_chainnr(&replace, - argv[optind])) == -1) - ebt_print_error("Bad chain"); - optind++; - } + if (optind < argc && argv[optind][0] != '-') { + if ((i = ebt_get_chainnr(replace, argv[optind])) == -1) + ebt_print_error2("Bad chain"); + optind++; + } if (i != -1) { if (c == 'Z') zerochain = i; else - replace.selected_chain = i; + replace->selected_chain = i; } break; - - case 'V': /* version */ - replace.command = 'V'; - if (replace.flags & OPT_COMMAND) - ebt_print_error("Multiple commands not " - "allowed"); + case 'V': /* Version */ + replace->command = 'V'; + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"); PRINT_VERSION; exit(0); - - case 'M': /* modprobe */ - if (replace.command != 'h') - ebt_print_error("Please put the -M option " - "earlier"); + case 'M': /* Modprobe */ + if (OPT_COMMANDS) + ebt_print_error2("Please put the -M option earlier"); ebt_modprobe = optarg; break; - - case 'h': /* help */ - if (replace.flags & OPT_COMMAND) - ebt_print_error("Multiple commands not " - "allowed"); - replace.command = 'h'; - /* - * All other arguments should be extension names - */ + case 'h': /* Help */ + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("-h not supported in daemon mode"); + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + replace->command = 'h'; + + /* All other arguments should be extension names */ while (optind < argc) { struct ebt_u_match *m; struct ebt_u_watcher *w; - if (!strcasecmp("list_extensions", - argv[optind])) + if (!strcasecmp("list_extensions", argv[optind])) { ebt_list_extensions(); - + exit(0); + } if ((m = ebt_find_match(argv[optind]))) ebt_add_match(new_entry, m); else if ((w = ebt_find_watcher(argv[optind]))) ebt_add_watcher(new_entry, w); else { if (!(t = ebt_find_target(argv[optind]))) - ebt_print_error("Extension %s " - "not found", argv[optind]); - if (replace.flags & OPT_JUMP) - ebt_print_error("Sorry, you " - "can only see help for one " - "target extension each time"); - replace.flags |= OPT_JUMP; - new_entry->t = - (struct ebt_entry_target *)t; + ebt_print_error2("Extension %s not found", argv[optind]); + if (replace->flags & OPT_JUMP) + ebt_print_error2("Sorry, you can only see help for one target extension at a time"); + replace->flags |= OPT_JUMP; + new_entry->t = (struct ebt_entry_target *)t; } optind++; } break; - - case 't': /* table */ - if (replace.command != 'h') - ebt_print_error("Please put the -t option " - "first"); - ebt_check_option(&replace.flags, OPT_TABLE); + case 't': /* Table */ + if (replace->command != 'h') + ebt_print_error2("Please put the -t option first"); + ebt_check_option2(&(replace->flags), OPT_TABLE); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) - ebt_print_error("Table name too long"); - strcpy(replace.name, optarg); + ebt_print_error2("Table name too long"); + strcpy(replace->name, optarg); break; - - case 'i': /* input interface */ - case 2 : /* logical input interface */ - case 'o': /* output interface */ - case 3 : /* logical output interface */ - case 'j': /* target */ - case 'p': /* net family protocol */ - case 's': /* source mac */ - case 'd': /* destination mac */ - if ((replace.flags & OPT_COMMAND) == 0) - ebt_print_error("No command specified"); - if ( replace.command != 'A' && - replace.command != 'D' && replace.command != 'I') - ebt_print_error("Command and option do not " - "match"); + case 'i': /* Input interface */ + case 2 : /* Logical input interface */ + case 'o': /* Output interface */ + case 3 : /* Logical output interface */ + case 'j': /* Target */ + case 'p': /* Net family protocol */ + case 's': /* Source mac */ + case 'd': /* Destination mac */ + if (!OPT_COMMANDS) + ebt_print_error2("No command specified"); + if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I') + ebt_print_error2("Command and option do not match"); if (c == 'i') { - ebt_check_option(&replace.flags, OPT_IN); - if (replace.selected_chain > 2 && - replace.selected_chain < NF_BR_BROUTING) - ebt_print_error("Use in-interface " - "only in " - "INPUT, FORWARD, PREROUTING and" - "BROUTING chains"); - if (ebt_check_inverse(optarg)) + ebt_check_option2(&(replace->flags), OPT_IN); + if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) + ebt_print_error2("Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IIN; - if (optind > argc) - ebt_print_error("No in-interface " - "specified"); - if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_if_l_error; - strcpy(new_entry->in, argv[optind - 1]); - parse_iface(new_entry->in, "-i"); + if (strlen(optarg) >= IFNAMSIZ) + ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ); + strcpy(new_entry->in, optarg); + if (parse_iface(new_entry->in, "-i")) + return -1; break; - } - if (c == 2) { - ebt_check_option(&replace.flags, OPT_LOGICALIN); - if (replace.selected_chain > 2 && - replace.selected_chain < NF_BR_BROUTING) - ebt_print_error("Use logical " - "in-interface " - "only in INPUT, FORWARD, " - "PREROUTING and BROUTING chains"); - if (ebt_check_inverse(optarg)) + } else if (c == 2) { + ebt_check_option2(&(replace->flags), OPT_LOGICALIN); + if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) + ebt_print_error2("Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALIN; - if (optind > argc) - ebt_print_error("No logical " - "in-interface specified"); - if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_if_l_error; - strcpy(new_entry->logical_in, argv[optind - 1]); - parse_iface(new_entry->logical_in, - "--logical-in"); + if (strlen(optarg) >= IFNAMSIZ) + ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ); + strcpy(new_entry->logical_in, optarg); + if (parse_iface(new_entry->logical_in, "--logical-in")) + return -1; break; - } - if (c == 'o') { - ebt_check_option(&replace.flags, OPT_OUT); - if (replace.selected_chain < 2) - ebt_print_error("Use out-interface " - "only in OUTPUT, FORWARD and " - "POSTROUTING chains"); - if (ebt_check_inverse(optarg)) + } else if (c == 'o') { + ebt_check_option2(&(replace->flags), OPT_OUT); + if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING) + ebt_print_error2("Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IOUT; - if (optind > argc) - ebt_print_error("No out-interface " - "specified"); - - if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_if_l_error; - strcpy(new_entry->out, argv[optind - 1]); - parse_iface(new_entry->out, "-o"); + if (strlen(optarg) >= IFNAMSIZ) + ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ); + strcpy(new_entry->out, optarg); + if (parse_iface(new_entry->out, "-o")) + return -1; break; - } - if (c == 3) { - ebt_check_option(&replace.flags, - OPT_LOGICALOUT); - if (replace.selected_chain < 2) - ebt_print_error("Use logical " - "out-interface " - "only in OUTPUT, FORWARD and " - "POSTROUTING chains"); - if (ebt_check_inverse(optarg)) + } else if (c == 3) { + ebt_check_option2(&(replace->flags), OPT_LOGICALOUT); + if (replace->selected_chain < 2) + ebt_print_error2("Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALOUT; - if (optind > argc) - ebt_print_error("No logical " - "out-interface specified"); - - if (strlen(argv[optind - 1]) >= IFNAMSIZ) - print_if_l_error; - strcpy(new_entry->logical_out, - argv[optind - 1]); - parse_iface(new_entry->logical_out, - "--logical-out"); + if (strlen(optarg) >= IFNAMSIZ) + ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ); + strcpy(new_entry->logical_out, optarg); + if (parse_iface(new_entry->logical_out, "--logical-out")) + return -1; break; - } - if (c == 'j') { - ebt_check_option(&replace.flags, OPT_JUMP); + } else if (c == 'j') { + ebt_check_option2(&(replace->flags), OPT_JUMP); for (i = 0; i < NUM_STANDARD_TARGETS; i++) - if (!strcmp(optarg, - ebt_standard_targets[i])) { - t = ebt_find_target( - EBT_STANDARD_TARGET); - ((struct ebt_standard_target *) - t->t)->verdict = -i - 1; + if (!strcmp(optarg, ebt_standard_targets[i])) { + t = ebt_find_target(EBT_STANDARD_TARGET); + ((struct ebt_standard_target *) t->t)->verdict = -i - 1; break; } - if (-i - 1 == EBT_RETURN) { - if (replace.selected_chain < - NF_BR_NUMHOOKS) - ebt_print_error("Return target" - " only for user defined " - "chains"); - } - if (i != NUM_STANDARD_TARGETS) + if (-i - 1 == EBT_RETURN && replace->selected_chain < NF_BR_NUMHOOKS) { + ebt_print_error2("Return target only for user defined chains"); + } else if (i != NUM_STANDARD_TARGETS) break; - if ((i = ebt_get_chainnr(&replace, optarg)) != - -1) { + + if ((i = ebt_get_chainnr(replace, optarg)) != -1) { if (i < NF_BR_NUMHOOKS) - ebt_print_error("don't jump" - " to a standard chain"); + ebt_print_error2("Don't jump to a standard chain"); t = ebt_find_target(EBT_STANDARD_TARGET); - ((struct ebt_standard_target *) - t->t)->verdict = i - NF_BR_NUMHOOKS; + ((struct ebt_standard_target *) t->t)->verdict = i - NF_BR_NUMHOOKS; break; } else { - /* - * must be an extension then - */ + /* Must be an extension then */ struct ebt_u_target *t; t = ebt_find_target(optarg); - /* - * -j standard not allowed either - */ - if (!t || t == - (struct ebt_u_target *)new_entry->t) - ebt_print_error("Illegal " - "target name"); - new_entry->t = - (struct ebt_entry_target *)t; + /* -j standard not allowed either */ + if (!t || t == (struct ebt_u_target *)new_entry->t) + ebt_print_error2("Illegal target name"); + new_entry->t = (struct ebt_entry_target *)t; + ebt_find_target(EBT_STANDARD_TARGET)->used = 0; + t->used = 1; } break; - } - if (c == 's') { - ebt_check_option(&replace.flags, OPT_SOURCE); - if (ebt_check_inverse(optarg)) + } else if (c == 's') { + ebt_check_option2(&(replace->flags), OPT_SOURCE); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ISOURCE; - if (optind > argc) - ebt_print_error("No source mac " - "specified"); - if (ebt_get_mac_and_mask(argv[optind - 1], - new_entry->sourcemac, new_entry->sourcemsk)) - ebt_print_error("Problem with " - "specified source mac"); + if (ebt_get_mac_and_mask(optarg, new_entry->sourcemac, new_entry->sourcemsk)) + ebt_print_error2("Problem with specified source mac"); new_entry->bitmask |= EBT_SOURCEMAC; break; - } - if (c == 'd') { - ebt_check_option(&replace.flags, OPT_DEST); - if (ebt_check_inverse(optarg)) + } else if (c == 'd') { + ebt_check_option2(&(replace->flags), OPT_DEST); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IDEST; - if (optind > argc) - ebt_print_error("No destination mac " - "specified"); - if (ebt_get_mac_and_mask(argv[optind - 1], - new_entry->destmac, new_entry->destmsk)) - ebt_print_error("Problem with " - "specified destination mac"); + if (ebt_get_mac_and_mask(optarg, new_entry->destmac, new_entry->destmsk)) + ebt_print_error2("Problem with specified destination mac"); new_entry->bitmask |= EBT_DESTMAC; break; } - ebt_check_option(&replace.flags, OPT_PROTOCOL); - if (ebt_check_inverse(optarg)) + ebt_check_option2(&(replace->flags), OPT_PROTOCOL); + if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IPROTO; - if (optind > argc) - ebt_print_error("No protocol specified"); new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO); - i = strtol(argv[optind - 1], &buffer, 16); + i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) - ebt_print_error("Problem with the specified " - "protocol"); - new_entry->ethproto = i; + ebt_print_error2("Problem with the specified protocol"); if (*buffer != '\0') { struct ethertypeent *ent; - if (!strcasecmp(argv[optind - 1], "LENGTH")) { + if (!strcasecmp(optarg, "LENGTH")) { new_entry->bitmask |= EBT_802_3; break; } - ent = getethertypebyname(argv[optind - 1]); + ent = getethertypebyname(optarg); if (!ent) - print_epoto_error(argv[optind - 1]); + ebt_print_error2("Problem with the specified Ethernet protocol (%s), perhaps "_PATH_ETHERTYPES " is missing", optarg) new_entry->ethproto = ent->e_ethertype; - } - if (new_entry->ethproto < 1536 && - !(new_entry->bitmask & EBT_802_3)) - ebt_print_error("Sorry, protocols have values " - "above or equal to 0x0600"); - break; + } else + new_entry->ethproto = i; + if (new_entry->ethproto < 0x0600) + ebt_print_error2("Sorry, protocols have values above or equal to 0x0600"); + break; case 4 : /* Lc */ - ebt_check_option(&replace.flags, LIST_C); - if (replace.command != 'L') + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--Lc is not supported in daemon mode"); + ebt_check_option2(&(replace->flags), LIST_C); + if (replace->command != 'L') ebt_print_error("Use --Lc with -L"); - if (replace.flags & LIST_X) - ebt_print_error("--Lx not compatible with " - "--Lc"); - replace.flags |= LIST_C; + if (replace->flags & LIST_X) + ebt_print_error2("--Lx is not compatible with --Lc"); + replace->flags |= LIST_C; break; case 5 : /* Ln */ - ebt_check_option(&replace.flags, LIST_N); - if (replace.command != 'L') - ebt_print_error("Use --Ln with -L"); - if (replace.flags & LIST_X) - ebt_print_error("--Lx not compatible with " - "--Ln"); - replace.flags |= LIST_N; + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--Ln is not supported in daemon mode"); + ebt_check_option2(&(replace->flags), LIST_N); + if (replace->command != 'L') + ebt_print_error2("Use --Ln with -L"); + if (replace->flags & LIST_X) + ebt_print_error2("--Lx is not compatible with --Ln"); + replace->flags |= LIST_N; break; case 6 : /* Lx */ - ebt_check_option(&replace.flags, LIST_X); - if (replace.command != 'L') - ebt_print_error("Use --Lx with -L"); - if (replace.flags & LIST_C) - ebt_print_error("--Lx not compatible with " - "--Lc"); - if (replace.flags & LIST_N) - ebt_print_error("--Lx not compatible with " - "--Ln"); - replace.flags |= LIST_X; + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--Lx is not supported in daemon mode"); + ebt_check_option2(&(replace->flags), LIST_X); + if (replace->command != 'L') + ebt_print_error2("Use --Lx with -L"); + if (replace->flags & LIST_C) + ebt_print_error2("--Lx is not compatible with --Lc"); + if (replace->flags & LIST_N) + ebt_print_error2("--Lx is not compatible with --Ln"); + replace->flags |= LIST_X; break; case 12 : /* Lmac2 */ - ebt_check_option(&replace.flags, LIST_MAC2); - if (replace.command != 'L') - ebt_print_error("Use --Lmac2 with -L"); - replace.flags |= LIST_MAC2; + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error("--Lmac2 is not supported in daemon mode"); + ebt_check_option2(&(replace->flags), LIST_MAC2); + if (replace->command != 'L') + ebt_print_error2("Use --Lmac2 with -L"); + replace->flags |= LIST_MAC2; break; case 8 : /* atomic-commit */ - replace.command = c; - if (replace.flags & OPT_COMMAND) - ebt_print_error("Multiple commands not " - "allowed"); - replace.flags |= OPT_COMMAND; - if (!replace.filename) - ebt_print_error("No atomic file specified"); - /* - * get the information from the file - */ - ebt_get_table(&replace, 0); - /* - * we don't want the kernel giving us its counters, + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--atomic-commit is not supported in daemon mode"); + replace->command = c; + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + replace->flags |= OPT_COMMAND; + if (!replace->filename) + ebt_print_error2("No atomic file specified"); + /* Get the information from the file */ + ebt_get_table(replace, 0); + /* We don't want the kernel giving us its counters, * they would overwrite the counters extracted from - * the file - */ - replace.num_counters = 0; - /* - * make sure the table will be written to the kernel - */ - free(replace.filename); - replace.filename = NULL; + * the file */ + replace->num_counters = 0; + /* Make sure the table will be written to the kernel */ + 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) - ebt_print_error("Multiple commands not " - "allowed"); - if (c != 11 && !replace.filename) - ebt_print_error("No atomic file specified"); - replace.flags |= OPT_COMMAND; + if (exec_style == EXEC_STYLE_DAEMON) { + if (c == 7) { + ebt_print_error2("--atomic-init is not supported in daemon mode"); + } else if (c == 10) + ebt_print_error2("--atomic-save is not supported in daemon mode"); + ebt_print_error2("--init-table is not supported in daemon mode"); + } + replace->command = c; + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + if (c != 11 && !replace->filename) + ebt_print_error2("No atomic file specified"); + replace->flags |= OPT_COMMAND; { - char *tmp = replace.filename; + char *tmp = replace->filename; int init = 1; if (c == 10) init = 0; - tmp = replace.filename; - /* get the kernel table */ - replace.filename = NULL; - ebt_get_kernel_table(&replace, table, init); - replace.filename = tmp; + /* Get the kernel table */ + replace->filename = NULL; + ebt_get_kernel_table(replace, init); + replace->filename = tmp; } break; case 9 : /* atomic */ - if (replace.flags & OPT_COMMAND) - ebt_print_error("--atomic has to come before" - " the command"); - /* another possible memory leak here */ - replace.filename = (char *)malloc(strlen(optarg) + 1); - strcpy(replace.filename, optarg); + if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--atomic is not supported in daemon mode"); + if (OPT_COMMANDS) + ebt_print_error2("--atomic has to come before the command"); + /* A possible memory leak here, but this is not + * executed in daemon mode */ + replace->filename = (char *)malloc(strlen(optarg) + 1); + strcpy(replace->filename, optarg); break; case 1 : if (!strcmp(optarg, "!")) - ebt_check_inverse(optarg); + ebt_check_inverse2(optarg); else - ebt_print_error("Bad argument : %s", optarg); - /* - * ebt_check_inverse() did optind++ - */ + ebt_print_error2("Bad argument : %s", optarg); + /* ebt_check_inverse() did optind++ */ optind--; continue; default: - /* - * is it a target option? - */ + /* Is it a target option? */ t = (struct ebt_u_target *)new_entry->t; - if ((t->parse(c - t->option_offset, argv, argc, - new_entry, &t->flags, &t->t))) + if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) goto check_extension; - /* - * is it a match_option? - */ + /* Is it a match_option? */ for (m = ebt_matches; m; m = m->next) - if (m->parse(c - m->option_offset, argv, - argc, new_entry, &m->flags, &m->m)) + if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) break; if (m != NULL) { @@ -1105,109 +985,107 @@ handle_P: goto check_extension; } - /* - * is it a watcher option? - */ + /* Is it a watcher option? */ for (w = ebt_watchers; w; w = w->next) - if (w->parse(c-w->option_offset, argv, - argc, new_entry, &w->flags, &w->w)) + if (w->parse(c-w->option_offset, argv, argc, new_entry, &w->flags, &w->w)) break; if (w == NULL) - ebt_print_error("Unknown argument"); + ebt_print_error2("Unknown argument: '%s', %c, '%c'", argv[optind - 1], (char)optopt, (char)c); if (w->used == 0) { ebt_add_watcher(new_entry, w); w->used = 1; } check_extension: - if (replace.command != 'A' && replace.command != 'I' && - replace.command != 'D') - ebt_print_error("Extensions only for -A, " - "-I and -D"); + if (replace->command != 'A' && replace->command != 'I' && replace->command != 'D') + ebt_print_error2("Extensions only for -A, -I and -D"); } ebt_invert = 0; } - if ( !table && !(table = ebt_find_table(replace.name)) ) - ebt_print_error("Bad table name"); + /* Just in case we didn't catch an error */ + if (ebt_errormsg[0] != '\0') + return -1; - if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' && - replace.flags & OPT_ZERO ) - ebt_print_error("Command -Z only allowed together with " - "command -L"); + if (!(table = ebt_find_table(replace->name))) + ebt_print_error2("Bad table name"); - /* - * do this after parsing everything, so we can print specific info - */ - if (replace.command == 'h' && !(replace.flags & OPT_ZERO)) + if (replace->command == 'h' && !(replace->flags & OPT_ZERO)) print_help(); - /* - * do the final checks - */ - if (replace.command == 'A' || replace.command == 'I' || - replace.command == 'D') { - /* - * this will put the hook_mask right for the chains - */ - ebt_check_for_loops(&replace); - entries = ebt_to_chain(&replace); + /* Do the final checks */ + if (replace->command == 'A' || replace->command == 'I' || + replace->command == 'D') { + /* This will put the hook_mask right for the chains */ + ebt_check_for_loops(replace); + if (ebt_errormsg[0] != '\0') + return -1; + entries = ebt_to_chain(replace); 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, + m->final_check(new_entry, m->m, replace->name, entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; 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, + w->final_check(new_entry, w->w, replace->name, entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; w_l = w_l->next; } - t->final_check(new_entry, t->t, replace.name, + t->final_check(new_entry, t->t, replace->name, entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; } - /* - * so, the extensions can work with the host endian - * the kernel does not have to do this of course - */ + /* So, the extensions can work with the host endian. + * The kernel does not have to do this of course */ new_entry->ethproto = htons(new_entry->ethproto); - if (replace.command == 'P') { - if (replace.selected_chain < NF_BR_NUMHOOKS && - policy == EBT_RETURN) - ebt_print_error("Policy RETURN only allowed for user " - "defined chains"); - ebt_change_policy(&replace, policy); - } else if (replace.command == 'L') { + if (replace->command == 'P') { + if (replace->selected_chain < NF_BR_NUMHOOKS && policy == EBT_RETURN) + ebt_print_error2("Policy RETURN only allowed for user defined chains"); + ebt_change_policy(replace, policy); + if (ebt_errormsg[0] != '\0') + return -1; + } else if (replace->command == 'L') { list_rules(); - if (replace.flags & OPT_ZERO) { - replace.selected_chain = zerochain; - ebt_zero_counters(&replace); - } else + if (!(replace->flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) exit(0); } - if (replace.flags & OPT_ZERO) { - replace.selected_chain = zerochain; - ebt_zero_counters(&replace); - } else if (replace.command == 'F') - ebt_flush_chains(&replace); - else if (replace.command == 'A' || replace.command == 'I') { - ebt_add_rule(&replace, new_entry, rule_nr); - ebt_check_for_loops(&replace); - /* - * do the final_check(), for all entries - * needed when adding a rule that has a chain target - */ + if (replace->flags & OPT_ZERO) { + replace->selected_chain = zerochain; + ebt_zero_counters(replace); + } else if (replace->command == 'F') { + ebt_flush_chains(replace); + } else if (replace->command == 'A' || replace->command == 'I') { + ebt_add_rule(replace, new_entry, rule_nr); + if (ebt_errormsg[0] != '\0') + return -1; + /* Makes undoing the add easier (jumps to delete_the_rule) */ + if (rule_nr <= 0) + rule_nr--; + rule_nr_end = rule_nr; + + ebt_check_for_loops(replace); + if (ebt_errormsg[0] != '\0') + goto delete_the_rule; + + /* Do the final_check(), for all entries. + * This is needed when adding a rule that has a chain target */ i = -1; while (1) { struct ebt_u_entry *e; i++; - entries = ebt_nr_to_chain(&replace, i); + entries = ebt_nr_to_chain(replace, i); if (!entries) { if (i < NF_BR_NUMHOOKS) continue; @@ -1216,28 +1094,33 @@ check_extension: } e = entries->entries; while (e) { - /* - * userspace extensions use host endian - */ + /* Userspace extensions use host endian */ e->ethproto = ntohs(e->ethproto); - ebt_do_final_checks(&replace, e, entries); + ebt_do_final_checks(replace, e, entries); + if (ebt_errormsg[0] != '\0') + goto delete_the_rule; e->ethproto = htons(e->ethproto); e = e->next; } } - } else if (replace.command == 'D') - ebt_delete_rule(&replace, new_entry, rule_nr, rule_nr_end); - /* - * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save, - * --init-table fall through - */ - + /* Don't reuse the added rule */ + new_entry = NULL; + } else if (replace->command == 'D') +delete_the_rule: /* This needs to be followed by a check on ebt_errormsg[0] */ + ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end); + /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save, + * --init-table fall through */ + + if (ebt_errormsg[0] != '\0') + return -1; if (table->check) - table->check(&replace); + table->check(replace); - ebt_deliver_table(&replace); + if (exec_style == EXEC_STYLE_PRG) {/* Implies ebt_errormsg[0] == '\0' */ + ebt_deliver_table(replace); - if (replace.counterchanges) - ebt_deliver_counters(&replace); + if (replace->counterchanges) + ebt_deliver_counters(replace, exec_style); + } return 0; } diff --git a/ebtablesd.c b/ebtablesd.c new file mode 100644 index 0000000..1f60791 --- /dev/null +++ b/ebtablesd.c @@ -0,0 +1,367 @@ +/* + * ebtablesd.c, January 2005 + * + * Author: Bart De Schuymer + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/ebtables_u.h" + +#define OPT_KERNELDATA 0x800 /* Also defined in ebtables.c */ + +static struct ebt_u_replace replace[3]; +#define OPEN_METHOD_FILE 1 +#define OPEN_METHOD_KERNEL 2 +static int open_method[3]; +void ebt_early_init_once(); + +static void sigpipe_handler(int sig) +{ +} + +int main(int argc_, char *argv_[]) +{ + char *argv[EBTD_ARGC_MAX], *args[4], name[] = "mkdir", + mkdir_option[] = "-p", mkdir_dir[] = EBTD_PIPE_DIR, + cmdline[EBTD_CMDLINE_MAXLN]; + int readfd, stop = 0, base = 0, offset = 0, n = 0, ret = 0; + + /* Make sure the pipe directory exists */ + args[0] = name; + args[1] = mkdir_option; + args[2] = mkdir_dir; + args[3] = NULL; + switch (fork()) { + case 0: + execvp(args[0], args); + + /* Not usually reached */ + exit(0); + case -1: + return -1; + + default: /* Parent */ + wait(NULL); + } + + if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) { + printf("Error creating FIFO " EBTD_PIPE "\n"); + ret = -1; + goto do_exit; + } + + if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) { + perror("open"); + ret = -1; + goto do_exit; + } + + if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) { + perror("signal"); + ret = -1; + goto do_exit; + } + + ebt_silent = 1; + + strcpy(replace[0].name, "filter"); + strcpy(replace[1].name, "nat"); + strcpy(replace[2].name, "broute"); + + ebt_early_init_once(); + + while (!stop) { + int n2, i, argc, table_nr, ntot; + + /* base == 0 */ + ntot = read(readfd, cmdline+offset, EBTD_CMDLINE_MAXLN-offset-1); + if (ntot <= 0) + continue; + ntot += offset; +continue_read: + /* Change all ' ' into '\0'. This implies that the user is not + * allowed to use spaces (that don't distinguish options or + * commands) in her rules. This comes down to not allowing spaces + * in options like the string of --ulog-prefix (use '_' instead). + */ + for (; offset < ntot; n++, offset++) { + if (cmdline[offset] == ' ') + cmdline[offset] = '\0'; + if (cmdline[offset] == '\n') { + cmdline[offset] = '\0'; + break; + } + } + if (n == 0) { + if (offset == ntot) { + /* The ntot bytes were parsed and ended with '\n' */ + base = 0; + offset = 0; + continue; + } + offset++; + base = offset; + n = 0; + goto continue_read; + } + if (offset == ntot) { /* The ntot bytes were parsed but no complete rule is yet specified */ + if (base == 0) { + ebt_print_error("ebtablesd: the maximum command line length is %d", EBTD_CMDLINE_MAXLN-1); + goto write_msg; + } + memmove(cmdline, cmdline+base+offset, ntot-offset); + offset -= base; + offset++; + base = 0; + continue; + } + + table_nr = 0; + n2 = 0; + argc = 0; + while (n2 < n && argc < EBTD_ARGC_MAX) { + argv[argc++] = cmdline + base + n2; + n2 += strlen(cmdline + base + n2) + 1; + } + offset++; /* Move past the '\n' */ + base = offset; + + if (argc > EBTD_ARGC_MAX) { + ebt_print_error("ebtablesd: maximum %d arguments " + "allowed", EBTD_ARGC_MAX - 1); + goto write_msg; + } + if (argc == 1) { + ebt_print_error("ebtablesd: no arguments"); + goto write_msg; + } + + /* Parse the options */ + if (!strcmp(argv[1], "-t")) { + if (argc < 3) { + ebt_print_error("ebtablesd: -t but no table"); + goto write_msg; + } + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + table_nr = i; + } else if (!strcmp(argv[1], "free")) { + if (argc != 3) { + ebt_print_error("ebtablesd: command free " + "needs exactly one argument"); + goto write_msg; + } + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + if (!(replace[i].flags & OPT_KERNELDATA)) { + ebt_print_error("ebtablesd: table %s has not " + "been opened"); + goto write_msg; + } + ebt_cleanup_replace(&replace[i]); + replace[i].flags &= ~OPT_KERNELDATA; + goto write_msg; + } else if (!strcmp(argv[1], "open")) { + if (argc != 3) { + ebt_print_error("ebtablesd: command open " + "needs exactly one argument"); + goto write_msg; + } + + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + if (replace[i].flags & OPT_KERNELDATA) { + ebt_print_error("ebtablesd: table %s needs to " + "be freed before it can be " + "opened"); + goto write_msg; + } + if (!ebt_get_kernel_table(&replace[i], 0)) { + replace[i].flags |= OPT_KERNELDATA; + open_method[i] = OPEN_METHOD_KERNEL; + } + goto write_msg; + } else if (!strcmp(argv[1], "fopen")) { + struct ebt_u_replace tmp; + + memset(&tmp, 0, sizeof(tmp)); + if (argc != 4) { + ebt_print_error("ebtablesd: command fopen " + "needs exactly two arguments"); + goto write_msg; + } + + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + if (replace[i].flags & OPT_KERNELDATA) { + ebt_print_error("ebtablesd: table %s needs to " + "be freed before it can be " + "opened"); + goto write_msg; + } + tmp.filename = (char *)malloc(strlen(argv[3]) + 1); + if (!tmp.filename) { + ebt_print_error("Out of memory"); + goto write_msg; + } + strcpy(tmp.filename, argv[3]); + strcpy(tmp.name, "filter"); + tmp.command = 'L'; /* Make sure retrieve_from_file() + * doesn't complain about wrong + * table name */ + + ebt_get_kernel_table(&tmp, 0); + free(tmp.filename); + tmp.filename = NULL; + if (ebt_errormsg[0] != '\0') + goto write_msg; + + if (strcmp(tmp.name, argv[2])) { + ebt_print_error("ebtablesd: opened file with " + "wrong table name '%s'", tmp.name); + ebt_cleanup_replace(&tmp); + goto write_msg; + } + replace[i] = tmp; + replace[i].command = '\0'; + replace[i].flags |= OPT_KERNELDATA; + open_method[i] = OPEN_METHOD_FILE; + goto write_msg; + } else if (!strcmp(argv[1], "commit")) { + if (argc != 3) { + ebt_print_error("ebtablesd: command commit " + "needs exactly one argument"); + goto write_msg; + } + + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + if (!(replace[i].flags & OPT_KERNELDATA)) { + ebt_print_error("ebtablesd: table %s has not " + "been opened"); + goto write_msg; + } + /* The counters from the kernel are useless if we + * didn't start from a kernel table */ + if (open_method[i] == OPEN_METHOD_FILE) + replace[i].num_counters = 0; + ebt_deliver_table(&replace[i]); + if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL) + ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON); + goto write_msg; + } else if (!strcmp(argv[1], "fcommit")) { + if (argc != 4) { + ebt_print_error("ebtablesd: command commit " + "needs exactly two argument"); + goto write_msg; + } + + for (i = 0; i < 3; i++) + if (!strcmp(replace[i].name, argv[2])) + break; + if (i == 3) { + ebt_print_error("ebtablesd: table '%s' was " + "not recognized", argv[2]); + goto write_msg; + } + if (!(replace[i].flags & OPT_KERNELDATA)) { + ebt_print_error("ebtablesd: table %s has not " + "been opened"); + goto write_msg; + } + replace[i].filename = (char *)malloc(strlen(argv[3]) + 1); + if (!replace[i].filename) { + ebt_print_error("Out of memory"); + goto write_msg; + } + strcpy(replace[i].filename, argv[3]); + ebt_deliver_table(&replace[i]); + if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL) + ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON); + free(replace[i].filename); + replace[i].filename = NULL; + goto write_msg; + }else if (!strcmp(argv[1], "quit")) { + if (argc != 2) { + ebt_print_error("ebtablesd: command quit does " + "not take any arguments"); + goto write_msg; + } + stop = 1; + goto write_msg; + } + if (!(replace[table_nr].flags & OPT_KERNELDATA)) { + ebt_print_error("ebtablesd: table %s has not been " + "opened", replace[table_nr].name); + goto write_msg; + } + optind = 1; +printf("jak: ntot = %d, offset = %d, base = %d\n", ntot, offset, base); + do_command(argc, argv, EXEC_STYLE_DAEMON, &replace[table_nr]); + ebt_reinit_extensions(); +write_msg: +#ifndef SILENT_DAEMON + if (ebt_errormsg[0] != '\0') + printf("%s\n", ebt_errormsg); +#endif + ebt_errormsg[0]= '\0'; + n = 0; + goto continue_read; + } +do_exit: + unlink(EBTD_PIPE); + + return 0; +} diff --git a/ebtablesu.c b/ebtablesu.c new file mode 100644 index 0000000..234d4f6 --- /dev/null +++ b/ebtablesu.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *arguments, *pos; + int i, writefd, len = 0; + + if ((writefd = open(EBTD_PIPE, O_WRONLY, 0)) == -1) { + perror("open"); + return -1; + } + + if (argc > EBTD_ARGC_MAX) { + printf("ebtablesd accepts at most %d arguments, %d arguments " + "were specified. If you need this many arguments, " + "recompile this tool with a higher value for " + "EBTD_ARGC_MAX.\n", EBTD_ARGC_MAX - 1, argc - 1); + return -1; + } else if (argc == 1) { + printf("At least one argument is needed.\n"); + return -1; + } + + for (i = 0; i < argc; i++) + len += strlen(argv[i]); + /* Don't forget '\0' */ + len += argc; + if (len > EBTD_CMDLINE_MAXLN) { + printf("ebtablesd has a maximum command line argument length " + "of %d, an argument length of %d was received. If a " + "smaller length is unfeasible, recompile this tool " + "with a higher value for EBTD_CMDLINE_MAXLN.\n", + EBTD_CMDLINE_MAXLN, len); + return -1; + } + + if (!(arguments = (char *)malloc(len))) { + printf("ebtablesu: out of memory.\n"); + return -1; + } + + pos = arguments; + for (i = 0; i < argc; i++) { + strcpy(pos, argv[i]); + pos += strlen(argv[i]) + 1; + } + + *(pos-1) = '\n'; + if (write(writefd, arguments, len) == -1) { + perror("write"); + return -1; + } + return 0; +} diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c index 6d9233e..c81e687 100644 --- a/extensions/ebt_ip.c +++ b/extensions/ebt_ip.c @@ -209,7 +209,7 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, ipinfo->invflags |= EBT_IP_PROTO; if (optind > argc) ebt_print_error("Missing IP protocol argument"); - (unsigned char) i = strtoul(argv[optind - 1], &end, 10); + i = strtoul(argv[optind - 1], &end, 10); if (*end != '\0') { struct protoent *pe; diff --git a/extensions/ebt_limit.c b/extensions/ebt_limit.c index 1c5c32b..6dcd50d 100644 --- a/extensions/ebt_limit.c +++ b/extensions/ebt_limit.c @@ -203,15 +203,15 @@ static int compare(const struct ebt_entry_match* m1, const struct ebt_entry_matc static struct ebt_u_match limit_match = { - .name EBT_LIMIT_MATCH, - .size sizeof(struct ebt_limit_info), - .help print_help, - .init init, - .parse parse, - .final_check final_check, - .print print, - .compare compare, - .extra_ops opts, + .name = EBT_LIMIT_MATCH, + .size = sizeof(struct ebt_limit_info), + .help = print_help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .compare = compare, + .extra_ops = opts, }; void _init(void) diff --git a/extensions/ebt_vlan.c b/extensions/ebt_vlan.c index b4e1d38..0c94a66 100644 --- a/extensions/ebt_vlan.c +++ b/extensions/ebt_vlan.c @@ -141,8 +141,7 @@ parse(int c, ebt_check_option(flags, OPT_VLAN_ID); CHECK_INV_FLAG(EBT_VLAN_ID); CHECK_IF_MISSING_VALUE; - (unsigned short) local.id = - strtoul(argv[optind - 1], &end, 10); + local.id = strtoul(argv[optind - 1], &end, 10); CHECK_RANGE(local.id > 4094 || *end != '\0'); vlaninfo->id = local.id; SET_BITMASK(EBT_VLAN_ID); @@ -152,8 +151,7 @@ parse(int c, ebt_check_option(flags, OPT_VLAN_PRIO); CHECK_INV_FLAG(EBT_VLAN_PRIO); CHECK_IF_MISSING_VALUE; - (unsigned char) local.prio = - strtoul(argv[optind - 1], &end, 10); + local.prio = strtoul(argv[optind - 1], &end, 10); CHECK_RANGE(local.prio >= 8 || *end != '\0'); vlaninfo->prio = local.prio; SET_BITMASK(EBT_VLAN_PRIO); @@ -163,8 +161,7 @@ parse(int c, ebt_check_option(flags, OPT_VLAN_ENCAP); CHECK_INV_FLAG(EBT_VLAN_ENCAP); CHECK_IF_MISSING_VALUE; - (unsigned short) local.encap = - strtoul(argv[optind - 1], &end, 16); + local.encap = strtoul(argv[optind - 1], &end, 16); if (*end != '\0') { ethent = getethertypebyname(argv[optind - 1]); if (ethent == NULL) diff --git a/include/ebtables_u.h b/include/ebtables_u.h index 5b040d2..d5264e3 100644 --- a/include/ebtables_u.h +++ b/include/ebtables_u.h @@ -26,6 +26,9 @@ #include #include +#define EXEC_STYLE_PRG 0 +#define EXEC_STYLE_DAEMON 1 + #ifndef EBT_MIN_ALIGN #define EBT_MIN_ALIGN (__alignof__(struct ebt_entry_target)) #endif @@ -223,8 +226,7 @@ void ebt_register_table(struct ebt_u_table *); void ebt_register_match(struct ebt_u_match *); void ebt_register_watcher(struct ebt_u_watcher *); void ebt_register_target(struct ebt_u_target *t); -void ebt_get_kernel_table(struct ebt_u_replace *replace, - struct ebt_u_table *table, int init); +int ebt_get_kernel_table(struct ebt_u_replace *replace, int init); struct ebt_u_target *ebt_find_target(const char *name); struct ebt_u_match *ebt_find_match(const char *name); struct ebt_u_watcher *ebt_find_watcher(const char *name); @@ -232,6 +234,8 @@ struct ebt_u_table *ebt_find_table(const char *name); int ebtables_insmod(const char *modname); void ebt_list_extensions(); void ebt_initialize_entry(struct ebt_u_entry *e); +void ebt_cleanup_replace(struct ebt_u_replace *replace); +void ebt_reinit_extensions(); void ebt_free_u_entry(struct ebt_u_entry *e); struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, const char* arg); @@ -257,8 +261,9 @@ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name); /**/ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, struct ebt_u_entries *entries); -int ebt_check_for_references(struct ebt_u_replace *replace); -int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr); +int ebt_check_for_references(struct ebt_u_replace *replace, int print_err); +int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr, + int print_err); void ebt_check_for_loops(struct ebt_u_replace *replace); void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m); void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w); @@ -271,7 +276,7 @@ void __ebt_print_error(char *format, ...); /* communication.c */ int ebt_get_table(struct ebt_u_replace *repl, int init); -void ebt_deliver_counters(struct ebt_u_replace *repl); +void ebt_deliver_counters(struct ebt_u_replace *repl, int exec_style); void ebt_deliver_table(struct ebt_u_replace *repl); /* useful_functions.c */ @@ -285,6 +290,9 @@ int ebt_get_mac_and_mask(char *from, char *to, char *mask); void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk); char *ebt_mask_to_dotted(uint32_t mask); +int do_command(int argc, char *argv[], int exec_style, + struct ebt_u_replace *replace_); + struct ethertypeent *parseethertypebynumber(int type); #define ebt_print_bug(format, args...) \ diff --git a/libebtc.c b/libebtc.c index dfc277b..0fef235 100644 --- a/libebtc.c +++ b/libebtc.c @@ -40,9 +40,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace); static void remove_udc(struct ebt_u_replace *replace); static int iterate_entries(struct ebt_u_replace *replace, int type); -/* - * The standard names - */ +/* The standard names */ const char *ebt_hooknames[NF_BR_NUMHOOKS] = { [NF_BR_PRE_ROUTING]"PREROUTING", @@ -53,9 +51,7 @@ const char *ebt_hooknames[NF_BR_NUMHOOKS] = [NF_BR_BROUTING]"BROUTING" }; -/* - * The four target names - */ +/* The four target names */ const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = { "ACCEPT", @@ -64,22 +60,18 @@ const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = "RETURN", }; -/* - * The lists of supported tables, matches, watchers and targets - */ +/* The lists of supported tables, matches, watchers and targets */ struct ebt_u_table *ebt_tables; struct ebt_u_match *ebt_matches; struct ebt_u_watcher *ebt_watchers; struct ebt_u_target *ebt_targets; -/* - * Find the right structure belonging to a name - */ +/* Find the right structure belonging to a name */ struct ebt_u_target *ebt_find_target(const char *name) { struct ebt_u_target *t = ebt_targets; - while(t && strcmp(t->name, name)) + while (t && strcmp(t->name, name)) t = t->next; return t; } @@ -88,7 +80,7 @@ struct ebt_u_match *ebt_find_match(const char *name) { struct ebt_u_match *m = ebt_matches; - while(m && strcmp(m->name, name)) + while (m && strcmp(m->name, name)) m = m->next; return m; } @@ -97,7 +89,7 @@ struct ebt_u_watcher *ebt_find_watcher(const char *name) { struct ebt_u_watcher *w = ebt_watchers; - while(w && strcmp(w->name, name)) + while (w && strcmp(w->name, name)) w = w->next; return w; } @@ -111,9 +103,7 @@ struct ebt_u_table *ebt_find_table(const char *name) return t; } -/* - * Prints all registered extensions - */ +/* Prints all registered extensions */ void ebt_list_extensions() { struct ebt_u_table *tbl = ebt_tables; @@ -123,59 +113,51 @@ void ebt_list_extensions() PRINT_VERSION; printf("Supported userspace extensions:\n\nSupported tables:\n"); - while(tbl) { + while (tbl) { printf("%s\n", tbl->name); tbl = tbl->next; } printf("\nSupported targets:\n"); - while(t) { + while (t) { printf("%s\n", t->name); t = t->next; } printf("\nSupported matches:\n"); - while(m) { + while (m) { printf("%s\n", m->name); m = m->next; } printf("\nSupported watchers:\n"); - while(w) { + while (w) { printf("%s\n", w->name); w = w->next; } - exit(0); } -/* - * Get the table from the kernel or from a binary file +/* Get the table from the kernel or from a binary file * init: 1 = ask the kernel for the initial contents of a table, i.e. the * way it looks when the table is insmod'ed - * 0 = get the current data in the table - */ -void ebt_get_kernel_table(struct ebt_u_replace *replace, - struct ebt_u_table *table, int init) + * 0 = get the current data in the table */ +int ebt_get_kernel_table(struct ebt_u_replace *replace, int init) { - if ( !(table = ebt_find_table(replace->name)) ) + if (!ebt_find_table(replace->name)) { ebt_print_error("Bad table name"); - /* - * get the kernel's information - */ + return -1; + } + /* Get the kernel's information */ if (ebt_get_table(replace, init)) { + if (ebt_errormsg[0] != '\0') + return -1; ebtables_insmod("ebtables"); - if (ebt_get_table(replace, init)) - ebt_print_error("The kernel doesn't support the " - "ebtables %s table", replace->name); + if (ebt_get_table(replace, init)) { + ebt_print_error("The kernel doesn't support the ebtables %s table", replace->name); + return -1; + } } - /* - * when listing a table contained in a file, we don't demand that - * the user knows the table's name, so we update table if necessary - */ - if ( !(table = ebt_find_table(replace->name)) ) - ebt_print_error("Bad table name"); + return 0; } -/* - * Put sane values into a new entry - */ +/* Put sane values into a new entry */ void ebt_initialize_entry(struct ebt_u_entry *e) { e->bitmask = EBT_NOPROTO; @@ -188,16 +170,14 @@ void ebt_initialize_entry(struct ebt_u_entry *e) e->m_list = NULL; e->w_list = NULL; e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET); + ebt_find_target(EBT_STANDARD_TARGET)->used = 1; if (!e->t) ebt_print_bug("Couldn't load standard target"); - ((struct ebt_standard_target *) - ((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE; + ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE; } -/* - * replace is reborn, i.e. rebirth of replace - */ +/* Free up the memory of the table held in userspace, *replace can be reused */ void ebt_cleanup_replace(struct ebt_u_replace *replace) { int i; @@ -245,6 +225,7 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) } udc1 = replace->udc; while (udc1) { + free(udc1->udc); udc2 = udc1->next; free(udc1); udc1 = udc2; @@ -259,10 +240,8 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) replace->counterchanges = NULL; } -/* - * Should be called between 2 rule adds, f.e. - */ -void ebt_reinit_extensions(struct ebt_u_replace *replace) +/* Should be called, e.g., between 2 rule adds */ +void ebt_reinit_extensions() { struct ebt_u_match *m; struct ebt_u_watcher *w; @@ -273,42 +252,46 @@ void ebt_reinit_extensions(struct ebt_u_replace *replace) * called for the first time or not (when necessary). */ for (m = ebt_matches; m; m = m->next) { size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match); - if (m->m) - free(m->m); - m->m = (struct ebt_entry_match *)malloc(size); - if (!m->m) - ebt_print_memory(); - m->used = 0; - m->flags = 0; + if (m->used) { + m->m = (struct ebt_entry_match *)malloc(size); + if (!m->m) + ebt_print_memory(); + strcpy(m->m->u.name, m->name); + m->m->match_size = EBT_ALIGN(m->size); + m->used = 0; + m->flags = 0; + } m->init(m->m); } for (w = ebt_watchers; w; w = w->next) { size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher); - if (w->w) - free(w->w); - w->w = (struct ebt_entry_watcher *)malloc(size); - if (!w->w) - ebt_print_memory(); - w->used = 0; - w->flags = 0; + if (w->used) { + w->w = (struct ebt_entry_watcher *)malloc(size); + if (!w->w) + ebt_print_memory(); + strcpy(w->w->u.name, w->name); + w->w->watcher_size = EBT_ALIGN(w->size); + w->used = 0; + w->flags = 0; + } w->init(w->w); } - for (t = ebt_targets; m; t = t->next) { + for (t = ebt_targets; t; t = t->next) { size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target); - if (t->t) - free(t->t); - t->t = (struct ebt_entry_target *)malloc(size); - if (!t->t) - ebt_print_memory(); - t->used = 0; - t->flags = 0; + if (t->used) { + t->t = (struct ebt_entry_target *)malloc(size); + if (!t->t) + ebt_print_memory(); + strcpy(t->t->u.name, t->name); + t->t->target_size = EBT_ALIGN(t->size); + t->used = 0; + t->flags = 0; + } t->init(t->t); } } -/* - * This doesn't free e, becoz the calling function might need e->next - */ +/* This doesn't free e, because the calling function might need e->next */ void ebt_free_u_entry(struct ebt_u_entry *e) { struct ebt_u_match_list *m_l, *m_l2; @@ -331,10 +314,8 @@ void ebt_free_u_entry(struct ebt_u_entry *e) free(e->t); } -/* - * Blatently stolen (again) from iptables.c userspace program - * find out where the modprobe utility is located - */ +/* Blatently stolen (again) from iptables.c userspace program + * find out where the modprobe utility is located */ static char *get_modprobe(void) { int procfile; @@ -350,8 +331,8 @@ static char *get_modprobe(void) case -1: goto fail; case 1024: goto fail; /* Partial read. Wierd */ } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; + if (ret[strlen(ret)-1] == '\n') + ret[strlen(ret)-1] = 0; close(procfile); return ret; } @@ -362,9 +343,7 @@ static char *get_modprobe(void) } char *ebt_modprobe; -/* - * Try to load the kernel module - */ +/* Try to load the kernel module */ int ebtables_insmod(const char *modname) { char *buf = NULL; @@ -385,12 +364,12 @@ int ebtables_insmod(const char *modname) argv[2] = NULL; execv(argv[0], argv); - /* not usually reached */ + /* Not usually reached */ exit(0); case -1: return -1; - default: /* parent */ + default: /* Parent */ wait(NULL); } @@ -398,11 +377,9 @@ int ebtables_insmod(const char *modname) return 0; } -/* - * Gives back a pointer to the chain base, based on nr. +/* Gives back a pointer to the chain base, based on nr. * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain. - * Returns NULL on failure. - */ + * Returns NULL on failure. */ struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, int nr) { @@ -426,20 +403,16 @@ struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, } } -/* - * Gives back a pointer to the chain base of selected_chain - */ +/* Gives back a pointer to the chain base of selected_chain */ struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace) { return ebt_nr_to_chain(replace, replace->selected_chain); } -/* - * Parse the chain name and return a pointer to the chain base. - * Returns NULL on failure. - */ +/* Parse the chain name and return a pointer to the chain base. + * Returns NULL on failure. */ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, - const char* arg) + const char* arg) { int i; struct ebt_u_chain_list *cl = replace->udc; @@ -458,10 +431,8 @@ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, return NULL; } -/* - * Parse the chain name and return the corresponding chain nr - * returns -1 on failure - */ +/* Parse the chain name and return the corresponding chain nr + * returns -1 on failure */ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg) { int i; @@ -490,23 +461,19 @@ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg) ************ */ -/* - * Chainge the policy of selected_chain. - * No sanity checks are done. - */ +/* Change the policy of selected_chain. + * Handing a bad policy to this function is a bug. */ void ebt_change_policy(struct ebt_u_replace *replace, int policy) { struct ebt_u_entries *entries = ebt_to_chain(replace); if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE) - ebt_print_bug("wrong policy: %d", policy); + ebt_print_bug("Wrong policy: %d", policy); entries->policy = policy; } -/* - * Flush one chain or the complete table - * If selected_chain == -1: flush the complete table - */ +/* Flush one chain or the complete table + * If selected_chain == -1: flush the complete table */ void ebt_flush_chains(struct ebt_u_replace *replace) { int i, j, numdel; @@ -515,17 +482,13 @@ void ebt_flush_chains(struct ebt_u_replace *replace) struct ebt_cntchanges *cc = replace->counterchanges; struct ebt_cntchanges **prev_cc = &(replace->counterchanges); - /* - * flush whole table - */ + /* Flush whole table */ if (!entries) { if (replace->nentries == 0) return; replace->nentries = 0; - /* - * free everything and zero (n)entries - */ + /* Free everything and zero (n)entries */ i = -1; while (1) { i++; @@ -547,9 +510,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace) u_e = tmp; } } - /* - * update the counters - */ + /* Update the counters */ while (cc) { if (cc->type == CNT_ADD) { *prev_cc = cc->next; @@ -569,10 +530,8 @@ void ebt_flush_chains(struct ebt_u_replace *replace) replace->nentries -= entries->nentries; numdel = entries->nentries; - /* - * delete the counters belonging to the specified chain, - * update counter_offset - */ + /* Delete the counters belonging to the specified chain, + * update counter_offset */ i = -1; while (1) { i++; @@ -589,7 +548,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace) } j = entries->nentries; while (j) { - /* don't count deleted entries */ + /* Don't count deleted entries */ if (cc->type == CNT_DEL) goto letscontinue; if (i == replace->selected_chain) { @@ -619,15 +578,12 @@ letscontinue: u_e = tmp; } entries->entries = NULL; - return; } -/* - * returns the rule number on success (starting from 0), -1 on failure +/* Returns the rule number on success (starting from 0), -1 on failure * * This function expects the ebt_{match,watcher,target} members of new_entry - * to contain pointers to ebt_u_{match,watcher,target}. - */ + * to contain pointers to ebt_u_{match,watcher,target} */ int ebt_check_rule_exists(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry) { @@ -641,10 +597,8 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, int i, j, k; u_e = entries->entries; - /* - * check for an existing rule (if there are duplicate rules, - * take the first occurance) - */ + /* Check for an existing rule (if there are duplicate rules, + * take the first occurance) */ for (i = 0; i < entries->nentries; i++, u_e = u_e->next) { if (!u_e) ebt_print_bug("Hmm, trouble"); @@ -659,17 +613,15 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, if (strcmp(u_e->logical_out, new_entry->logical_out)) continue; if (new_entry->bitmask & EBT_SOURCEMAC && - memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN)) + memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN)) continue; if (new_entry->bitmask & EBT_DESTMAC && - memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN)) + memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN)) continue; if (new_entry->bitmask != u_e->bitmask || - new_entry->invflags != u_e->invflags) + new_entry->invflags != u_e->invflags) continue; - /* - * compare all matches - */ + /* Compare all matches */ m_l = new_entry->m_list; j = 0; while (m_l) { @@ -682,9 +634,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, j++; m_l = m_l->next; } - /* - * now be sure they have the same nr of matches - */ + /* Now be sure they have the same nr of matches */ k = 0; m_l = u_e->m_list; while (m_l) { @@ -694,9 +644,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, if (j != k) continue; - /* - * compare all watchers - */ + /* Compare all watchers */ w_l = new_entry->w_list; j = 0; while (w_l) { @@ -732,13 +680,14 @@ letscontinue:; * rule_nr > 0 : insert the rule right before the rule_nr'th rule * (the first rule is rule 1) * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule, - * where n denotes the number of rule in the chain + * where n denotes the number of rules in the chain * rule_nr == 0: add a new rule at the end of the chain * * This function expects the ebt_{match,watcher,target} members of new_entry * to contain pointers to ebt_u_{match,watcher,target} and updates these - * pointers before adding the rule to the chain. - */ + * pointers so that they point to ebt_{match,watcher,target}, before adding + * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a + * successful call to ebt_add_rule() */ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int rule_nr) { @@ -754,17 +703,15 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, rule_nr += entries->nentries; else rule_nr--; - if (rule_nr > entries->nentries || rule_nr < 0) + if (rule_nr > entries->nentries || rule_nr < 0) { ebt_print_error("The specified rule number is incorrect"); - /* - * we're adding one rule - */ + return; + } + /* We're adding one rule */ replace->nentries++; entries->nentries++; - /* - * handle counter stuff - */ + /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; @@ -783,32 +730,26 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, prev_cc = &(cc->next); cc = cc->next; } - if (cc && cc->type == CNT_DEL) /* The add is victorious and conquers - * the delete */ + if (cc && cc->type == CNT_DEL) cc->type = CNT_OWRITE; else { new_cc = (struct ebt_cntchanges *) malloc(sizeof(struct ebt_cntchanges)); + if (!new_cc) + ebt_print_memory(); new_cc->type = CNT_ADD; new_cc->next = cc; *prev_cc = new_cc; } - - /* - * go to the right position in the chain - */ + /* Go to the right position in the chain */ u_e = &entries->entries; for (i = 0; i < rule_nr; i++) u_e = &(*u_e)->next; - /* - * insert the rule - */ + /* Insert the rule */ new_entry->next = *u_e; *u_e = new_entry; - /* - * put the ebt_[match, watcher, target] pointers in place - */ + /* Put the ebt_{match, watcher, target} pointers in place */ m_l = new_entry->m_list; while (m_l) { m_l->m = ((struct ebt_u_match *)m_l->m)->m; @@ -820,10 +761,7 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, 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 - */ + /* Update the counter_offset of chains behind this one */ i = replace->selected_chain; while (1) { i++; @@ -838,14 +776,12 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, } } -/* - * Delete a rule or rules +/* Delete a rule or rules * begin == end == 0: delete the rule corresponding to new_entry * - * the first rule has rule nr 1, the last rule has rule nr -1, etc. + * The first rule has rule nr 1, the last rule has rule nr -1, etc. * This function expects the ebt_{match,watcher,target} members of new_entry - * to contain pointers to ebt_u_{match,watcher,target}. - */ + * to contain pointers to ebt_u_{match,watcher,target}. */ void ebt_delete_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int begin, int end) { @@ -860,8 +796,10 @@ void ebt_delete_rule(struct ebt_u_replace *replace, if (end < 0) end += entries->nentries + 1; - if (begin < 0 || begin > end || end > entries->nentries) + if (begin < 0 || begin > end || end > entries->nentries) { ebt_print_error("Sorry, wrong rule numbers"); + return; + } if ((begin * end == 0) && (begin + end != 0)) ebt_print_bug("begin and end should be either both zero, " @@ -872,20 +810,18 @@ void ebt_delete_rule(struct ebt_u_replace *replace, } else { begin = ebt_check_rule_exists(replace, new_entry); end = begin; - if (begin == -1) + if (begin == -1) { ebt_print_error("Sorry, rule does not exist"); + return; + } } - /* - * we're deleting rules - */ + /* We're deleting rules */ nr_deletes = end - begin + 1; replace->nentries -= nr_deletes; entries->nentries -= nr_deletes; - /* - * handle counter stuff - */ + /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; @@ -920,27 +856,21 @@ void ebt_delete_rule(struct ebt_u_replace *replace, cc = cc->next; } - /* - * go to the right position in the chain - */ + /* Go to the right position in the chain */ u_e = &entries->entries; for (j = 0; j < begin; j++) u_e = &(*u_e)->next; - /* - * remove the rules - */ + /* Remove the rules */ j = nr_deletes; while(j--) { u_e2 = *u_e; *u_e = (*u_e)->next; - /* free everything */ + /* Free everything */ ebt_free_u_entry(u_e2); free(u_e2); } - /* - * update the counter_offset of chains behind this one - */ + /* Update the counter_offset of chains behind this one */ j = replace->selected_chain; while (1) { j++; @@ -955,10 +885,8 @@ void ebt_delete_rule(struct ebt_u_replace *replace, } } -/* - * Selected_chain == -1 : zero all counters - * else, zero the counters of selected_chain - */ +/* Selected_chain == -1 : zero all counters + * Otherwise, zero the counters of selected_chain */ void ebt_zero_counters(struct ebt_u_replace *replace) { struct ebt_u_entries *entries = ebt_to_chain(replace); @@ -976,8 +904,7 @@ void ebt_zero_counters(struct ebt_u_replace *replace) return; for (i = 0; i < replace->selected_chain; i++) { - if (i < NF_BR_NUMHOOKS && - !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -998,20 +925,22 @@ void ebt_zero_counters(struct ebt_u_replace *replace) } } -/* - * Add a new chain and specify its policy - */ +/* Add a new chain and specify its policy */ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy) { struct ebt_u_chain_list *cl, **cl2; - if (ebt_get_chainnr(replace, name) != -1) + if (ebt_get_chainnr(replace, name) != -1) { ebt_print_error("Chain %s already exists", optarg); - if (ebt_find_target(name)) + return; + } else if (ebt_find_target(name)) { ebt_print_error("Target with name %s exists", optarg); - if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) + return; + } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) { ebt_print_error("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); + return; + } cl = (struct ebt_u_chain_list *) malloc(sizeof(struct ebt_u_chain_list)); if (!cl) @@ -1028,39 +957,37 @@ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy) strcpy(cl->udc->name, name); cl->udc->entries = NULL; cl->kernel_start = NULL; - /* - * put the new chain at the end - */ + /* Put the new chain at the end */ cl2 = &(replace->udc); while (*cl2) cl2 = &((*cl2)->next); *cl2 = cl; } -/* - * Selected_chain == -1: delete all non-referenced udc - * selected_chain < NF_BR_NUMHOOKS is illegal - */ +/* Selected_chain == -1: delete all non-referenced udc + * selected_chain < NF_BR_NUMHOOKS is illegal */ void ebt_delete_chain(struct ebt_u_replace *replace) { - int chain_nr = replace->selected_chain; + int chain_nr = replace->selected_chain, print_error = 1; if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS) ebt_print_bug("You can't remove a standard chain"); - if (chain_nr == -1) + if (chain_nr == -1) { + print_error = 0; replace->selected_chain = NF_BR_NUMHOOKS; + } do { if (ebt_to_chain(replace) == NULL) { if (chain_nr == -1) break; ebt_print_bug("udc nr %d doesn't exist", chain_nr); } - /* - * if the chain is referenced, don't delete it, + /* If the chain is referenced, don't delete it, * also decrement jumps to a chain behind the - * one we're deleting - */ - if (ebt_check_for_references(replace)) { + * one we're deleting */ + if (ebt_check_for_references(replace, print_error)) { + if (chain_nr != -1) + break; replace->selected_chain++; continue; } @@ -1068,12 +995,10 @@ void ebt_delete_chain(struct ebt_u_replace *replace) ebt_flush_chains(replace); remove_udc(replace); } while (chain_nr == -1); - replace->selected_chain = chain_nr; + replace->selected_chain = chain_nr; /* Put back to -1 */ } -/* - * Rename an existing chain. - */ +/* Rename an existing chain. */ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name) { struct ebt_u_entries *entries = ebt_to_chain(replace); @@ -1093,11 +1018,10 @@ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name) */ -/* - * executes the final_check() function for all extensions used by the rule +/* Executes the final_check() function for all extensions used by the rule * ebt_check_for_loops should have been executed earlier, to make sure the - * hook_mask is correct. - */ + * hook_mask is correct. The time argument to final_check() is set to 1, + * meaning it's the second time the final_check() function is executed. */ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, struct ebt_u_entries *entries) { @@ -1113,12 +1037,16 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, m = ebt_find_match(m_l->m->u.name); m->final_check(e, m_l->m, replace->name, entries->hook_mask, 1); + if (ebt_errormsg[0] != '\0') + return; m_l = m_l->next; } while (w_l) { w = ebt_find_watcher(w_l->w->u.name); w->final_check(e, w_l->w, replace->name, entries->hook_mask, 1); + if (ebt_errormsg[0] != '\0') + return; w_l = w_l->next; } t = ebt_find_target(e->t->u.name); @@ -1126,26 +1054,29 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, entries->hook_mask, 1); } -/* - * returns 1 when the chain is referenced, - * 0 when it isn't. - */ -int ebt_check_for_references(struct ebt_u_replace *replace) +/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't. + * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */ +int ebt_check_for_references(struct ebt_u_replace *replace, int print_err) { - return iterate_entries(replace, 1); + if (print_err) + return iterate_entries(replace, 1); + else + return iterate_entries(replace, 2); } -/* - * chain_nr: nr of the udc (>= NF_BR_NUMHOOKS) - * returns 1 when the chain is referenced, - * 0 when it isn't. - */ -int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr) +/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS) + * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't. + * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */ +int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr, + int print_err) { int tmp = replace->selected_chain, ret; replace->selected_chain = chain_nr; - ret = iterate_entries(replace, 1); + if (print_err) + ret = iterate_entries(replace, 1); + else + ret = iterate_entries(replace, 2); replace->selected_chain = tmp; return ret; } @@ -1158,12 +1089,10 @@ struct ebt_u_stack struct ebt_u_entries *entries; }; -/* - * Checks for loops +/* Checks for loops * As a by-product, the hook_mask member of each chain is filled in * correctly. The check functions of the extensions need this hook_mask - * to know from which standard chains they can be called. - */ + * to know from which standard chains they can be called. */ void ebt_check_for_loops(struct ebt_u_replace *replace) { int chain_nr , i, j , k, sp = 0, verdict; @@ -1172,9 +1101,7 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) struct ebt_u_entry *e; i = -1; - /* - * initialize hook_mask to 0 - */ + /* Initialize hook_mask to 0 */ while (1) { i++; if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) @@ -1191,17 +1118,13 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) ebt_print_memory(); } - /* - * check for loops, starting from every base chain - */ + /* Check for loops, starting from every base chain */ for (i = 0; i < NF_BR_NUMHOOKS; i++) { if (!(replace->valid_hooks & (1 << i))) continue; entries = ebt_nr_to_chain(replace, i); - /* - * (1 << NF_BR_NUMHOOKS) implies it's a standard chain - * (usefull in the final_check() funtions) - */ + /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain + * (usefull in the final_check() funtions) */ entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS); chain_nr = i; @@ -1212,20 +1135,17 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) verdict = ((struct ebt_standard_target *)(e->t))->verdict; if (verdict < 0) goto letscontinue; - entries2 = ebt_nr_to_chain(replace, - verdict + NF_BR_NUMHOOKS); + entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS); entries2->hook_mask |= entries->hook_mask; - /* - * now see if we've been here before - */ + /* Now see if we've been here before */ for (k = 0; k < sp; k++) - if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) - ebt_print_error("Loop from chain %s to chain %s", + if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) { + ebt_print_error("Loop from chain '%s' to chain '%s'", ebt_nr_to_chain(replace, chain_nr)->name, ebt_nr_to_chain(replace, stack[k].chain_nr)->name); - /* - * jump to the chain, make sure we know how to get back - */ + goto free_stack; + } + /* 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; @@ -1239,14 +1159,10 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) letscontinue: e = e->next; } - /* - * we are at the end of a standard chain - */ + /* We are at the end of a standard chain */ if (sp == 0) continue; - /* - * go back to the chain one level higher - */ + /* Go back to the chain one level higher */ sp--; j = stack[sp].n; chain_nr = stack[sp].chain_nr; @@ -1254,13 +1170,16 @@ letscontinue: entries = stack[sp].entries; goto letscontinue; } +free_stack: free(stack); return; } -/* - * the user will use the match, so put it in new_entry - */ +/* The user will use the match, so put it in new_entry. The ebt_u_match + * pointer is put in the ebt_entry_match pointer. ebt_add_rule will + * fill in the final value for new->m. Unless the rule is added to a chain, + * the pointer will keep pointing to the ebt_u_match (until the new_entry + * is freed). I know, I should use a union for these 2 pointer types... */ void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m) { struct ebt_u_match_list **m_list, *new; @@ -1300,13 +1219,12 @@ void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w) */ -/* - * type = 0 => update chain jumps - * type = 1 => check for reference +/* type = 0 => update chain jumps + * type = 1 => check for reference, print error when referenced + * type = 2 => check for reference, don't print error when referenced * - * returns 1 when type == 1 and the chain is referenced - * returns 0 otherwise - */ + * Returns 1 when type == 1 and the chain is referenced + * returns 0 otherwise */ static int iterate_entries(struct ebt_u_replace *replace, int type) { int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS; @@ -1338,19 +1256,21 @@ static int iterate_entries(struct ebt_u_replace *replace, int type) verdict; switch (type) { case 1: + case 2: if (chain_jmp == chain_nr) { - ebt_print_error("Can't delete the chain, it's " - "referenced in chain %s, rule %d", - entries->name, j); + if (type == 2) + return 1; + ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d", + ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j); return 1; } break; case 0: - /* adjust the chain jumps when necessary */ + /* Adjust the chain jumps when necessary */ if (chain_jmp > chain_nr) ((struct ebt_standard_target *)e->t)->verdict--; break; - } /* end switch */ + } /* End switch */ e = e->next; } } @@ -1362,9 +1282,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace) iterate_entries(replace, 0); } -/* - * selected_chain >= NF_BR_NUMHOOKS - */ +/* Selected_chain >= NF_BR_NUMHOOKS */ static void remove_udc(struct ebt_u_replace *replace) { struct ebt_u_chain_list *cl, **cl2; @@ -1375,7 +1293,7 @@ static void remove_udc(struct ebt_u_replace *replace) if (chain_nr < NF_BR_NUMHOOKS) ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr, NF_BR_NUMHOOKS); - /* first free the rules */ + /* First free the rules */ entries = ebt_nr_to_chain(replace, chain_nr); u_e = entries->entries; while (u_e) { @@ -1395,10 +1313,7 @@ static void remove_udc(struct ebt_u_replace *replace) free(cl); } - -/* - * used in initialization code of modules - */ +/* Used in initialization code of modules */ void ebt_register_match(struct ebt_u_match *m) { int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match); @@ -1480,9 +1395,7 @@ void ebt_iterate_targets(void (*f)(struct ebt_u_target *)) f(i); } -/* - * Don't use this function, use ebt_print_bug() - */ +/* Don't use this function, use ebt_print_bug() */ void __ebt_print_bug(char *file, int line, char *format, ...) { va_list l; @@ -1495,26 +1408,20 @@ void __ebt_print_bug(char *file, int line, char *format, ...) exit (-1); } -/* - * The error messages are put in here when ebt_silent == 1 - * ebt_errormsg[0] == '\0' implies there was no error - */ +/* The error messages are put in here when ebt_silent == 1 + * ebt_errormsg[0] == '\0' implies there was no error */ char ebt_errormsg[ERRORMSG_MAXLEN]; -/* - * When error messages should not be printed on the screen, after which - * the program exit()s, set ebt_silent to 1. - */ +/* When error messages should not be printed on the screen, after which + * the program exit()s, set ebt_silent to 1. */ int ebt_silent; -/* - * Don't use this function, use ebt_print_error() - */ +/* Don't use this function, use ebt_print_error() */ void __ebt_print_error(char *format, ...) { va_list l; va_start(l, format); - if (ebt_silent) { - snprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l); + if (ebt_silent && ebt_errormsg[0] == '\0') { + vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l); va_end(l); } else { vprintf(format, l); -- cgit v1.2.3