From 6622a01ea3874e189d877c954f791259b8e6a504 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Wed, 19 Jan 2005 21:09:05 +0000 Subject: add ebtablesu scheme, along with general cleanup --- communication.c | 235 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 140 insertions(+), 95 deletions(-) (limited to 'communication.c') diff --git a/communication.c b/communication.c index af00fa2..81fca22 100644 --- a/communication.c +++ b/communication.c @@ -31,15 +31,19 @@ extern char* hooknames[NF_BR_NUMHOOKS]; int sockfd = -1; -static void get_sockfd() +static int get_sockfd() { + int ret = 0; if (sockfd == -1) { sockfd = socket(AF_INET, SOCK_RAW, PF_INET); - if (sockfd < 0) + if (sockfd < 0) { ebt_print_error("Problem getting a socket, " "you probably don't have the right " "permissions"); + ret = -1; + } } + return ret; } static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) @@ -62,7 +66,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) new->nentries = u_repl->nentries; new->num_counters = u_repl->num_counters; new->counters = sparc_cast u_repl->counters; - /* determine nr of udc */ + /* Determine nr of udc */ i = 0; cl = u_repl->udc; while (cl) { @@ -71,7 +75,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) } i += NF_BR_NUMHOOKS; chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int)); - /* determine size */ + /* Determine size */ i = 0; cl = u_repl->udc; while (1) { @@ -109,7 +113,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) sizeof(struct ebt_entry_target); e = e->next; } - /* a little sanity check */ + /* A little sanity check */ if (j != entries->nentries) ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j, entries->nentries, entries->name); @@ -123,7 +127,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) if (!p) ebt_print_memory(); - /* put everything in one block */ + /* Put everything in one block */ new->entries = sparc_cast p; i = 0; cl = u_repl->udc; @@ -147,7 +151,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) hlp->policy = entries->policy; strcpy(hlp->name, entries->name); hlp->counter_offset = entries->counter_offset; - hlp->distinguisher = 0; /* make the kernel see the light */ + hlp->distinguisher = 0; /* Make the kernel see the light */ p += sizeof(struct ebt_entries); e = entries->entries; while (e) { @@ -192,7 +196,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) { struct ebt_standard_target *st = (struct ebt_standard_target *)p; - /* translate the jump to a udc */ + /* Translate the jump to a udc */ if (st->verdict >= 0) st->verdict = chain_offsets [st->verdict + NF_BR_NUMHOOKS]; @@ -207,7 +211,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl) i++; } - /* sanity check */ + /* Sanity check */ if (p - (char *)new->entries != new->entries_size) ebt_print_bug("Entries_size bug"); free(chain_offsets); @@ -220,19 +224,22 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl) int size; FILE *file; - /* start from an empty file with right priviliges */ + /* Start from an empty file with right priviliges */ command = (char *)malloc(strlen(filename) + 15); if (!command) ebt_print_memory(); strcpy(command, "cat /dev/null>"); strcpy(command + 14, filename); - if (system(command)) + if (system(command)) { ebt_print_error("Couldn't create file %s", filename); + goto free_command; + } strcpy(command, "chmod 600 "); strcpy(command + 10, filename); - if (system(command)) + if (system(command)) { ebt_print_error("Couldn't chmod file %s", filename); - free(command); + goto free_command; + } size = sizeof(struct ebt_replace) + repl->entries_size + repl->nentries * sizeof(struct ebt_counter); @@ -242,18 +249,20 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl) memcpy(data, repl, sizeof(struct ebt_replace)); memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries, repl->entries_size); - /* initialize counters to zero, deliver_counters() can update them */ + /* Initialize counters to zero, deliver_counters() can update them */ memset(data + sizeof(struct ebt_replace) + repl->entries_size, 0, repl->nentries * sizeof(struct ebt_counter)); - if (!(file = fopen(filename, "wb"))) + if (!(file = fopen(filename, "wb"))) { ebt_print_error("Couldn't open file %s", filename); - if (fwrite(data, sizeof(char), size, file) != size) { - fclose(file); + goto free_data; + } else if (fwrite(data, sizeof(char), size, file) != size) ebt_print_error("Couldn't write everything to file %s", filename); - } fclose(file); +free_data: free(data); +free_command: + free(command); } void ebt_deliver_table(struct ebt_u_replace *u_repl) @@ -261,19 +270,20 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl) socklen_t optlen; struct ebt_replace *repl; - /* translate the struct ebt_u_replace to a struct ebt_replace */ + /* Translate the struct ebt_u_replace to a struct ebt_replace */ repl = translate_user2kernel(u_repl); if (u_repl->filename != NULL) { store_table_in_file(u_repl->filename, repl); return; } - /* give the data to the kernel */ + /* Give the data to the kernel */ optlen = sizeof(struct ebt_replace) + repl->entries_size; - get_sockfd(); + if (get_sockfd()) + return; if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen)) return; - if (u_repl->command == 8) { /* the ebtables module may not - * yet be loaded with --atomic-commit */ + if (u_repl->command == 8) { /* The ebtables module may not + * yet be loaded with --atomic-commit */ ebtables_insmod("ebtables"); if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen)) @@ -285,41 +295,46 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl) " the extension"); } -static void store_counters_in_file(char *filename, struct ebt_u_replace *repl) +static int store_counters_in_file(char *filename, struct ebt_u_replace *repl) { - int size = repl->nentries * sizeof(struct ebt_counter); + int size = repl->nentries * sizeof(struct ebt_counter), ret = 0; unsigned int entries_size; struct ebt_replace hlp; FILE *file; - if (!(file = fopen(filename, "r+b"))) + if (!(file = fopen(filename, "r+b"))) { ebt_print_error("Could not open file %s", filename); - /* - * find out entries_size and then set the file pointer to the - * counters - */ + return -1; + } + /* Find out entries_size and then set the file pointer to the + * counters */ if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET) || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) != sizeof(unsigned int) || fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) { - fclose(file); ebt_print_error("File %s is corrupt", filename); + ret = -1; + goto close_file; } if (fwrite(repl->counters, sizeof(char), size, file) != size) { - fclose(file); ebt_print_error("Could not write everything to file %s", filename); + ret = -1; } +close_file: fclose(file); + return 0; } -/* gets executed after ebt_deliver_table */ -void ebt_deliver_counters(struct ebt_u_replace *u_repl) +/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel + * and resets the counterchanges to CNT_NORM */ +void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style) { struct ebt_counter *old, *new, *newcounters; socklen_t optlen; struct ebt_replace repl; - struct ebt_cntchanges *cc = u_repl->counterchanges; + struct ebt_cntchanges *cc = u_repl->counterchanges, *cc2, **cc3; + int i; if (u_repl->nentries == 0) return; @@ -333,24 +348,22 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl) new = newcounters; while (cc) { if (cc->type == CNT_NORM) { - /* - *'normal' rule, meaning we didn't do anything to it - * So, we just copy - */ + /* 'Normal' rule, meaning we didn't do anything to it + * So, we just copy */ new->pcnt = old->pcnt; new->bcnt = old->bcnt; - /* we've used an old counter */ + /* We've used an old counter */ old++; - /* we've set a new counter */ + /* We've set a new counter */ new++; } else if (cc->type == CNT_DEL) { - /* don't use this old counter */ + /* Don't use this old counter */ old++; } else if (cc->type == CNT_ADD) { - /* new counter, let it stay 0 */ + /* New counter, let it stay 0 */ new++; } else { - /* zero it (let it stay 0) */ + /* Zero it (let it stay 0) */ old++; new++; } @@ -366,20 +379,38 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl) } optlen = u_repl->nentries * sizeof(struct ebt_counter) + sizeof(struct ebt_replace); - /* now put the stuff in the kernel's struct ebt_replace */ + /* Now put the stuff in the kernel's struct ebt_replace */ repl.counters = sparc_cast u_repl->counters; repl.num_counters = u_repl->num_counters; memcpy(repl.name, u_repl->name, sizeof(repl.name)); - get_sockfd(); + if (get_sockfd()) + return; if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen)) ebt_print_bug("Couldn't update kernel counters"); + + if (exec_style != EXEC_STYLE_DAEMON) + return; + /* Reset the counterchanges to CNT_NORM */ + cc = u_repl->counterchanges; + for (i = 0; i < u_repl->nentries; i++) { + cc->type = CNT_NORM; + cc3 = &cc->next; + cc = cc->next; + } + *cc3 = NULL; + while (cc) { + cc2 = cc->next; + free(cc); + cc = cc2; + } } static int ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l) { struct ebt_u_match_list *new; + int ret = 0; new = (struct ebt_u_match_list *) malloc(sizeof(struct ebt_u_match_list)); @@ -393,10 +424,12 @@ ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l) new->next = NULL; **l = new; *l = &new->next; - if (ebt_find_match(new->m->u.name) == NULL) + if (ebt_find_match(new->m->u.name) == NULL) { ebt_print_error("Kernel match %s unsupported by userspace tool", new->m->u.name); - return 0; + ret = -1; + } + return ret; } static int @@ -404,6 +437,7 @@ ebt_translate_watcher(struct ebt_entry_watcher *w, struct ebt_u_watcher_list ***l) { struct ebt_u_watcher_list *new; + int ret = 0; new = (struct ebt_u_watcher_list *) malloc(sizeof(struct ebt_u_watcher_list)); @@ -417,10 +451,12 @@ ebt_translate_watcher(struct ebt_entry_watcher *w, new->next = NULL; **l = new; *l = &new->next; - if (ebt_find_watcher(new->w->u.name) == NULL) + if (ebt_find_watcher(new->w->u.name) == NULL) { ebt_print_error("Kernel watcher %s unsupported by userspace " "tool", new->w->u.name); - return 0; + ret = -1; + } + return ret; } static int @@ -428,7 +464,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl, unsigned int valid_hooks, char *base) { - /* an entry */ + /* An entry */ if (e->bitmask & EBT_ENTRY_OR_ENTRIES) { struct ebt_u_entry *new; struct ebt_u_match_list **m_l; @@ -440,7 +476,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, ebt_print_memory(); new->bitmask = e->bitmask; /* - * plain userspace code doesn't know about + * Plain userspace code doesn't know about * EBT_ENTRY_OR_ENTRIES */ new->bitmask &= ~EBT_ENTRY_OR_ENTRIES; @@ -467,12 +503,14 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, malloc(t->target_size + sizeof(struct ebt_entry_target)); if (!new->t) ebt_print_memory(); - if (ebt_find_target(t->u.name) == NULL) + if (ebt_find_target(t->u.name) == NULL) { ebt_print_error("Kernel target %s unsupported by " "userspace tool", t->u.name); + return -1; + } memcpy(new->t, t, t->target_size + sizeof(struct ebt_entry_target)); - /* deal with jumps to udc */ + /* Deal with jumps to udc */ if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) { char *tmp = base; int verdict = ((struct ebt_standard_target *)t)->verdict; @@ -488,7 +526,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, cl = cl->next; } if (!cl) - ebt_print_bug("can't find udc for " + ebt_print_bug("Can't find udc for " "jump"); ((struct ebt_standard_target *)new->t)->verdict = i; } @@ -500,7 +538,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, (*cnt)++; (*totalcnt)++; return 0; - } else { /* a new chain */ + } else { /* A new chain */ int i; struct ebt_entries *entries = (struct ebt_entries *)e; struct ebt_u_chain_list *cl; @@ -513,8 +551,8 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, if (valid_hooks & (1 << i)) break; *hook = i; - /* makes use of fact that standard chains come before udc */ - if (i >= NF_BR_NUMHOOKS) { /* udc */ + /* Makes use of fact that standard chains come before udc */ + if (i >= NF_BR_NUMHOOKS) { /* Udc */ i -= NF_BR_NUMHOOKS; cl = u_repl->udc; while (i-- > 0) @@ -526,7 +564,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt, } } -/* initialize all chain headers */ +/* Initialize all chain headers */ static int ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, struct ebt_u_replace *u_repl, unsigned int valid_hooks) @@ -540,10 +578,10 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++) if (valid_hooks & (1 << i)) break; - /* makes use of fact that standard chains come before udc */ - if (i >= NF_BR_NUMHOOKS) { /* udc */ + /* Makes use of fact that standard chains come before udc */ + if (i >= NF_BR_NUMHOOKS) { /* Udc */ chain_list = &u_repl->udc; - /* add in the back */ + /* Add in the back */ while (*chain_list) chain_list = &((*chain_list)->next); *chain_list = (struct ebt_u_chain_list *) @@ -556,10 +594,8 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, if (!((*chain_list)->udc)) ebt_print_memory(); new = (*chain_list)->udc; - /* - * ebt_translate_entry depends on this for knowing - * to which chain is being jumped - */ + /* ebt_translate_entry depends on this for knowing + * to which chain is being jumped */ (*chain_list)->kernel_start = (char *)e; } else { *hook = i; @@ -578,19 +614,19 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook, return 0; } -static void retrieve_from_file(char *filename, struct ebt_replace *repl, +static int retrieve_from_file(char *filename, struct ebt_replace *repl, char command) { FILE *file; char *hlp = NULL, *entries; struct ebt_counter *counters; - int size; + int size, ret = 0; - if (!(file = fopen(filename, "r+b"))) + if (!(file = fopen(filename, "r+b"))) { ebt_print_error("Could not open file %s", filename); - /* - * make sure table name is right if command isn't -L or --atomic-commit - */ + return -1; + } + /* Make sure table name is right if command isn't -L or --atomic-commit */ if (command != 'L' && command != 8) { hlp = (char *)malloc(strlen(repl->name) + 1); if (!hlp) @@ -598,25 +634,30 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, strcpy(hlp, repl->name); } if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file) - != sizeof(struct ebt_replace)) + != sizeof(struct ebt_replace)) { ebt_print_error("File %s is corrupt", filename); + ret = -1; + goto close_file; + } if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) { - fclose(file); ebt_print_error("File %s contains wrong table name or is " "corrupt", filename); - free(hlp); + ret = -1; + goto close_file; } else if (!ebt_find_table(repl->name)) { - fclose(file); ebt_print_error("File %s contains invalid table name", filename); + ret = -1; + goto close_file; } size = sizeof(struct ebt_replace) + repl->nentries * sizeof(struct ebt_counter) + repl->entries_size; fseek(file, 0, SEEK_END); if (size != ftell(file)) { - fclose(file); ebt_print_error("File %s has wrong size", filename); + ret -1; + goto close_file; } entries = (char *)malloc(repl->entries_size); if (!entries) @@ -630,7 +671,7 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, ebt_print_memory(); } else repl->counters = sparc_cast NULL; - /* copy entries and counters */ + /* Copy entries and counters */ if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) || fread((char *)repl->entries, sizeof(char), repl->entries_size, file) != repl->entries_size || @@ -639,10 +680,15 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl, || fread((char *)repl->counters, sizeof(char), repl->nentries * sizeof(struct ebt_counter), file) != repl->nentries * sizeof(struct ebt_counter)) { - fclose(file); ebt_print_error("File %s is corrupt", filename); + free(entries); + repl->entries = NULL; + ret = -1; } +close_file: fclose(file); + free(hlp); + return ret; } static int retrieve_from_kernel(struct ebt_replace *repl, char command, @@ -653,7 +699,8 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, char *entries; optlen = sizeof(struct ebt_replace); - get_sockfd(); + if (get_sockfd()) + return -1; /* --atomic-init || --init-table */ if (init) optname = EBT_SO_GET_INIT_INFO; @@ -676,7 +723,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, else repl->counters = sparc_cast NULL; - /* we want to receive the counters */ + /* We want to receive the counters */ repl->num_counters = repl->nentries; optlen += repl->entries_size + repl->num_counters * sizeof(struct ebt_counter); @@ -685,7 +732,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command, else optname = EBT_SO_GET_ENTRIES; if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen)) - ebt_print_bug("hmm, what is wrong??? bug#1"); + ebt_print_bug("Hmm, what is wrong??? bug#1"); return 0; } @@ -701,17 +748,16 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init) strcpy(repl.name, u_repl->name); if (u_repl->filename != NULL) { if (init) - ebt_print_bug("getting initial table data from a " + ebt_print_bug("Getting initial table data from a " "file is impossible"); - retrieve_from_file(u_repl->filename, &repl, u_repl->command); - /* - * -L with a wrong table name should be dealt with silently - */ + if (retrieve_from_file(u_repl->filename, &repl, u_repl->command)) + return -1; + /* -L with a wrong table name should be dealt with silently */ strcpy(u_repl->name, repl.name); - } else if (retrieve_from_kernel(&repl, u_repl->command, init) == -1) + } else if (retrieve_from_kernel(&repl, u_repl->command, init)) return -1; - /* translate the struct ebt_replace to a struct ebt_u_replace */ + /* Translate the struct ebt_replace to a struct ebt_u_replace */ u_repl->valid_hooks = repl.valid_hooks; u_repl->nentries = repl.nentries; u_repl->num_counters = repl.num_counters; @@ -729,14 +775,13 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init) prev_cc = &(new_cc->next); } hook = -1; + /* FIXME: Clean up when an error is encountered */ EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains, &hook, u_repl, u_repl->valid_hooks); - i = 0; /* holds the expected nr. of entries for the chain */ - j = 0; /* holds the up to now counted entries for the chain */ - /* - * holds the total nr. of entries, - * should equal u_repl->nentries afterwards - */ + i = 0; /* Holds the expected nr. of entries for the chain */ + j = 0; /* Holds the up to now counted entries for the chain */ + /* Holds the total nr. of entries, + * should equal u_repl->nentries afterwards */ k = 0; hook = -1; EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size, -- cgit v1.2.3