X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fiptables-test.c;h=5634eaef35410244c56c21d8575333afda6ff5b5;hb=05ae1fe8a02326a7cdae03fe73dc5936bc114dda;hp=891d219baf4d63f28585a893eed4ea39137887a9;hpb=d9ccd472903ec7b46bf88571961c35d5d3489dab;p=framework%2Fconnectivity%2Fconnman.git diff --git a/tools/iptables-test.c b/tools/iptables-test.c index 891d219..5634eae 100644 --- a/tools/iptables-test.c +++ b/tools/iptables-test.c @@ -82,9 +82,8 @@ struct ipt_error_target { }; struct connman_iptables_entry { + int offset; int builtin; - int std_target; - int jump_offset; struct ipt_entry *entry; }; @@ -99,6 +98,9 @@ struct connman_iptables { unsigned int old_entries; unsigned int size; + unsigned int underflow[NF_INET_NUMHOOKS]; + unsigned int hook_entry[NF_INET_NUMHOOKS]; + GList *entries; }; @@ -158,16 +160,41 @@ static gboolean is_builtin_target(char *target_name) return FALSE; } +static gboolean is_jump(struct connman_iptables_entry *e) +{ + struct xt_entry_target *target; + + target = ipt_get_target(e->entry); + + if (!strcmp(target->u.user.name, IPT_STANDARD_TARGET)) { + struct xt_standard_target *t; + + t = (struct xt_standard_target *)target; + + switch (t->verdict) { + case XT_RETURN: + case -NF_ACCEPT - 1: + case -NF_DROP - 1: + case -NF_QUEUE - 1: + case -NF_STOP - 1: + return false; + + default: + return true; + } + } + + return false; +} + static gboolean is_chain(struct connman_iptables *table, struct connman_iptables_entry *e) { - int builtin; struct ipt_entry *entry; struct xt_entry_target *target; entry = e->entry; - builtin = is_hook_entry(table, entry); - if (builtin >= 0) + if (e->builtin >= 0) return TRUE; target = ipt_get_target(entry); @@ -177,6 +204,34 @@ static gboolean is_chain(struct connman_iptables *table, return FALSE; } +static GList *find_chain_head(struct connman_iptables *table, + char *chain_name) +{ + GList *list; + struct connman_iptables_entry *head; + struct ipt_entry *entry; + struct xt_entry_target *target; + int builtin; + + for (list = table->entries; list; list = list->next) { + head = list->data; + entry = head->entry; + + /* Buit-in chain */ + builtin = head->builtin; + if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name)) + break; + + /* User defined chain */ + target = ipt_get_target(entry); + if (!strcmp(target->u.user.name, IPT_ERROR_TARGET) && + !strcmp((char *)target->data, chain_name)) + break; + } + + return list; +} + static GList *find_chain_tail(struct connman_iptables *table, char *chain_name) { @@ -192,7 +247,7 @@ static GList *find_chain_tail(struct connman_iptables *table, entry = head->entry; /* Buit-in chain */ - builtin = is_hook_entry(table, entry); + builtin = head->builtin; if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name)) break; @@ -221,10 +276,35 @@ static GList *find_chain_tail(struct connman_iptables *table, return g_list_last(table->entries); } +static void update_offsets(struct connman_iptables *table) +{ + GList *list, *prev; + struct connman_iptables_entry *entry, *prev_entry; + + for (list = table->entries; list; list = list->next) { + entry = list->data; + + if (list == table->entries) { + entry->offset = 0; + + continue; + } + + prev = list->prev; + prev_entry = prev->data; + + entry->offset = prev_entry->offset + + prev_entry->entry->next_offset; + } +} + static int connman_add_entry(struct connman_iptables *table, - struct ipt_entry *entry, GList *before) + struct ipt_entry *entry, GList *before, + int builtin) { - struct connman_iptables_entry *e; + GList *list; + struct connman_iptables_entry *e, *tmp, *entry_before; + struct xt_standard_target *t; if (table == NULL) return -1; @@ -234,11 +314,71 @@ static int connman_add_entry(struct connman_iptables *table, return -1; e->entry = entry; + e->builtin = builtin; table->entries = g_list_insert_before(table->entries, before, e); table->num_entries++; table->size += entry->next_offset; + if (before == NULL) { + e->offset = table->size - entry->next_offset; + + return 0; + } + + entry_before = before->data; + + /* + * We've just insterted a new entry. All references before it + * should be bumped accordingly. + */ + for (list = table->entries; list != before; list = list->next) { + tmp = list->data; + + if (!is_jump(tmp)) + continue; + + t = (struct xt_standard_target *)ipt_get_target(tmp->entry); + + if (t->verdict >= entry_before->offset) + t->verdict += entry->next_offset; + } + + update_offsets(table); + + return 0; +} + +static int connman_iptables_delete_chain(struct connman_iptables *table, + char *name) +{ + GList *chain_head, *chain_tail, *list, *next; + struct connman_iptables_entry *entry; + + chain_head = find_chain_head(table, name); + if (chain_head == NULL) + return -EINVAL; + + chain_tail = find_chain_tail(table, name); + if (chain_tail == NULL) + return -EINVAL; + + list = chain_head; + + while (list != chain_tail) { + entry = list->data; + next = g_list_next(list); + + table->num_entries--; + table->size -= entry->entry->next_offset; + + table->entries = g_list_remove(table->entries, list->data); + + list = next; + } + + update_offsets(table); + return 0; } @@ -280,7 +420,7 @@ static int connman_iptables_add_chain(struct connman_iptables *table, error->t.u.user.target_size = ALIGN(sizeof(struct ipt_error_target)); strcpy(error->error, name); - if (connman_add_entry(table, entry_head, last) < 0) + if (connman_add_entry(table, entry_head, last, -1) < 0) goto err; /* tail entry */ @@ -300,7 +440,7 @@ static int connman_iptables_add_chain(struct connman_iptables *table, ALIGN(sizeof(struct ipt_standard_target)); standard->verdict = XT_RETURN; - if (connman_add_entry(table, entry_return, last) < 0) + if (connman_add_entry(table, entry_return, last, -1) < 0) goto err; return 0; @@ -313,26 +453,23 @@ err: } static struct ipt_entry * -new_builtin_rule(char *target_name, - char *match_name, int match_argc, char **match_argv) +new_rule(struct connman_iptables *table, + char *target_name, struct xtables_target *xt_t, + char *match_name, struct xtables_match *xt_m) { struct ipt_entry *new_entry; size_t match_size, target_size; - struct xtables_match *xt_m; - struct xt_standard_target *target; - - xt_m = NULL; - match_size = 0; - - if (match_name) { - xt_m = xtables_find_match(match_name, XTF_TRY_LOAD, NULL); - if (xt_m == NULL) - return NULL; + int is_builtin = is_builtin_target(target_name); - match_size = ALIGN(sizeof(struct xt_entry_match)) + xt_m->size; - } + if (xt_m) + match_size = xt_m->m->u.match_size; + else + match_size = 0; - target_size = ALIGN(sizeof(struct xt_standard_target)); + if (xt_t) + target_size = ALIGN(xt_t->t->u.target_size); + else + target_size = ALIGN(sizeof(struct xt_standard_target)); new_entry = g_try_malloc0(sizeof(struct ipt_entry) + target_size + match_size); @@ -342,69 +479,124 @@ new_builtin_rule(char *target_name, new_entry->target_offset = sizeof(struct ipt_entry) + match_size; new_entry->next_offset = sizeof(struct ipt_entry) + target_size + match_size; - if (xt_m) { struct xt_entry_match *entry_match; entry_match = (struct xt_entry_match *)new_entry->elems; - entry_match->u.match_size = match_size; - strcpy(entry_match->u.user.name, xt_m->name); - entry_match->u.user.revision = xt_m->revision; - if (xt_m->init != NULL) - xt_m->init(entry_match); + memcpy(entry_match, xt_m->m, match_size); } - target = (struct xt_standard_target *)(new_entry->elems + match_size); - strcpy(target->target.u.user.name, IPT_STANDARD_TARGET); - target->target.u.user.target_size = - ALIGN(sizeof(struct ipt_standard_target)); - target->verdict = target_to_verdict(target_name); + if (xt_t) { + struct xt_entry_target *entry_target; + + if (is_builtin) { + struct xt_standard_target *target; + + target = (struct xt_standard_target *)(xt_t->t); + strcpy(target->target.u.user.name, IPT_STANDARD_TARGET); + target->verdict = target_to_verdict(target_name); + } + + entry_target = ipt_get_target(new_entry); + memcpy(entry_target, xt_t->t, target_size); + } else { + struct connman_iptables_entry *target_rule; + struct xt_standard_target *target; + GList *chain_head; + + /* + * This is a user defined target, i.e. a chain jump. + * We search for the chain head, and the target verdict + * is the first rule's offset on this chain. + * The offset is from the beginning of the table. + */ + + chain_head = find_chain_head(table, target_name); + if (chain_head == NULL || chain_head->next == NULL) { + g_free(new_entry); + return NULL; + } + + target_rule = chain_head->next->data; + + target = (struct xt_standard_target *)ipt_get_target(new_entry); + strcpy(target->target.u.user.name, IPT_STANDARD_TARGET); + target->target.u.user.target_size = target_size; + target->verdict = target_rule->offset; + } return new_entry; } -static struct ipt_entry * -new_custom_rule(char *target_name, int target_argc, char **target_argv, - char *match_name, int match_argc, char **match_argv) +static void update_hooks(struct connman_iptables *table, GList *chain_head, struct ipt_entry *entry) { - return NULL; -} + GList *list; + struct connman_iptables_entry *head, *e; + int builtin; -static struct ipt_entry * -new_rule(char *target_name, int target_argc, char **target_argv, - char *match_name, int match_argc, char **match_argv) -{ - struct ipt_entry *new_entry; + if (chain_head == NULL) + return; - if (is_builtin_target(target_name)) - new_entry = new_builtin_rule(target_name, - match_name, match_argc, match_argv); - else - new_entry = new_custom_rule(target_name, - target_argc, target_argv, - match_name, match_argc, match_argv); + head = chain_head->data; - return new_entry; + builtin = head->builtin; + if (builtin < 0) + return; + + table->underflow[builtin] += entry->next_offset; + + for (list = chain_head->next; list; list = list->next) { + e = list->data; + + builtin = e->builtin; + if (builtin < 0) + continue; + + table->hook_entry[builtin] += entry->next_offset; + table->underflow[builtin] += entry->next_offset; + } } static int connman_iptables_add_rule(struct connman_iptables *table, char *chain_name, - char *target_name, int target_argc, char **target_argv, - char *match_name, int match_argc, char **match_argv) + char *target_name, struct xtables_target *xt_t, + char *match_name, struct xtables_match *xt_m) { - GList *chain_tail; + GList *chain_tail, *chain_head; struct ipt_entry *new_entry; + struct connman_iptables_entry *head; + int builtin = -1; + + chain_head = find_chain_head(table, chain_name); + if (chain_head == NULL) + return -EINVAL; chain_tail = find_chain_tail(table, chain_name); if (chain_tail == NULL) return -EINVAL; - new_entry = new_rule(target_name, target_argc, target_argv, - match_name, match_argc, match_argv); + new_entry = new_rule(table, + target_name, xt_t, + match_name, xt_m); if (new_entry == NULL) return -EINVAL; - return connman_add_entry(table, new_entry, chain_tail->prev); + update_hooks(table, chain_head, new_entry); + + /* + * If the chain is builtin, and does not have any rule, + * then the one that we're inserting is becoming the head + * and thus needs the builtin flag. + */ + head = chain_head->data; + if (head->builtin < 0) + builtin = -1; + else if (chain_head == chain_tail->prev) { + head->builtin = -1; + builtin = head->builtin; + } + + return connman_add_entry(table, new_entry, chain_tail->prev, builtin); } static struct ipt_replace * @@ -435,10 +627,8 @@ connman_iptables_blob(struct connman_iptables *table) r->num_counters = table->old_entries; r->valid_hooks = table->info->valid_hooks; - memcpy(r->hook_entry, table->info->hook_entry, - sizeof(table->info->hook_entry)); - memcpy(r->underflow, table->info->underflow, - sizeof(table->info->underflow)); + memcpy(r->hook_entry, table->hook_entry, sizeof(table->hook_entry)); + memcpy(r->underflow, table->underflow, sizeof(table->underflow)); entry_index = (unsigned char *)r->entries; for (list = table->entries; list; list = list->next) { @@ -499,14 +689,17 @@ static void dump_target(struct connman_iptables *table, if(xt_t->print != NULL) xt_t->print(NULL, target, 1); } else { - printf("\ttarget %s\n", target->u.user.name); - xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD); - if (xt_t == NULL) + if (xt_t == NULL) { + printf("\ttarget %s\n", target->u.user.name); return; + } - if(xt_t->print != NULL) + if(xt_t->print != NULL) { + printf("\ttarget "); xt_t->print(NULL, target, 1); + printf("\n"); + } } } @@ -515,6 +708,9 @@ static void dump_match(struct connman_iptables *table, struct ipt_entry *entry) struct xtables_match *xt_m; struct xt_entry_match *match; + if (entry->elems == (unsigned char *)entry + entry->target_offset) + return; + match = (struct xt_entry_match *) entry->elems; if (!strlen(match->u.user.name)) @@ -579,6 +775,22 @@ static int connman_iptables_dump_entry(struct ipt_entry *entry, return 0; } +static void connman_iptables_dump_hook(struct connman_iptables *table) +{ + int i; + printf("hooks: \n"); + for (i = 0; i < NF_INET_NUMHOOKS; i++) { + if ((table->info->valid_hooks & (1 << i))) + printf("%s entry 0x%x underflow 0x%x (0x%x)\n", + hooknames[i], + (unsigned int)table->blob_entries->entrytable + + table->info->hook_entry[i], + (unsigned int)table->blob_entries->entrytable + + table->info->underflow[i], + table->info->underflow[i]); + } +} + static void connman_iptables_dump(struct connman_iptables *table) { printf("%s valid_hooks=0x%08x, num_entries=%u, size=%u\n", @@ -586,6 +798,8 @@ static void connman_iptables_dump(struct connman_iptables *table) table->info->valid_hooks, table->info->num_entries, table->info->size); + connman_iptables_dump_hook(table); + ENTRY_ITERATE(table->blob_entries->entrytable, table->blob_entries->size, connman_iptables_dump_entry, table); @@ -611,10 +825,22 @@ static int connman_iptables_replace(struct connman_iptables *table, static void connman_iptables_cleanup(struct connman_iptables *table) { + GList *list; + struct connman_iptables_entry *entry; + close(table->ipt_sock); + + for (list = table->entries; list; list = list->next) { + entry = list->data; + + g_free(entry->entry); + } + g_free(table->info); g_free(table->blob_entries); g_free(table); + + xtables_free_opts(1); } static int connman_iptables_commit(struct connman_iptables *table) @@ -628,7 +854,18 @@ static int connman_iptables_commit(struct connman_iptables *table) static int add_entry(struct ipt_entry *entry, struct connman_iptables *table) { - return connman_add_entry(table, entry, NULL); + struct ipt_entry *new_entry; + int builtin; + + new_entry = g_try_malloc0(entry->next_offset); + if (new_entry == NULL) + return -ENOMEM; + + memcpy(new_entry, entry, entry->next_offset); + + builtin = is_hook_entry(table, entry); + + return connman_add_entry(table, new_entry, NULL, builtin); } static struct connman_iptables *connman_iptables_init(const char *table_name) @@ -669,6 +906,11 @@ static struct connman_iptables *connman_iptables_init(const char *table_name) table->old_entries = table->info->num_entries; table->size = 0; + memcpy(table->underflow, table->info->underflow, + sizeof(table->info->underflow)); + memcpy(table->hook_entry, table->info->hook_entry, + sizeof(table->info->hook_entry)); + ENTRY_ITERATE(table->blob_entries->entrytable, table->blob_entries->size, add_entry, table); @@ -688,47 +930,87 @@ static struct option connman_iptables_opts[] = { {.name = "append", .has_arg = 1, .val = 'A'}, {.name = "list", .has_arg = 2, .val = 'L'}, {.name = "new-chain", .has_arg = 1, .val = 'N'}, + {.name = "delete-chain", .has_arg = 1, .val = 'X'}, {.name = "in-interface", .has_arg = 1, .val = 'i'}, {.name = "jump", .has_arg = 1, .val = 'j'}, {.name = "match", .has_arg = 1, .val = 'm'}, {.name = "out-interface", .has_arg = 1, .val = 'o'}, + {.name = "table", .has_arg = 1, .val = 't'}, {NULL}, }; +struct xtables_globals connman_iptables_globals = { + .option_offset = 0, + .opts = connman_iptables_opts, + .orig_opts = connman_iptables_opts, +}; + int main(int argc, char *argv[]) { struct connman_iptables *table; - char *chain, *new_chain, *match_name, *target_name; + struct xtables_match *xt_m; + struct xtables_target *xt_t; + char *table_name, *chain, *new_chain, *match_name, *target_name; + char *delete_chain; int c; - gboolean dump; + size_t size; + gboolean dump, invert, delete; - xtables_init(); - xtables_set_nfproto(NFPROTO_IPV4); - - table = connman_iptables_init("filter"); - if (table == NULL) - return -1; + xtables_init_all(&connman_iptables_globals, NFPROTO_IPV4); dump = FALSE; - chain = new_chain = match_name = target_name = NULL; + invert = FALSE; + delete = FALSE; + table_name = chain = new_chain = match_name = target_name = NULL; + delete_chain = NULL; + table = NULL; + xt_m = NULL; + xt_t = NULL; while ((c = getopt_long(argc, argv, - "-A:L::N:j:i:m:o:", connman_iptables_opts, NULL)) != -1) { + "-A:L::N:X:j:i:m:o:t:", connman_iptables_globals.opts, NULL)) != -1) { switch (c) { case 'A': chain = optarg; break; case 'L': - dump = TRUE; + dump = true; break; case 'N': new_chain = optarg; break; + case 'X': + delete = true; + delete_chain = optarg; + break; + case 'j': target_name = optarg; + xt_t = xtables_find_target(target_name, XTF_TRY_LOAD); + + if (xt_t == NULL) + break; + + size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size; + + xt_t->t = g_try_malloc0(size); + if (xt_t->t == NULL) + goto out; + xt_t->t->u.target_size = size; + strcpy(xt_t->t->u.user.name, target_name); + xt_t->t->u.user.revision = xt_t->revision; + if (xt_t->init != NULL) + xt_t->init(xt_t->t); + connman_iptables_globals.opts = + xtables_merge_options(connman_iptables_globals.opts, + xt_t->extra_opts, + &xt_t->option_offset); + if (connman_iptables_globals.opts == NULL) + goto out; + break; case 'i': @@ -736,17 +1018,82 @@ int main(int argc, char *argv[]) case 'm': match_name = optarg; + + xt_m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, NULL); + size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size; + xt_m->m = g_try_malloc0(size); + if (xt_m == NULL) + goto out; + xt_m->m->u.match_size = size; + strcpy(xt_m->m->u.user.name, xt_m->name); + xt_m->m->u.user.revision = xt_m->revision; + if (xt_m->init != NULL) + xt_m->init(xt_m->m); + if (xt_m != xt_m->next) { + connman_iptables_globals.opts = + xtables_merge_options(connman_iptables_globals.opts, + xt_m->extra_opts, + &xt_m->option_offset); + if (connman_iptables_globals.opts == NULL) + goto out; + } + break; case 'o': break; + case 't': + table_name = optarg; + break; + + case 1: + if (optarg[0] == '!' && optarg[1] == '\0') { + if (invert) + printf("Consecutive ! not allowed\n"); + + invert = TRUE; + optarg[0] = '\0'; + continue; + } + + printf("Invalid option\n"); + + return -1; + default: - printf("default %s\n", optarg); + if (xt_t == NULL || xt_t->parse == NULL || + !xt_t->parse(c - xt_t->option_offset, argv, invert, + &xt_t->tflags, NULL, &xt_t->t)) { + if (xt_m == NULL || xt_m->parse == NULL) + break; + xt_m->parse(c - xt_m->option_offset, argv, + invert, &xt_m->mflags, NULL, &xt_m->m); + } + + break; } } + if (table_name == NULL) + table_name = "filter"; + + table = connman_iptables_init(table_name); + if (table == NULL) + return -1; + + if (delete) { + if (delete_chain == NULL) + goto out; + + printf("Delete chain %s\n", delete_chain); + + connman_iptables_delete_chain(table, delete_chain); + + goto commit; + } + if (dump) { connman_iptables_dump(table); @@ -770,9 +1117,8 @@ int main(int argc, char *argv[]) printf("Adding %s to %s (match %s)\n", target_name, chain, match_name); - connman_iptables_add_rule(table, chain, - target_name, 0, NULL, - match_name, 0, NULL); + connman_iptables_add_rule(table, chain, target_name, xt_t, + match_name, xt_m); goto commit; } @@ -781,7 +1127,14 @@ commit: connman_iptables_commit(table); +out: connman_iptables_cleanup(table); + if (xt_t) + g_free(xt_t->t); + + if (xt_m) + g_free(xt_m->m); + return 0; }