+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:
* <grzes_at_gnu.univ.gda.pl> added arpreply and among modules
The Makefile will append /man8/ebtables.8.
- ethertypes is by default placed in /etc/, if you
want to change this, include ETHERTYPESPATH=<<path>>.
-- 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=<<path>>.
+- 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=<<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=<<path>>.
That's all
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)
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 $< $@
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
.PHONY: clean
clean:
- rm -f ebtables
+ rm -f ebtables ebtablesd ebtablesu
rm -f *.o *.c~ *.so
rm -f extensions/*.o extensions/*.c~ extensions/*.so
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)
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) {
}
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) {
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);
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;
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) {
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];
i++;
}
- /* sanity check */
+ /* Sanity check */
if (p - (char *)new->entries != new->entries_size)
ebt_print_bug("Entries_size bug");
free(chain_offsets);
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);
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)
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))
" 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;
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++;
}
}
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));
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
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));
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
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;
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;
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;
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;
}
(*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;
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)
}
}
-/* 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)
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 *)
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;
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)
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)
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 ||
|| 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,
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;
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);
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;
}
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;
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,
--- /dev/null
+#include <string.h>
+#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;
+}
.\"
.\"
.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
.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
*
* 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
#include <fcntl.h>
#include <sys/wait.h>
-/*
- * 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' },
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,
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);
(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)
{
*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;
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]);
}
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;
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)
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;
}
"--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"
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 {
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)
}
}
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)
return 0;
}
-static void parse_iface(char *iface, char *option)
+static int parse_iface(char *iface, char *option)
{
char *c;
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
#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 <this> -L <that>)
- */
+ /* Needed for the -Z option (we can have -Z <this> -L <that>) */
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;
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) {
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;
}
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;
}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#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;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+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;
+}
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;
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)
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);
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);
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)
#include <netinet/in.h>
#include <linux/netfilter_bridge/ebtables.h>
+#define EXEC_STYLE_PRG 0
+#define EXEC_STYLE_DAEMON 1
+
#ifndef EBT_MIN_ALIGN
#define EBT_MIN_ALIGN (__alignof__(struct ebt_entry_target))
#endif
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);
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);
/**/
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);
/* 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 */
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...) \
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",
[NF_BR_BROUTING]"BROUTING"
};
-/*
- * The four target names
- */
+/* The four target names */
const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
{
"ACCEPT",
"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;
}
{
struct ebt_u_match *m = ebt_matches;
- while(m && strcmp(m->name, name))
+ while (m && strcmp(m->name, name))
m = m->next;
return m;
}
{
struct ebt_u_watcher *w = ebt_watchers;
- while(w && strcmp(w->name, name))
+ while (w && strcmp(w->name, name))
w = w->next;
return w;
}
return t;
}
-/*
- * Prints all registered extensions
- */
+/* Prints all registered extensions */
void ebt_list_extensions()
{
struct ebt_u_table *tbl = ebt_tables;
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;
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;
}
udc1 = replace->udc;
while (udc1) {
+ free(udc1->udc);
udc2 = udc1->next;
free(udc1);
udc1 = udc2;
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;
* 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;
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;
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;
}
}
char *ebt_modprobe;
-/*
- * Try to load the kernel module
- */
+/* Try to load the kernel module */
int ebtables_insmod(const char *modname)
{
char *buf = NULL;
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);
}
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)
{
}
}
-/*
- * 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;
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;
************
*/
-/*
- * 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;
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++;
u_e = tmp;
}
}
- /*
- * update the counters
- */
+ /* Update the counters */
while (cc) {
if (cc->type == CNT_ADD) {
*prev_cc = cc->next;
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++;
}
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) {
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)
{
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");
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) {
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) {
if (j != k)
continue;
- /*
- * compare all watchers
- */
+ /* Compare all watchers */
w_l = new_entry->w_list;
j = 0;
while (w_l) {
* 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)
{
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;
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;
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++;
}
}
-/*
- * 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)
{
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, "
} 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;
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++;
}
}
-/*
- * 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);
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) {
}
}
-/*
- * 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)
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;
}
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);
*/
-/*
- * 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)
{
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);
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;
}
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;
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)))
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;
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;
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;
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;
*/
-/*
- * 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;
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;
}
}
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;
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) {
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);
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;
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);