X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fiptables-test.c;h=e9b7cb224d7aeb86bcc72b9694f766d61273e0b8;hb=3a8dc46a144e3902729553ced331a2dc0d8140fa;hp=60313aff66424342b9b72bf647e97ddf51ed5808;hpb=82998a7dcabc6434ab38914904ce78f31ceadc6a;p=platform%2Fupstream%2Fconnman.git diff --git a/tools/iptables-test.c b/tools/iptables-test.c old mode 100644 new mode 100755 index 60313af..e9b7cb2 --- a/tools/iptables-test.c +++ b/tools/iptables-test.c @@ -1,7 +1,8 @@ /* * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2013 BMW Car IT GmbH. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,1044 +20,143 @@ */ #include -#include #include -#include -#include -#include -#include -#include - -#include +#include +#include #include -static const char *hooknames[] = { - [NF_IP_PRE_ROUTING] = "PREROUTING", - [NF_IP_LOCAL_IN] = "INPUT", - [NF_IP_FORWARD] = "FORWARD", - [NF_IP_LOCAL_OUT] = "OUTPUT", - [NF_IP_POST_ROUTING] = "POSTROUTING", -}; - -#define LABEL_ACCEPT "ACCEPT" -#define LABEL_DROP "DROP" -#define LABEL_QUEUE "QUEUE" -#define LABEL_RETURN "RETURN" - -/* fn returns 0 to continue iteration */ -#define _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \ -({ \ - unsigned int __i; \ - int __n; \ - int __ret = 0; \ - type *__entry; \ - \ - for (__i = 0, __n = 0; __i < (size); \ - __i += __entry->next_offset, __n++) { \ - __entry = (void *)(entries) + __i; \ - if (__n < n) \ - continue; \ - \ - __ret = fn(__entry, ## args); \ - if (__ret != 0) \ - break; \ - } \ - __ret; \ -}) - -/* fn returns 0 to continue iteration */ -#define _XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ - _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) - -#define ENTRY_ITERATE(entries, size, fn, args...) \ - _XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) - -#define MIN_ALIGN (__alignof__(struct ipt_entry)) - -#define ALIGN(s) (((s) + ((MIN_ALIGN)-1)) & ~((MIN_ALIGN)-1)) - -struct ipt_error_target { - struct xt_entry_target t; - char error[IPT_TABLE_MAXNAMELEN]; -}; - -struct connman_iptables_entry { - int offset; - - struct ipt_entry *entry; -}; - -struct connman_iptables { - int ipt_sock; - - struct ipt_getinfo *info; - struct ipt_get_entries *blob_entries; - - unsigned int num_entries; - unsigned int old_entries; - unsigned int size; - - GList *entries; -}; - - -static struct ipt_entry *get_entry(struct connman_iptables *table, - unsigned int offset) -{ - return (struct ipt_entry *)((char *)table->blob_entries->entrytable + - offset); -} - -static int is_hook_entry(struct connman_iptables *table, - struct ipt_entry *entry) -{ - unsigned int i; - - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - if ((table->info->valid_hooks & (1 << i)) - && get_entry(table, table->info->hook_entry[i]) == entry) - return i; - } - - return -1; -} - -static unsigned long entry_to_offset(struct connman_iptables *table, - struct ipt_entry *entry) -{ - return (void *)entry - (void *)table->blob_entries->entrytable; -} - -static int target_to_verdict(char *target_name) -{ - if (!strcmp(target_name, LABEL_ACCEPT)) - return -NF_ACCEPT - 1; - - if (!strcmp(target_name, LABEL_DROP)) - return -NF_DROP - 1; - - if (!strcmp(target_name, LABEL_QUEUE)) - return -NF_QUEUE - 1; - - if (!strcmp(target_name, LABEL_RETURN)) - return XT_RETURN; - - return 0; -} - -static gboolean is_builtin_target(char *target_name) -{ - if (!strcmp(target_name, LABEL_ACCEPT) || - !strcmp(target_name, LABEL_DROP) || - !strcmp(target_name, LABEL_QUEUE) || - !strcmp(target_name, LABEL_RETURN)) - return TRUE; - - 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) - return TRUE; - - target = ipt_get_target(entry); - if (!strcmp(target->u.user.name, IPT_ERROR_TARGET)) - return TRUE; - - 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 = is_hook_entry(table, entry); - 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) -{ - GList *chain_head, *list; - struct connman_iptables_entry *head, *tail; - struct ipt_entry *entry; - struct xt_entry_target *target; - int builtin; - - /* First we look for the head */ - for (list = table->entries; list; list = list->next) { - head = list->data; - entry = head->entry; - - /* Buit-in chain */ - builtin = is_hook_entry(table, entry); - 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; - } - - if (list == NULL) - return NULL; - - chain_head = list; - - /* Then we look for the next chain */ - for (list = chain_head->next; list; list = list->next) { - tail = list->data; - entry = tail->entry; - - if (is_chain(table, tail)) - return list; - } - - /* Nothing found, we return the table end */ - 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) -{ - GList *list; - struct connman_iptables_entry *e, *tmp, *entry_before; - struct xt_standard_target *t; - - if (table == NULL) - return -1; - - e = g_try_malloc0(sizeof(struct connman_iptables_entry)); - if (e == NULL) - return -1; - - e->entry = entry; - - 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_head == 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; -} - -static int connman_iptables_add_chain(struct connman_iptables *table, - char *name) -{ - GList *last; - struct ipt_entry *entry_head; - struct ipt_entry *entry_return; - struct ipt_error_target *error; - struct ipt_standard_target *standard; - u_int16_t entry_head_size, entry_return_size; - - last = g_list_last(table->entries); - - /* - * An empty chain is composed of: - * - A head entry, with no match and an error target. - * The error target data is the chain name. - * - A tail entry, with no match and a standard target. - * The standard target verdict is XT_RETURN (return to the - * caller). - */ - - /* head entry */ - entry_head_size = sizeof(struct ipt_entry) + - sizeof(struct ipt_error_target); - entry_head = g_try_malloc0(entry_head_size); - if (entry_head == NULL) - goto err; - - memset(entry_head, 0, entry_head_size); - - entry_head->target_offset = sizeof(struct ipt_entry); - entry_head->next_offset = entry_head_size; - - error = (struct ipt_error_target *) entry_head->elems; - strcpy(error->t.u.user.name, IPT_ERROR_TARGET); - 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) - goto err; - - /* tail entry */ - entry_return_size = sizeof(struct ipt_entry) + - sizeof(struct ipt_standard_target); - entry_return = g_try_malloc0(entry_return_size); - if (entry_return == NULL) - goto err; - - memset(entry_return, 0, entry_return_size); - - entry_return->target_offset = sizeof(struct ipt_entry); - entry_return->next_offset = entry_return_size; - - standard = (struct ipt_standard_target *) entry_return->elems; - standard->target.u.user.target_size = - ALIGN(sizeof(struct ipt_standard_target)); - standard->verdict = XT_RETURN; - - if (connman_add_entry(table, entry_return, last) < 0) - goto err; - - return 0; - -err: - g_free(entry_head); - g_free(entry_return); - - return -ENOMEM; -} - -static struct ipt_entry * -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; - int is_builtin = is_builtin_target(target_name); - - if (xt_m) - match_size = xt_m->m->u.match_size; - else - match_size = 0; - - 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); - if (new_entry == NULL) - return NULL; - - 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; - memcpy(entry_match, xt_m->m, match_size); - } - - 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 int -connman_iptables_add_rule(struct connman_iptables *table, char *chain_name, - char *target_name, struct xtables_target *xt_t, - char *match_name, struct xtables_match *xt_m) -{ - GList *chain_tail; - struct ipt_entry *new_entry; - - chain_tail = find_chain_tail(table, chain_name); - if (chain_tail == NULL) - return -EINVAL; - - 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); -} - -static struct ipt_replace * -connman_iptables_blob(struct connman_iptables *table) -{ - struct ipt_replace *r; - GList *list; - struct connman_iptables_entry *e; - unsigned char *entry_index; - - r = g_try_malloc0(sizeof(struct ipt_replace) + table->size); - if (r == NULL) - return NULL; - - memset(r, 0, sizeof(*r) + table->size); - - r->counters = g_try_malloc0(sizeof(struct xt_counters) - * table->num_entries); - if (r->counters == NULL) { - g_free(r); - return NULL; - } - - strcpy(r->name, table->info->name); - r->num_entries = table->num_entries; - r->size = table->size; - - 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)); - - entry_index = (unsigned char *)r->entries; - for (list = table->entries; list; list = list->next) { - e = list->data; - - memcpy(entry_index, e->entry, e->entry->next_offset); - entry_index += e->entry->next_offset; - } - - return r; -} - -static void dump_target(struct connman_iptables *table, - struct ipt_entry *entry) - -{ - struct xtables_target *xt_t; - struct xt_entry_target *target; - - target = ipt_get_target(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: - printf("\ttarget RETURN\n"); - break; - - case -NF_ACCEPT - 1: - printf("\ttarget ACCEPT\n"); - break; - - case -NF_DROP - 1: - printf("\ttarget DROP\n"); - break; - - case -NF_QUEUE - 1: - printf("\ttarget QUEUE\n"); - break; - - case -NF_STOP - 1: - printf("\ttarget STOP\n"); - break; - - default: - printf("\tJUMP @%p (0x%x)\n", - (char*)table->blob_entries->entrytable + - t->verdict, t->verdict); - break; - } - - xt_t = xtables_find_target(IPT_STANDARD_TARGET, - XTF_LOAD_MUST_SUCCEED); - - if(xt_t->print != NULL) - xt_t->print(NULL, target, 1); - } else { - xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD); - if (xt_t == NULL) { - printf("\ttarget %s\n", target->u.user.name); - return; - } - - if(xt_t->print != NULL) { - printf("\ttarget "); - xt_t->print(NULL, target, 1); - printf("\n"); - } - } -} - -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)) - return; - - xt_m = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL); - if (xt_m == NULL) - goto out; - - if(xt_m->print != NULL) { - printf("\tmatch "); - xt_m->print(NULL, match, 1); - printf("\n"); - - return; - } - -out: - printf("\tmatch %s\n", match->u.user.name); - -} - -static int connman_iptables_dump_entry(struct ipt_entry *entry, - struct connman_iptables *table) -{ - struct xt_entry_target *target; - unsigned int offset; - int builtin; - - offset = (char *)entry - (char *)table->blob_entries->entrytable; - target = ipt_get_target(entry); - builtin = is_hook_entry(table, entry); - - if (entry_to_offset(table, entry) + entry->next_offset == - table->blob_entries->size) { - printf("End of CHAIN 0x%x\n", offset); - return 0; - } - - if (!strcmp(target->u.user.name, IPT_ERROR_TARGET)) { - printf("USER CHAIN (%s) %p match %p target %p size %d\n", - target->data, entry, entry->elems, - (char *)entry + entry->target_offset, - entry->next_offset); - - return 0; - } else if (builtin >= 0) { - printf("CHAIN (%s) %p match %p target %p size %d\n", - hooknames[builtin], entry, entry->elems, - (char *)entry + entry->target_offset, - entry->next_offset); - } else { - printf("RULE %p match %p target %p size %d\n", entry, - entry->elems, - (char *)entry + entry->target_offset, - entry->next_offset); - } - - dump_match(table, entry); - dump_target(table, entry); - - return 0; -} - -static void connman_iptables_dump(struct connman_iptables *table) -{ - printf("%s valid_hooks=0x%08x, num_entries=%u, size=%u\n", - table->info->name, - table->info->valid_hooks, table->info->num_entries, - table->info->size); - - ENTRY_ITERATE(table->blob_entries->entrytable, - table->blob_entries->size, - connman_iptables_dump_entry, table); - -} - -static int connman_iptables_get_entries(struct connman_iptables *table) -{ - socklen_t entry_size; - - entry_size = sizeof(struct ipt_get_entries) + table->info->size; - - return getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_ENTRIES, - table->blob_entries, &entry_size); -} - -static int connman_iptables_replace(struct connman_iptables *table, - struct ipt_replace *r) -{ - return setsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_SET_REPLACE, r, - sizeof(*r) + r->size); -} - -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) -{ - struct ipt_replace *repl; - - repl = connman_iptables_blob(table); - - return connman_iptables_replace(table, repl); -} - -static int add_entry(struct ipt_entry *entry, struct connman_iptables *table) -{ - struct ipt_entry *new_entry; - - new_entry = g_try_malloc0(entry->next_offset); - if (new_entry == NULL) - return -ENOMEM; - - memcpy(new_entry, entry, entry->next_offset); - - return connman_add_entry(table, new_entry, NULL); -} - -static struct connman_iptables *connman_iptables_init(const char *table_name) -{ - struct connman_iptables *table; - socklen_t s; - - table = g_try_new0(struct connman_iptables, 1); - if (table == NULL) - return NULL; - - table->info = g_try_new0(struct ipt_getinfo, 1); - if (table->info == NULL) - goto err; - - table->ipt_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (table->ipt_sock < 0) - goto err; - - s = sizeof(*table->info); - strcpy(table->info->name, table_name); - if (getsockopt(table->ipt_sock, IPPROTO_IP, IPT_SO_GET_INFO, - table->info, &s) < 0) - goto err; - - table->blob_entries = g_try_malloc0(sizeof(struct ipt_get_entries) + - table->info->size); - if (table->blob_entries == NULL) - goto err; - - strcpy(table->blob_entries->name, table_name); - table->blob_entries->size = table->info->size; - - if (connman_iptables_get_entries(table) < 0) - goto err; - - table->num_entries = 0; - table->old_entries = table->info->num_entries; - table->size = 0; - - ENTRY_ITERATE(table->blob_entries->entrytable, - table->blob_entries->size, - add_entry, table); - - - return table; - -err: - - connman_iptables_cleanup(table); - - return NULL; -} - - -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, +#include "../src/connman.h" + +enum iptables_command { + IPTABLES_COMMAND_APPEND, + IPTABLES_COMMAND_INSERT, + IPTABLES_COMMAND_DELETE, + IPTABLES_COMMAND_POLICY, + IPTABLES_COMMAND_CHAIN_INSERT, + IPTABLES_COMMAND_CHAIN_DELETE, + IPTABLES_COMMAND_CHAIN_FLUSH, + IPTABLES_COMMAND_DUMP, + IPTABLES_COMMAND_UNKNOWN, }; int main(int argc, char *argv[]) { - struct connman_iptables *table; - 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; - size_t size; - gboolean dump, invert, delete; - - xtables_init_all(&connman_iptables_globals, NFPROTO_IPV4); + enum iptables_command cmd = IPTABLES_COMMAND_UNKNOWN; + char *table = NULL, *chain = NULL, *rule = NULL, *tmp; + int err, c, i; - dump = FALSE; - 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; + opterr = 0; while ((c = getopt_long(argc, argv, - "-A:L::N:X:j:i:m:o:t:", connman_iptables_globals.opts, NULL)) != -1) { + "-A:I:D:P:N:X:F:Lt:", NULL, NULL)) != -1) { switch (c) { case 'A': chain = optarg; + cmd = IPTABLES_COMMAND_APPEND; break; - - case 'L': - dump = true; + case 'I': + chain = optarg; + cmd = IPTABLES_COMMAND_INSERT; break; - - case 'N': - new_chain = optarg; + case 'D': + chain = optarg; + cmd = IPTABLES_COMMAND_DELETE; break; - - case 'X': - delete = true; - delete_chain = optarg; + case 'P': + chain = optarg; + /* The policy will be stored in rule. */ + cmd = IPTABLES_COMMAND_POLICY; 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; - + case 'N': + chain = optarg; + cmd = IPTABLES_COMMAND_CHAIN_INSERT; break; - - case 'i': + case 'X': + chain = optarg; + cmd = IPTABLES_COMMAND_CHAIN_DELETE; break; - - 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; - } - + case 'F': + chain = optarg; + cmd = IPTABLES_COMMAND_CHAIN_FLUSH; break; - - case 'o': + case 'L': + cmd = IPTABLES_COMMAND_DUMP; break; - case 't': - table_name = optarg; + table = 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: - 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); - - return 0; - } - - if (chain && new_chain) - return -1; - - if (new_chain) { - printf("New chain %s\n", new_chain); - - connman_iptables_add_chain(table, new_chain); - - goto commit; - } - - if (chain) { - if (target_name == NULL) - return -1; - - printf("Adding %s to %s (match %s)\n", target_name, chain, match_name); - - connman_iptables_add_rule(table, chain, target_name, xt_t, - match_name, xt_m); - - goto commit; + } } -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); + if (!table) + table = "filter"; + + for (i = optind - 1; i < argc; i++) { + if (rule) { + tmp = rule; + rule = g_strdup_printf("%s %s", rule, argv[i]); + g_free(tmp); + } else + rule = g_strdup(argv[i]); + } + + __connman_iptables_init(); + + switch (cmd) { + case IPTABLES_COMMAND_APPEND: + err = __connman_iptables_append(AF_INET, table, chain, rule); + break; + case IPTABLES_COMMAND_INSERT: + err = __connman_iptables_insert(AF_INET, table, chain, rule); + break; + case IPTABLES_COMMAND_DELETE: + err = __connman_iptables_delete(AF_INET, table, chain, rule); + break; + case IPTABLES_COMMAND_POLICY: + err = __connman_iptables_change_policy(AF_INET, table, chain, + rule); + break; + case IPTABLES_COMMAND_CHAIN_INSERT: + err = __connman_iptables_new_chain(AF_INET, table, chain); + break; + case IPTABLES_COMMAND_CHAIN_DELETE: + err = __connman_iptables_delete_chain(AF_INET, table, chain); + break; + case IPTABLES_COMMAND_CHAIN_FLUSH: + err = __connman_iptables_flush_chain(AF_INET, table, chain); + break; + case IPTABLES_COMMAND_DUMP: + __connman_log_init(argv[0], "*", false, false, + "iptables-test", "1"); + err = __connman_iptables_dump(AF_INET, table); + break; + case IPTABLES_COMMAND_UNKNOWN: + printf("Missing command\n"); + printf("usage: iptables-test [-t table] {-A|-I|-D} chain rule\n"); + printf(" iptables-test [-t table] {-N|-X|-F} chain\n"); + printf(" iptables-test [-t table] -L\n"); + printf(" iptables-test [-t table] -P chain target\n"); + exit(-EINVAL); + } + + if (err < 0) { + printf("Error: %s\n", strerror(-err)); + exit(err); + } + + err = __connman_iptables_commit(AF_INET, table); + if (err < 0) { + printf("Failed to commit changes: %s\n", strerror(-err)); + exit(err); + } + + g_free(rule); + + __connman_iptables_cleanup(); return 0; }