diff options
-rw-r--r-- | communication.c | 23 | ||||
-rw-r--r-- | ebtables.c | 68 | ||||
-rw-r--r-- | libebtc.c | 125 |
3 files changed, 109 insertions, 107 deletions
diff --git a/communication.c b/communication.c index e429d15..6db6858 100644 --- a/communication.c +++ b/communication.c @@ -369,12 +369,20 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style) /* Don't use this old counter */ old++; } else { - if (cc->type == CNT_INCR) { - new->pcnt = old->pcnt + next->cnt_surplus.pcnt; - new->bcnt = old->bcnt + next->cnt_surplus.bcnt; - } else if (cc->type == CNT_DECR) { - new->pcnt = old->pcnt - next->cnt_surplus.pcnt; - new->bcnt = old->bcnt - next->cnt_surplus.bcnt; + if (cc->type == CNT_CHANGE) { + new->pcnt = old->pcnt; + if (cc->change % 3 == 1) + new->pcnt = old->pcnt + next->cnt_surplus.pcnt; + else if (cc->change % 3 == 2) + new->pcnt = old->pcnt - next->cnt_surplus.pcnt; + else + new->pcnt = next->cnt.pcnt; + if (cc->change / 3 == 1) + new->bcnt = old->bcnt + next->cnt_surplus.bcnt; + else if (cc->change / 3 == 2) + new->bcnt = old->bcnt - next->cnt_surplus.bcnt; + else + new->bcnt = next->cnt.bcnt; } else *new = next->cnt; next->cnt = *new; @@ -415,6 +423,7 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style) cc = u_repl->counterchanges; for (i = 0; i < u_repl->nentries; i++) { cc->type = CNT_NORM; + cc->change = 0; cc3 = &cc->next; cc = cc->next; } @@ -513,6 +522,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, if (*totalcnt >= u_repl->nentries) ebt_print_bug("*totalcnt >= u_repl->nentries"); new->cnt = u_repl->counters[*totalcnt]; + new->cnt_surplus.pcnt = new->cnt_surplus.bcnt = 0; new->m_list = NULL; new->w_list = NULL; new->next = NULL; @@ -792,6 +802,7 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init) if (!new_cc) ebt_print_memory(); new_cc->type = CNT_NORM; + new_cc->change = 0; new_cc->next = NULL; *prev_cc = new_cc; prev_cc = &(new_cc->next); @@ -318,14 +318,8 @@ static void list_em(struct ebt_u_entries *entries, struct ebt_cntchanges *cc) while (cc->type == CNT_DEL) cc = cc->next; - /* This can only happen in daemon mode */ - if (cc->type == CNT_INCR) { - pcnt += hlp->cnt_surplus.pcnt; - bcnt += hlp->cnt_surplus.bcnt; - } else if (cc->type == CNT_DECR) { - pcnt -= hlp->cnt_surplus.pcnt; - bcnt -= hlp->cnt_surplus.bcnt; - } + if (cc->change != 0) /* in daemon mode, only change==0 is allowed */ + ebt_print_bug("cc->change != 0"); cc = cc->next; if (replace->flags & LIST_X) printf("-c %llu %llu", pcnt, bcnt); @@ -490,13 +484,16 @@ static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end) return 0; } -static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end) +/* Incrementing or decrementing rules in daemon mode is not supported as the + * involved code overload is not worth it. */ +static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style) { char *buffer; + int ret = 0; if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) || (argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0' && argv[optind + 1][1] > '9'))) - ebt_print_error2("The command -C needs at least 3 arguments"); + ebt_print_error2("The command -C needs at least 2 arguments"); if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) { if (optind + 3 != argc) ebt_print_error2("No extra options allowed with -C start_nr[:end_nr] pcnt bcnt"); @@ -506,36 +503,40 @@ static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int * } if (argv[optind][0] == '+') { - if (argv[optind + 1][0] != '+') - ebt_print_error2("If one counter is increased, the other should be increased too (perhaps put a '+' before '%s')", argv[optind + 1]); - replace->flags |= OPT_CNT_INCR; + if (exec_style == EXEC_STYLE_DAEMON) +daemon_incr: + ebt_print_error2("Incrementing rule counters (%s) not allowed in daemon mode", argv[optind]); + ret += 1; new_entry->cnt_surplus.pcnt = strtoull(argv[optind] + 1, &buffer, 10); - if (*buffer != '\0') - goto invalid; - optind++; - new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10); } else if (argv[optind][0] == '-') { - if (argv[optind + 1][0] != '-') - ebt_print_error2("If one counter is decreased, the other should be decreased too (perhaps put a '-' before '%s')", argv[optind + 1]); - replace->flags |= OPT_CNT_DECR; + if (exec_style == EXEC_STYLE_DAEMON) +daemon_decr: + ebt_print_error2("Decrementing rule counters (%s) not allowed in daemon mode", argv[optind]); + ret += 2; new_entry->cnt_surplus.pcnt = strtoull(argv[optind] + 1, &buffer, 10); - if (*buffer != '\0') - goto invalid; - optind++; - new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10); - } else { - if (argv[optind + 1][0] == '-' || argv[optind + 1][0] == '+') - ebt_print_error2("If one counter is %screased, the other should be %screased too (perhaps put a '%c' before '%s')", - argv[optind + 1][0] == '-' ? "de" : "in", argv[optind + 1][0] == '-' ? "de" : "in", argv[optind + 1][0], argv[optind]); + } else new_entry->cnt_surplus.pcnt = strtoull(argv[optind], &buffer, 10); - optind++; + + if (*buffer != '\0') + goto invalid; + optind++; + if (argv[optind][0] == '+') { + if (exec_style == EXEC_STYLE_DAEMON) + goto daemon_incr; + ret += 3; + new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else if (argv[optind][0] == '-') { + if (exec_style == EXEC_STYLE_DAEMON) + goto daemon_decr; + ret += 6; + new_entry->cnt_surplus.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else new_entry->cnt_surplus.bcnt = strtoull(argv[optind], &buffer, 10); - } if (*buffer != '\0') goto invalid; optind++; - return 0; + return ret; invalid: ebt_print_error2("Packet counter '%s' invalid", argv[optind]); } @@ -567,6 +568,7 @@ int do_command(int argc, char *argv[], int exec_style, char *buffer; int c, i; int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */ + int chcounter; /* Needed for -C */ int policy = 0; int rule_nr = 0; int rule_nr_end = 0; @@ -686,7 +688,7 @@ int do_command(int argc, char *argv[], int exec_style, ebt_print_error2("Problem with the specified rule number(s) '%s'", argv[optind]); optind++; } else if (c == 'C') { - if (parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end)) + if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style)) == -1) return -1; } else if (c == 'I') { if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) @@ -1224,7 +1226,7 @@ delete_the_rule: if (ebt_errormsg[0] != '\0') return -1; } else if (replace->command == 'C') { - ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus)); + ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); if (ebt_errormsg[0] != '\0') return -1; } @@ -23,12 +23,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <getopt.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> -#include <netinet/ether.h> #include "include/ebtables_u.h" #include "include/ethernetdb.h" #include <unistd.h> @@ -140,7 +138,7 @@ void ebt_list_extensions() int ebt_get_kernel_table(struct ebt_u_replace *replace, int init) { if (!ebt_find_table(replace->name)) { - ebt_print_error("Bad table name"); + ebt_print_error("Bad table name '%s'", replace->name); return -1; } /* Get the kernel's information */ @@ -149,7 +147,7 @@ int ebt_get_kernel_table(struct ebt_u_replace *replace, int init) 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); + ebt_print_error("The kernel doesn't support the ebtables '%s' table", replace->name); return -1; } } @@ -212,10 +210,7 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) else break; } - entries->nentries = 0; - entries->counter_offset = 0; u_e1 = entries->entries; - entries->entries = NULL; while (u_e1) { ebt_free_u_entry(u_e1); u_e2 = u_e1->next; @@ -223,6 +218,11 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) u_e1 = u_e2; } } + for (i = 0; i < NF_BR_NUMHOOKS; i++) + if (replace->hook_entry[i]) { + free(replace->hook_entry[i]); + replace->hook_entry[i] = NULL; + } udc1 = replace->udc; while (udc1) { free(udc1->udc); @@ -314,8 +314,6 @@ void ebt_free_u_entry(struct ebt_u_entry *e) free(e->t); } -/* Blatently stolen (again) from iptables.c userspace program - * find out where the modprobe utility is located */ static char *get_modprobe(void) { int procfile; @@ -327,12 +325,9 @@ static char *get_modprobe(void) ret = malloc(1024); if (ret) { - switch (read(procfile, ret, 1024)) { - case -1: goto fail; - case 1024: goto fail; /* Partial read. Wierd */ - } - if (ret[strlen(ret)-1] == '\n') - ret[strlen(ret)-1] = 0; + if (read(procfile, ret, 1024) == -1) + goto fail; + ret[1023] = '\0'; close(procfile); return ret; } @@ -343,7 +338,7 @@ static char *get_modprobe(void) } char *ebt_modprobe; -/* Try to load the kernel module */ +/* Try to load the kernel module, analogous to ip_tables.c */ int ebtables_insmod(const char *modname) { char *buf = NULL; @@ -380,8 +375,7 @@ int ebtables_insmod(const char *modname) /* 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. */ -struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, - int nr) +struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, int nr) { if (nr == -1) return NULL; @@ -418,7 +412,7 @@ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, struct ebt_u_chain_list *cl = replace->udc; for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(replace->valid_hooks & (1 << i))) + if (!replace->hook_entry[i]) continue; if (!strcmp(arg, replace->hook_entry[i]->name)) return replace->hook_entry[i]; @@ -439,7 +433,7 @@ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg) struct ebt_u_chain_list *cl = replace->udc; for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(replace->valid_hooks & (1 << i))) + if (!replace->hook_entry[i]) continue; if (!strcmp(arg, replace->hook_entry[i]->name)) return i; @@ -473,7 +467,7 @@ void ebt_change_policy(struct ebt_u_replace *replace, int policy) } /* Flush one chain or the complete table - * If selected_chain == -1: flush the complete table */ + * If selected_chain == -1 then flush the complete table */ void ebt_flush_chains(struct ebt_u_replace *replace) { int i, j, numdel; @@ -690,8 +684,8 @@ letscontinue:; * 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 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() */ + * the rule to the chain. Don't free() the ebt_{match,watcher,target} and + * don't reuse the new_entry 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) { @@ -717,7 +711,7 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { - if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i])) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -737,11 +731,11 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, if (cc && cc->type == CNT_DEL) cc->type = CNT_OWRITE; else { - new_cc = (struct ebt_cntchanges *) - malloc(sizeof(struct ebt_cntchanges)); + new_cc = (struct ebt_cntchanges *)malloc(sizeof(struct ebt_cntchanges)); if (!new_cc) ebt_print_memory(); new_cc->type = CNT_ADD; + new_cc->change = 0; new_cc->next = cc; *prev_cc = new_cc; } @@ -780,6 +774,8 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, } } +/* If *begin==*end==0 then find the rule corresponding to new_entry, + * else make the rule numbers positive and check for bad rule numbers. */ static int check_and_change_rule_number(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int *begin, int *end) { @@ -837,7 +833,7 @@ void ebt_delete_rule(struct ebt_u_replace *replace, /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { - if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i])) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -899,17 +895,19 @@ void ebt_delete_rule(struct ebt_u_replace *replace, } } -#define OPT_CNT_INCR 0x2000 /* This value is also defined in ebtables.c */ -#define OPT_CNT_DECR 0x4000 /* This value is also defined in ebtables.c */ /* Change the counters of a rule or rules * begin == end == 0: change counters of the rule corresponding to new_entry * * 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}. + * The mask denotes the following: + * pcnt: mask % 3 = 0 : change; = 1: increment; = 2: decrement + * bcnt: mask / 3 = 0 : change; = 1: increment = 2: increment + * In daemon mode, mask==0 must hold */ void ebt_change_counters(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int begin, int end, - struct ebt_counter *cnt) + struct ebt_counter *cnt, int mask) { int i, j; struct ebt_u_entry *u_e; @@ -920,7 +918,7 @@ void ebt_change_counters(struct ebt_u_replace *replace, return; for (i = 0; i < replace->selected_chain; i++) { - if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i])) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -942,40 +940,34 @@ void ebt_change_counters(struct ebt_u_replace *replace, while (i) { if (cc->type != CNT_DEL) { i--; - if (cc->type != CNT_ADD && cc->type != CNT_OWRITE) { - /* In daemon mode, we want to make sure we don't lose - * any counted packets/bytes (the kernel is still counting - * while we are changing things in userspace). Therefore, - * we need to add the amount to the counters in the kernel, - * not the counters copied earlier from the kernel. */ - u_e->cnt_surplus = *cnt; - if (replace->flags & OPT_CNT_INCR) { - cc->type = CNT_INCR; - } else if (replace->flags & OPT_CNT_DECR) - cc->type = CNT_DECR; - else { - cc->type = CNT_CHANGE; - u_e->cnt = *cnt; - u_e->cnt_surplus.pcnt = u_e->cnt_surplus.bcnt = 0; - } - } else { /* A -C after a -A remains a -A */ - if (replace->flags & OPT_CNT_INCR) { - u_e->cnt.pcnt += cnt->pcnt; - u_e->cnt.bcnt += cnt->bcnt; - } else if (replace->flags & OPT_CNT_DECR) { - u_e->cnt.pcnt -= cnt->pcnt; - u_e->cnt.bcnt -= cnt->bcnt; - } else - u_e->cnt = *cnt; + if (mask % 3 == 0) { + u_e->cnt.pcnt = (*cnt).pcnt; + u_e->cnt_surplus.pcnt = 0; + } else { + if (cc->type != CNT_NORM) + ebt_print_bug("cc->type != CNT_NORM"); + u_e->cnt_surplus.pcnt = (*cnt).pcnt; + } + + if (mask / 3 == 0) { + u_e->cnt.bcnt = (*cnt).bcnt; + u_e->cnt_surplus.bcnt = 0; + } else { + if (cc->type != CNT_NORM) + ebt_print_bug("cc->type != CNT_NORM"); + u_e->cnt_surplus.bcnt = (*cnt).bcnt; } + if (cc->type == CNT_NORM || cc->type == CNT_ZERO) + cc->type = CNT_CHANGE; + cc->change = mask; u_e = u_e->next; } cc = cc->next; } } -/* Selected_chain == -1 : zero all counters - * Otherwise, zero the counters of selected_chain */ +/* If selected_chain == -1 then 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); @@ -992,7 +984,7 @@ void ebt_zero_counters(struct ebt_u_replace *replace) i = -1; while (1) { i++; - if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i])) continue; entries = ebt_nr_to_chain(replace, i); if (!entries) { @@ -1006,14 +998,13 @@ void ebt_zero_counters(struct ebt_u_replace *replace) next = next->next; } } - } else { next = entries->entries; if (entries->nentries == 0) 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->hook_entry[i])) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -1059,8 +1050,7 @@ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy) if (!cl) ebt_print_memory(); cl->next = NULL; - cl->udc = (struct ebt_u_entries *) - malloc(sizeof(struct ebt_u_entries)); + cl->udc = (struct ebt_u_entries *)malloc(sizeof(struct ebt_u_entries)); if (!cl->udc) ebt_print_memory(); cl->udc->nentries = 0; @@ -1217,7 +1207,7 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) /* Initialize hook_mask to 0 */ while (1) { i++; - if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->hook_entry[i])) continue; entries = ebt_nr_to_chain(replace, i); if (!entries) @@ -1225,15 +1215,14 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) entries->hook_mask = 0; } if (i > NF_BR_NUMHOOKS) { - stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) * - sizeof(struct ebt_u_stack)); + stack = (struct ebt_u_stack *)malloc((i - NF_BR_NUMHOOKS) * sizeof(struct ebt_u_stack)); if (!stack) ebt_print_memory(); } /* Check for loops, starting from every base chain */ for (i = 0; i < NF_BR_NUMHOOKS; i++) { - if (!(replace->valid_hooks & (1 << i))) + if (!(replace->hook_entry[i])) continue; entries = ebt_nr_to_chain(replace, i); /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain |