From 98984a8c623b592ddfb3b30ac92615422849eab3 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 19 Jan 2005 21:09:05 +0000 Subject: add ebtablesu scheme, along with general cleanup --- userspace/ebtables2/libebtc.c | 535 +++++++++++++++++------------------------- 1 file changed, 221 insertions(+), 314 deletions(-) (limited to 'userspace/ebtables2/libebtc.c') diff --git a/userspace/ebtables2/libebtc.c b/userspace/ebtables2/libebtc.c index dfc277b..0fef235 100644 --- a/userspace/ebtables2/libebtc.c +++ b/userspace/ebtables2/libebtc.c @@ -40,9 +40,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace); static void remove_udc(struct ebt_u_replace *replace); static int iterate_entries(struct ebt_u_replace *replace, int type); -/* - * The standard names - */ +/* The standard names */ const char *ebt_hooknames[NF_BR_NUMHOOKS] = { [NF_BR_PRE_ROUTING]"PREROUTING", @@ -53,9 +51,7 @@ const char *ebt_hooknames[NF_BR_NUMHOOKS] = [NF_BR_BROUTING]"BROUTING" }; -/* - * The four target names - */ +/* The four target names */ const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = { "ACCEPT", @@ -64,22 +60,18 @@ const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = "RETURN", }; -/* - * The lists of supported tables, matches, watchers and targets - */ +/* The lists of supported tables, matches, watchers and targets */ struct ebt_u_table *ebt_tables; struct ebt_u_match *ebt_matches; struct ebt_u_watcher *ebt_watchers; struct ebt_u_target *ebt_targets; -/* - * Find the right structure belonging to a name - */ +/* Find the right structure belonging to a name */ struct ebt_u_target *ebt_find_target(const char *name) { struct ebt_u_target *t = ebt_targets; - while(t && strcmp(t->name, name)) + while (t && strcmp(t->name, name)) t = t->next; return t; } @@ -88,7 +80,7 @@ struct ebt_u_match *ebt_find_match(const char *name) { struct ebt_u_match *m = ebt_matches; - while(m && strcmp(m->name, name)) + while (m && strcmp(m->name, name)) m = m->next; return m; } @@ -97,7 +89,7 @@ struct ebt_u_watcher *ebt_find_watcher(const char *name) { struct ebt_u_watcher *w = ebt_watchers; - while(w && strcmp(w->name, name)) + while (w && strcmp(w->name, name)) w = w->next; return w; } @@ -111,9 +103,7 @@ struct ebt_u_table *ebt_find_table(const char *name) return t; } -/* - * Prints all registered extensions - */ +/* Prints all registered extensions */ void ebt_list_extensions() { struct ebt_u_table *tbl = ebt_tables; @@ -123,59 +113,51 @@ void ebt_list_extensions() PRINT_VERSION; printf("Supported userspace extensions:\n\nSupported tables:\n"); - while(tbl) { + while (tbl) { printf("%s\n", tbl->name); tbl = tbl->next; } printf("\nSupported targets:\n"); - while(t) { + while (t) { printf("%s\n", t->name); t = t->next; } printf("\nSupported matches:\n"); - while(m) { + while (m) { printf("%s\n", m->name); m = m->next; } printf("\nSupported watchers:\n"); - while(w) { + while (w) { printf("%s\n", w->name); w = w->next; } - exit(0); } -/* - * Get the table from the kernel or from a binary file +/* Get the table from the kernel or from a binary file * init: 1 = ask the kernel for the initial contents of a table, i.e. the * way it looks when the table is insmod'ed - * 0 = get the current data in the table - */ -void ebt_get_kernel_table(struct ebt_u_replace *replace, - struct ebt_u_table *table, int init) + * 0 = get the current data in the table */ +int ebt_get_kernel_table(struct ebt_u_replace *replace, int init) { - if ( !(table = ebt_find_table(replace->name)) ) + if (!ebt_find_table(replace->name)) { ebt_print_error("Bad table name"); - /* - * get the kernel's information - */ + return -1; + } + /* Get the kernel's information */ if (ebt_get_table(replace, init)) { + if (ebt_errormsg[0] != '\0') + return -1; ebtables_insmod("ebtables"); - if (ebt_get_table(replace, init)) - ebt_print_error("The kernel doesn't support the " - "ebtables %s table", replace->name); + if (ebt_get_table(replace, init)) { + ebt_print_error("The kernel doesn't support the ebtables %s table", replace->name); + return -1; + } } - /* - * when listing a table contained in a file, we don't demand that - * the user knows the table's name, so we update table if necessary - */ - if ( !(table = ebt_find_table(replace->name)) ) - ebt_print_error("Bad table name"); + return 0; } -/* - * Put sane values into a new entry - */ +/* Put sane values into a new entry */ void ebt_initialize_entry(struct ebt_u_entry *e) { e->bitmask = EBT_NOPROTO; @@ -188,16 +170,14 @@ void ebt_initialize_entry(struct ebt_u_entry *e) e->m_list = NULL; e->w_list = NULL; e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET); + ebt_find_target(EBT_STANDARD_TARGET)->used = 1; if (!e->t) ebt_print_bug("Couldn't load standard target"); - ((struct ebt_standard_target *) - ((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE; + ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE; } -/* - * replace is reborn, i.e. rebirth of replace - */ +/* Free up the memory of the table held in userspace, *replace can be reused */ void ebt_cleanup_replace(struct ebt_u_replace *replace) { int i; @@ -245,6 +225,7 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) } udc1 = replace->udc; while (udc1) { + free(udc1->udc); udc2 = udc1->next; free(udc1); udc1 = udc2; @@ -259,10 +240,8 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace) replace->counterchanges = NULL; } -/* - * Should be called between 2 rule adds, f.e. - */ -void ebt_reinit_extensions(struct ebt_u_replace *replace) +/* Should be called, e.g., between 2 rule adds */ +void ebt_reinit_extensions() { struct ebt_u_match *m; struct ebt_u_watcher *w; @@ -273,42 +252,46 @@ void ebt_reinit_extensions(struct ebt_u_replace *replace) * called for the first time or not (when necessary). */ for (m = ebt_matches; m; m = m->next) { size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match); - if (m->m) - free(m->m); - m->m = (struct ebt_entry_match *)malloc(size); - if (!m->m) - ebt_print_memory(); - m->used = 0; - m->flags = 0; + if (m->used) { + m->m = (struct ebt_entry_match *)malloc(size); + if (!m->m) + ebt_print_memory(); + strcpy(m->m->u.name, m->name); + m->m->match_size = EBT_ALIGN(m->size); + m->used = 0; + m->flags = 0; + } m->init(m->m); } for (w = ebt_watchers; w; w = w->next) { size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher); - if (w->w) - free(w->w); - w->w = (struct ebt_entry_watcher *)malloc(size); - if (!w->w) - ebt_print_memory(); - w->used = 0; - w->flags = 0; + if (w->used) { + w->w = (struct ebt_entry_watcher *)malloc(size); + if (!w->w) + ebt_print_memory(); + strcpy(w->w->u.name, w->name); + w->w->watcher_size = EBT_ALIGN(w->size); + w->used = 0; + w->flags = 0; + } w->init(w->w); } - for (t = ebt_targets; m; t = t->next) { + for (t = ebt_targets; t; t = t->next) { size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target); - if (t->t) - free(t->t); - t->t = (struct ebt_entry_target *)malloc(size); - if (!t->t) - ebt_print_memory(); - t->used = 0; - t->flags = 0; + if (t->used) { + t->t = (struct ebt_entry_target *)malloc(size); + if (!t->t) + ebt_print_memory(); + strcpy(t->t->u.name, t->name); + t->t->target_size = EBT_ALIGN(t->size); + t->used = 0; + t->flags = 0; + } t->init(t->t); } } -/* - * This doesn't free e, becoz the calling function might need e->next - */ +/* This doesn't free e, because the calling function might need e->next */ void ebt_free_u_entry(struct ebt_u_entry *e) { struct ebt_u_match_list *m_l, *m_l2; @@ -331,10 +314,8 @@ void ebt_free_u_entry(struct ebt_u_entry *e) free(e->t); } -/* - * Blatently stolen (again) from iptables.c userspace program - * find out where the modprobe utility is located - */ +/* Blatently stolen (again) from iptables.c userspace program + * find out where the modprobe utility is located */ static char *get_modprobe(void) { int procfile; @@ -350,8 +331,8 @@ static char *get_modprobe(void) case -1: goto fail; case 1024: goto fail; /* Partial read. Wierd */ } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; + if (ret[strlen(ret)-1] == '\n') + ret[strlen(ret)-1] = 0; close(procfile); return ret; } @@ -362,9 +343,7 @@ static char *get_modprobe(void) } char *ebt_modprobe; -/* - * Try to load the kernel module - */ +/* Try to load the kernel module */ int ebtables_insmod(const char *modname) { char *buf = NULL; @@ -385,12 +364,12 @@ int ebtables_insmod(const char *modname) argv[2] = NULL; execv(argv[0], argv); - /* not usually reached */ + /* Not usually reached */ exit(0); case -1: return -1; - default: /* parent */ + default: /* Parent */ wait(NULL); } @@ -398,11 +377,9 @@ int ebtables_insmod(const char *modname) return 0; } -/* - * Gives back a pointer to the chain base, based on nr. +/* Gives back a pointer to the chain base, based on nr. * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain. - * Returns NULL on failure. - */ + * Returns NULL on failure. */ struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, int nr) { @@ -426,20 +403,16 @@ struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace, } } -/* - * Gives back a pointer to the chain base of selected_chain - */ +/* Gives back a pointer to the chain base of selected_chain */ struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace) { return ebt_nr_to_chain(replace, replace->selected_chain); } -/* - * Parse the chain name and return a pointer to the chain base. - * Returns NULL on failure. - */ +/* Parse the chain name and return a pointer to the chain base. + * Returns NULL on failure. */ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, - const char* arg) + const char* arg) { int i; struct ebt_u_chain_list *cl = replace->udc; @@ -458,10 +431,8 @@ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace, return NULL; } -/* - * Parse the chain name and return the corresponding chain nr - * returns -1 on failure - */ +/* Parse the chain name and return the corresponding chain nr + * returns -1 on failure */ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg) { int i; @@ -490,23 +461,19 @@ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg) ************ */ -/* - * Chainge the policy of selected_chain. - * No sanity checks are done. - */ +/* Change the policy of selected_chain. + * Handing a bad policy to this function is a bug. */ void ebt_change_policy(struct ebt_u_replace *replace, int policy) { struct ebt_u_entries *entries = ebt_to_chain(replace); if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE) - ebt_print_bug("wrong policy: %d", policy); + ebt_print_bug("Wrong policy: %d", policy); entries->policy = policy; } -/* - * Flush one chain or the complete table - * If selected_chain == -1: flush the complete table - */ +/* Flush one chain or the complete table + * If selected_chain == -1: flush the complete table */ void ebt_flush_chains(struct ebt_u_replace *replace) { int i, j, numdel; @@ -515,17 +482,13 @@ void ebt_flush_chains(struct ebt_u_replace *replace) struct ebt_cntchanges *cc = replace->counterchanges; struct ebt_cntchanges **prev_cc = &(replace->counterchanges); - /* - * flush whole table - */ + /* Flush whole table */ if (!entries) { if (replace->nentries == 0) return; replace->nentries = 0; - /* - * free everything and zero (n)entries - */ + /* Free everything and zero (n)entries */ i = -1; while (1) { i++; @@ -547,9 +510,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace) u_e = tmp; } } - /* - * update the counters - */ + /* Update the counters */ while (cc) { if (cc->type == CNT_ADD) { *prev_cc = cc->next; @@ -569,10 +530,8 @@ void ebt_flush_chains(struct ebt_u_replace *replace) replace->nentries -= entries->nentries; numdel = entries->nentries; - /* - * delete the counters belonging to the specified chain, - * update counter_offset - */ + /* Delete the counters belonging to the specified chain, + * update counter_offset */ i = -1; while (1) { i++; @@ -589,7 +548,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace) } j = entries->nentries; while (j) { - /* don't count deleted entries */ + /* Don't count deleted entries */ if (cc->type == CNT_DEL) goto letscontinue; if (i == replace->selected_chain) { @@ -619,15 +578,12 @@ letscontinue: u_e = tmp; } entries->entries = NULL; - return; } -/* - * returns the rule number on success (starting from 0), -1 on failure +/* Returns the rule number on success (starting from 0), -1 on failure * * This function expects the ebt_{match,watcher,target} members of new_entry - * to contain pointers to ebt_u_{match,watcher,target}. - */ + * to contain pointers to ebt_u_{match,watcher,target} */ int ebt_check_rule_exists(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry) { @@ -641,10 +597,8 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, int i, j, k; u_e = entries->entries; - /* - * check for an existing rule (if there are duplicate rules, - * take the first occurance) - */ + /* Check for an existing rule (if there are duplicate rules, + * take the first occurance) */ for (i = 0; i < entries->nentries; i++, u_e = u_e->next) { if (!u_e) ebt_print_bug("Hmm, trouble"); @@ -659,17 +613,15 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, if (strcmp(u_e->logical_out, new_entry->logical_out)) continue; if (new_entry->bitmask & EBT_SOURCEMAC && - memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN)) + memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN)) continue; if (new_entry->bitmask & EBT_DESTMAC && - memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN)) + memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN)) continue; if (new_entry->bitmask != u_e->bitmask || - new_entry->invflags != u_e->invflags) + new_entry->invflags != u_e->invflags) continue; - /* - * compare all matches - */ + /* Compare all matches */ m_l = new_entry->m_list; j = 0; while (m_l) { @@ -682,9 +634,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, j++; m_l = m_l->next; } - /* - * now be sure they have the same nr of matches - */ + /* Now be sure they have the same nr of matches */ k = 0; m_l = u_e->m_list; while (m_l) { @@ -694,9 +644,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace, if (j != k) continue; - /* - * compare all watchers - */ + /* Compare all watchers */ w_l = new_entry->w_list; j = 0; while (w_l) { @@ -732,13 +680,14 @@ letscontinue:; * rule_nr > 0 : insert the rule right before the rule_nr'th rule * (the first rule is rule 1) * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule, - * where n denotes the number of rule in the chain + * where n denotes the number of rules in the chain * rule_nr == 0: add a new rule at the end of the chain * * This function expects the ebt_{match,watcher,target} members of new_entry * to contain pointers to ebt_u_{match,watcher,target} and updates these - * pointers before adding the rule to the chain. - */ + * pointers so that they point to ebt_{match,watcher,target}, before adding + * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a + * successful call to ebt_add_rule() */ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int rule_nr) { @@ -754,17 +703,15 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, rule_nr += entries->nentries; else rule_nr--; - if (rule_nr > entries->nentries || rule_nr < 0) + if (rule_nr > entries->nentries || rule_nr < 0) { ebt_print_error("The specified rule number is incorrect"); - /* - * we're adding one rule - */ + return; + } + /* We're adding one rule */ replace->nentries++; entries->nentries++; - /* - * handle counter stuff - */ + /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; @@ -783,32 +730,26 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, prev_cc = &(cc->next); cc = cc->next; } - if (cc && cc->type == CNT_DEL) /* The add is victorious and conquers - * the delete */ + if (cc && cc->type == CNT_DEL) cc->type = CNT_OWRITE; else { new_cc = (struct ebt_cntchanges *) malloc(sizeof(struct ebt_cntchanges)); + if (!new_cc) + ebt_print_memory(); new_cc->type = CNT_ADD; new_cc->next = cc; *prev_cc = new_cc; } - - /* - * go to the right position in the chain - */ + /* Go to the right position in the chain */ u_e = &entries->entries; for (i = 0; i < rule_nr; i++) u_e = &(*u_e)->next; - /* - * insert the rule - */ + /* Insert the rule */ new_entry->next = *u_e; *u_e = new_entry; - /* - * put the ebt_[match, watcher, target] pointers in place - */ + /* Put the ebt_{match, watcher, target} pointers in place */ m_l = new_entry->m_list; while (m_l) { m_l->m = ((struct ebt_u_match *)m_l->m)->m; @@ -820,10 +761,7 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, w_l = w_l->next; } new_entry->t = ((struct ebt_u_target *)new_entry->t)->t; - - /* - * update the counter_offset of chains behind this one - */ + /* Update the counter_offset of chains behind this one */ i = replace->selected_chain; while (1) { i++; @@ -838,14 +776,12 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, } } -/* - * Delete a rule or rules +/* Delete a rule or rules * begin == end == 0: delete the rule corresponding to new_entry * - * the first rule has rule nr 1, the last rule has rule nr -1, etc. + * The first rule has rule nr 1, the last rule has rule nr -1, etc. * This function expects the ebt_{match,watcher,target} members of new_entry - * to contain pointers to ebt_u_{match,watcher,target}. - */ + * to contain pointers to ebt_u_{match,watcher,target}. */ void ebt_delete_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry, int begin, int end) { @@ -860,8 +796,10 @@ void ebt_delete_rule(struct ebt_u_replace *replace, if (end < 0) end += entries->nentries + 1; - if (begin < 0 || begin > end || end > entries->nentries) + if (begin < 0 || begin > end || end > entries->nentries) { ebt_print_error("Sorry, wrong rule numbers"); + return; + } if ((begin * end == 0) && (begin + end != 0)) ebt_print_bug("begin and end should be either both zero, " @@ -872,20 +810,18 @@ void ebt_delete_rule(struct ebt_u_replace *replace, } else { begin = ebt_check_rule_exists(replace, new_entry); end = begin; - if (begin == -1) + if (begin == -1) { ebt_print_error("Sorry, rule does not exist"); + return; + } } - /* - * we're deleting rules - */ + /* We're deleting rules */ nr_deletes = end - begin + 1; replace->nentries -= nr_deletes; entries->nentries -= nr_deletes; - /* - * handle counter stuff - */ + /* Handle counter stuff */ for (i = 0; i < replace->selected_chain; i++) { if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; @@ -920,27 +856,21 @@ void ebt_delete_rule(struct ebt_u_replace *replace, cc = cc->next; } - /* - * go to the right position in the chain - */ + /* Go to the right position in the chain */ u_e = &entries->entries; for (j = 0; j < begin; j++) u_e = &(*u_e)->next; - /* - * remove the rules - */ + /* Remove the rules */ j = nr_deletes; while(j--) { u_e2 = *u_e; *u_e = (*u_e)->next; - /* free everything */ + /* Free everything */ ebt_free_u_entry(u_e2); free(u_e2); } - /* - * update the counter_offset of chains behind this one - */ + /* Update the counter_offset of chains behind this one */ j = replace->selected_chain; while (1) { j++; @@ -955,10 +885,8 @@ void ebt_delete_rule(struct ebt_u_replace *replace, } } -/* - * Selected_chain == -1 : zero all counters - * else, zero the counters of selected_chain - */ +/* Selected_chain == -1 : zero all counters + * Otherwise, zero the counters of selected_chain */ void ebt_zero_counters(struct ebt_u_replace *replace) { struct ebt_u_entries *entries = ebt_to_chain(replace); @@ -976,8 +904,7 @@ void ebt_zero_counters(struct ebt_u_replace *replace) return; for (i = 0; i < replace->selected_chain; i++) { - if (i < NF_BR_NUMHOOKS && - !(replace->valid_hooks & (1 << i))) + if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) continue; j = ebt_nr_to_chain(replace, i)->nentries; while (j) { @@ -998,20 +925,22 @@ void ebt_zero_counters(struct ebt_u_replace *replace) } } -/* - * Add a new chain and specify its policy - */ +/* Add a new chain and specify its policy */ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy) { struct ebt_u_chain_list *cl, **cl2; - if (ebt_get_chainnr(replace, name) != -1) + if (ebt_get_chainnr(replace, name) != -1) { ebt_print_error("Chain %s already exists", optarg); - if (ebt_find_target(name)) + return; + } else if (ebt_find_target(name)) { ebt_print_error("Target with name %s exists", optarg); - if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) + return; + } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) { ebt_print_error("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); + return; + } cl = (struct ebt_u_chain_list *) malloc(sizeof(struct ebt_u_chain_list)); if (!cl) @@ -1028,39 +957,37 @@ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy) strcpy(cl->udc->name, name); cl->udc->entries = NULL; cl->kernel_start = NULL; - /* - * put the new chain at the end - */ + /* Put the new chain at the end */ cl2 = &(replace->udc); while (*cl2) cl2 = &((*cl2)->next); *cl2 = cl; } -/* - * Selected_chain == -1: delete all non-referenced udc - * selected_chain < NF_BR_NUMHOOKS is illegal - */ +/* Selected_chain == -1: delete all non-referenced udc + * selected_chain < NF_BR_NUMHOOKS is illegal */ void ebt_delete_chain(struct ebt_u_replace *replace) { - int chain_nr = replace->selected_chain; + int chain_nr = replace->selected_chain, print_error = 1; if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS) ebt_print_bug("You can't remove a standard chain"); - if (chain_nr == -1) + if (chain_nr == -1) { + print_error = 0; replace->selected_chain = NF_BR_NUMHOOKS; + } do { if (ebt_to_chain(replace) == NULL) { if (chain_nr == -1) break; ebt_print_bug("udc nr %d doesn't exist", chain_nr); } - /* - * if the chain is referenced, don't delete it, + /* If the chain is referenced, don't delete it, * also decrement jumps to a chain behind the - * one we're deleting - */ - if (ebt_check_for_references(replace)) { + * one we're deleting */ + if (ebt_check_for_references(replace, print_error)) { + if (chain_nr != -1) + break; replace->selected_chain++; continue; } @@ -1068,12 +995,10 @@ void ebt_delete_chain(struct ebt_u_replace *replace) ebt_flush_chains(replace); remove_udc(replace); } while (chain_nr == -1); - replace->selected_chain = chain_nr; + replace->selected_chain = chain_nr; /* Put back to -1 */ } -/* - * Rename an existing chain. - */ +/* Rename an existing chain. */ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name) { struct ebt_u_entries *entries = ebt_to_chain(replace); @@ -1093,11 +1018,10 @@ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name) */ -/* - * executes the final_check() function for all extensions used by the rule +/* Executes the final_check() function for all extensions used by the rule * ebt_check_for_loops should have been executed earlier, to make sure the - * hook_mask is correct. - */ + * hook_mask is correct. The time argument to final_check() is set to 1, + * meaning it's the second time the final_check() function is executed. */ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, struct ebt_u_entries *entries) { @@ -1113,12 +1037,16 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, m = ebt_find_match(m_l->m->u.name); m->final_check(e, m_l->m, replace->name, entries->hook_mask, 1); + if (ebt_errormsg[0] != '\0') + return; m_l = m_l->next; } while (w_l) { w = ebt_find_watcher(w_l->w->u.name); w->final_check(e, w_l->w, replace->name, entries->hook_mask, 1); + if (ebt_errormsg[0] != '\0') + return; w_l = w_l->next; } t = ebt_find_target(e->t->u.name); @@ -1126,26 +1054,29 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e, entries->hook_mask, 1); } -/* - * returns 1 when the chain is referenced, - * 0 when it isn't. - */ -int ebt_check_for_references(struct ebt_u_replace *replace) +/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't. + * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */ +int ebt_check_for_references(struct ebt_u_replace *replace, int print_err) { - return iterate_entries(replace, 1); + if (print_err) + return iterate_entries(replace, 1); + else + return iterate_entries(replace, 2); } -/* - * chain_nr: nr of the udc (>= NF_BR_NUMHOOKS) - * returns 1 when the chain is referenced, - * 0 when it isn't. - */ -int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr) +/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS) + * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't. + * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */ +int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr, + int print_err) { int tmp = replace->selected_chain, ret; replace->selected_chain = chain_nr; - ret = iterate_entries(replace, 1); + if (print_err) + ret = iterate_entries(replace, 1); + else + ret = iterate_entries(replace, 2); replace->selected_chain = tmp; return ret; } @@ -1158,12 +1089,10 @@ struct ebt_u_stack struct ebt_u_entries *entries; }; -/* - * Checks for loops +/* Checks for loops * As a by-product, the hook_mask member of each chain is filled in * correctly. The check functions of the extensions need this hook_mask - * to know from which standard chains they can be called. - */ + * to know from which standard chains they can be called. */ void ebt_check_for_loops(struct ebt_u_replace *replace) { int chain_nr , i, j , k, sp = 0, verdict; @@ -1172,9 +1101,7 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) struct ebt_u_entry *e; i = -1; - /* - * initialize hook_mask to 0 - */ + /* Initialize hook_mask to 0 */ while (1) { i++; if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i))) @@ -1191,17 +1118,13 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) ebt_print_memory(); } - /* - * check for loops, starting from every base chain - */ + /* Check for loops, starting from every base chain */ for (i = 0; i < NF_BR_NUMHOOKS; i++) { if (!(replace->valid_hooks & (1 << i))) continue; entries = ebt_nr_to_chain(replace, i); - /* - * (1 << NF_BR_NUMHOOKS) implies it's a standard chain - * (usefull in the final_check() funtions) - */ + /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain + * (usefull in the final_check() funtions) */ entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS); chain_nr = i; @@ -1212,20 +1135,17 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) verdict = ((struct ebt_standard_target *)(e->t))->verdict; if (verdict < 0) goto letscontinue; - entries2 = ebt_nr_to_chain(replace, - verdict + NF_BR_NUMHOOKS); + entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS); entries2->hook_mask |= entries->hook_mask; - /* - * now see if we've been here before - */ + /* Now see if we've been here before */ for (k = 0; k < sp; k++) - if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) - ebt_print_error("Loop from chain %s to chain %s", + if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) { + ebt_print_error("Loop from chain '%s' to chain '%s'", ebt_nr_to_chain(replace, chain_nr)->name, ebt_nr_to_chain(replace, stack[k].chain_nr)->name); - /* - * jump to the chain, make sure we know how to get back - */ + goto free_stack; + } + /* Jump to the chain, make sure we know how to get back */ stack[sp].chain_nr = chain_nr; stack[sp].n = j; stack[sp].entries = entries; @@ -1239,14 +1159,10 @@ void ebt_check_for_loops(struct ebt_u_replace *replace) letscontinue: e = e->next; } - /* - * we are at the end of a standard chain - */ + /* We are at the end of a standard chain */ if (sp == 0) continue; - /* - * go back to the chain one level higher - */ + /* Go back to the chain one level higher */ sp--; j = stack[sp].n; chain_nr = stack[sp].chain_nr; @@ -1254,13 +1170,16 @@ letscontinue: entries = stack[sp].entries; goto letscontinue; } +free_stack: free(stack); return; } -/* - * the user will use the match, so put it in new_entry - */ +/* The user will use the match, so put it in new_entry. The ebt_u_match + * pointer is put in the ebt_entry_match pointer. ebt_add_rule will + * fill in the final value for new->m. Unless the rule is added to a chain, + * the pointer will keep pointing to the ebt_u_match (until the new_entry + * is freed). I know, I should use a union for these 2 pointer types... */ void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m) { struct ebt_u_match_list **m_list, *new; @@ -1300,13 +1219,12 @@ void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w) */ -/* - * type = 0 => update chain jumps - * type = 1 => check for reference +/* type = 0 => update chain jumps + * type = 1 => check for reference, print error when referenced + * type = 2 => check for reference, don't print error when referenced * - * returns 1 when type == 1 and the chain is referenced - * returns 0 otherwise - */ + * Returns 1 when type == 1 and the chain is referenced + * returns 0 otherwise */ static int iterate_entries(struct ebt_u_replace *replace, int type) { int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS; @@ -1338,19 +1256,21 @@ static int iterate_entries(struct ebt_u_replace *replace, int type) verdict; switch (type) { case 1: + case 2: if (chain_jmp == chain_nr) { - ebt_print_error("Can't delete the chain, it's " - "referenced in chain %s, rule %d", - entries->name, j); + if (type == 2) + return 1; + ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d", + ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j); return 1; } break; case 0: - /* adjust the chain jumps when necessary */ + /* Adjust the chain jumps when necessary */ if (chain_jmp > chain_nr) ((struct ebt_standard_target *)e->t)->verdict--; break; - } /* end switch */ + } /* End switch */ e = e->next; } } @@ -1362,9 +1282,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace) iterate_entries(replace, 0); } -/* - * selected_chain >= NF_BR_NUMHOOKS - */ +/* Selected_chain >= NF_BR_NUMHOOKS */ static void remove_udc(struct ebt_u_replace *replace) { struct ebt_u_chain_list *cl, **cl2; @@ -1375,7 +1293,7 @@ static void remove_udc(struct ebt_u_replace *replace) if (chain_nr < NF_BR_NUMHOOKS) ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr, NF_BR_NUMHOOKS); - /* first free the rules */ + /* First free the rules */ entries = ebt_nr_to_chain(replace, chain_nr); u_e = entries->entries; while (u_e) { @@ -1395,10 +1313,7 @@ static void remove_udc(struct ebt_u_replace *replace) free(cl); } - -/* - * used in initialization code of modules - */ +/* Used in initialization code of modules */ void ebt_register_match(struct ebt_u_match *m) { int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match); @@ -1480,9 +1395,7 @@ void ebt_iterate_targets(void (*f)(struct ebt_u_target *)) f(i); } -/* - * Don't use this function, use ebt_print_bug() - */ +/* Don't use this function, use ebt_print_bug() */ void __ebt_print_bug(char *file, int line, char *format, ...) { va_list l; @@ -1495,26 +1408,20 @@ void __ebt_print_bug(char *file, int line, char *format, ...) exit (-1); } -/* - * The error messages are put in here when ebt_silent == 1 - * ebt_errormsg[0] == '\0' implies there was no error - */ +/* The error messages are put in here when ebt_silent == 1 + * ebt_errormsg[0] == '\0' implies there was no error */ char ebt_errormsg[ERRORMSG_MAXLEN]; -/* - * When error messages should not be printed on the screen, after which - * the program exit()s, set ebt_silent to 1. - */ +/* When error messages should not be printed on the screen, after which + * the program exit()s, set ebt_silent to 1. */ int ebt_silent; -/* - * Don't use this function, use ebt_print_error() - */ +/* Don't use this function, use ebt_print_error() */ void __ebt_print_error(char *format, ...) { va_list l; va_start(l, format); - if (ebt_silent) { - snprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l); + if (ebt_silent && ebt_errormsg[0] == '\0') { + vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l); va_end(l); } else { vprintf(format, l); -- cgit v1.2.3