tools: Add support for rule matches list to iptables_test
[framework/connectivity/connman.git] / tools / iptables-test.c
index eb7a164..5a3df95 100644 (file)
@@ -46,6 +46,8 @@ static const char *hooknames[] = {
 #define LABEL_QUEUE   "QUEUE"
 #define LABEL_RETURN  "RETURN"
 
+#define XT_OPTION_OFFSET_SCALE 256
+
 /* fn returns 0 to continue iteration */
 #define _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
 ({                                                             \
@@ -531,15 +533,15 @@ err_head:
 
 static struct ipt_entry *new_rule(struct ipt_ip *ip,
                        char *target_name, struct xtables_target *xt_t,
-                       char *match_name, struct xtables_match *xt_m)
+                       struct xtables_rule_match *xt_rm)
 {
+       struct xtables_rule_match *tmp_xt_rm;
        struct ipt_entry *new_entry;
        size_t match_size, target_size;
 
-       if (xt_m)
-               match_size = xt_m->m->u.match_size;
-       else
-               match_size = 0;
+       match_size = 0;
+       for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL; tmp_xt_rm = tmp_xt_rm->next)
+               match_size += tmp_xt_rm->match->m->u.match_size;
 
        if (xt_t)
                target_size = ALIGN(xt_t->t->u.target_size);
@@ -556,11 +558,13 @@ static struct ipt_entry *new_rule(struct ipt_ip *ip,
        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);
+       match_size = 0;
+       for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+                               tmp_xt_rm = tmp_xt_rm->next) {
+               memcpy(new_entry->elems + match_size, tmp_xt_rm->match->m,
+                                       tmp_xt_rm->match->m->u.match_size);
+               match_size += tmp_xt_rm->match->m->u.match_size;
        }
 
        if (xt_t) {
@@ -606,8 +610,7 @@ static void update_hooks(struct connman_iptables *table, GList *chain_head,
 static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
                                struct ipt_ip *ip, char *chain_name,
                                char *target_name, struct xtables_target *xt_t,
-                               char *match_name, struct xtables_match *xt_m,
-                               int *builtin)
+                               int *builtin, struct xtables_rule_match *xt_rm)
 {
        GList *chain_tail, *chain_head;
        struct ipt_entry *new_entry;
@@ -621,7 +624,7 @@ static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
        if (chain_tail == NULL)
                return NULL;
 
-       new_entry = new_rule(ip, target_name, xt_t, match_name, xt_m);
+       new_entry = new_rule(ip, target_name, xt_t, xt_rm);
        if (new_entry == NULL)
                return NULL;
 
@@ -646,7 +649,7 @@ static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
 static int connman_iptables_append_rule(struct connman_iptables *table,
                                struct ipt_ip *ip, char *chain_name,
                                char *target_name, struct xtables_target *xt_t,
-                               char *match_name, struct xtables_match *xt_m)
+                               struct xtables_rule_match *xt_rm)
 {
        GList *chain_tail;
        struct ipt_entry *new_entry;
@@ -657,7 +660,7 @@ static int connman_iptables_append_rule(struct connman_iptables *table,
                return -EINVAL;
 
        new_entry = prepare_rule_inclusion(table, ip, chain_name,
-                       target_name, xt_t, match_name, xt_m, &builtin);
+                                       target_name, xt_t, &builtin, xt_rm);
        if (new_entry == NULL)
                return -EINVAL;
 
@@ -671,7 +674,7 @@ static int connman_iptables_append_rule(struct connman_iptables *table,
 static int connman_iptables_insert_rule(struct connman_iptables *table,
                                struct ipt_ip *ip, char *chain_name,
                                char *target_name, struct xtables_target *xt_t,
-                               char *match_name, struct xtables_match *xt_m)
+                               struct xtables_rule_match *xt_rm)
 {
        GList *chain_head;
        struct ipt_entry *new_entry;
@@ -682,7 +685,7 @@ static int connman_iptables_insert_rule(struct connman_iptables *table,
                return -EINVAL;
 
        new_entry = prepare_rule_inclusion(table, ip, chain_name,
-                       target_name, xt_t, match_name, xt_m, &builtin);
+                                       target_name, xt_t, &builtin, xt_rm);
        if (new_entry == NULL)
                return -EINVAL;
 
@@ -755,7 +758,8 @@ static gboolean is_same_match(struct xt_entry_match *xt_e_m1,
 static int connman_iptables_delete_rule(struct connman_iptables *table,
                                struct ipt_ip *ip, char *chain_name,
                                char *target_name, struct xtables_target *xt_t,
-                               char *match_name, struct xtables_match *xt_m)
+                               struct xtables_match *xt_m,
+                               struct xtables_rule_match *xt_rm)
 {
        GList *chain_tail, *chain_head, *list;
        struct xt_entry_target *xt_e_t = NULL;
@@ -777,7 +781,7 @@ static int connman_iptables_delete_rule(struct connman_iptables *table,
        if (!xt_t && !xt_m)
                return -EINVAL;
 
-       entry_test = new_rule(ip, target_name, xt_t, match_name, xt_m);
+       entry_test = new_rule(ip, target_name, xt_t, xt_rm);
        if (entry_test == NULL)
                return -EINVAL;
 
@@ -1289,8 +1293,18 @@ static struct xtables_target *prepare_target(struct connman_iptables *table,
                        xt_t->init(xt_t->t);
        }
 
-       connman_iptables_globals.opts =
-               xtables_merge_options(
+       if (xt_t->x6_options != NULL)
+               connman_iptables_globals.opts =
+                       xtables_options_xfrm(
+#if XTABLES_VERSION_CODE > 5
+                               connman_iptables_globals.orig_opts,
+#endif
+                               connman_iptables_globals.opts,
+                               xt_t->x6_options,
+                               &xt_t->option_offset);
+       else
+               connman_iptables_globals.opts =
+                       xtables_merge_options(
 #if XTABLES_VERSION_CODE > 5
                                connman_iptables_globals.orig_opts,
 #endif
@@ -1329,7 +1343,19 @@ static struct xtables_match *prepare_matches(struct connman_iptables *table,
        if (xt_m->init != NULL)
                xt_m->init(xt_m->m);
 
-       if (xt_m != xt_m->next) {
+       if (xt_m == xt_m->next)
+               goto done;
+
+       if (xt_m->x6_options != NULL)
+               connman_iptables_globals.opts =
+                       xtables_options_xfrm(
+#if XTABLES_VERSION_CODE > 5
+                               connman_iptables_globals.orig_opts,
+#endif
+                               connman_iptables_globals.opts,
+                               xt_m->x6_options,
+                               &xt_m->option_offset);
+       else
                connman_iptables_globals.opts =
                        xtables_merge_options(
 #if XTABLES_VERSION_CODE > 5
@@ -1339,20 +1365,20 @@ static struct xtables_match *prepare_matches(struct connman_iptables *table,
                                xt_m->extra_opts,
                                &xt_m->option_offset);
 
-               if (connman_iptables_globals.opts == NULL) {
-                       g_free(xt_m->m);
-                       xt_m = NULL;
-               }
+       if (connman_iptables_globals.opts == NULL) {
+               g_free(xt_m->m);
+               xt_m = NULL;
        }
 
+done:
        return xt_m;
 }
 
 int main(int argc, char *argv[])
 {
        struct connman_iptables *table;
-       struct xtables_rule_match *xt_rm;
-       struct xtables_match *xt_m;
+       struct xtables_rule_match *xt_rm, *tmp_xt_rm;
+       struct xtables_match *xt_m, *xt_m_t;
        struct xtables_target *xt_t;
        struct ipt_ip ip;
        char *table_name, *chain, *new_chain, *match_name, *target_name;
@@ -1509,20 +1535,48 @@ int main(int argc, char *argv[])
                        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);
+                       if (xt_t != NULL && (xt_t->x6_parse != NULL ||
+                                               xt_t->parse != NULL) &&
+                                       (c >= (int) xt_t->option_offset &&
+                                       c < (int) xt_t->option_offset +
+                                       XT_OPTION_OFFSET_SCALE)) {
+                               xtables_option_tpcall(c, argv,
+                                                       invert, xt_t, NULL);
+
+                               break;
+                       }
+
+                       for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+                                               tmp_xt_rm = tmp_xt_rm->next) {
+                               xt_m_t = tmp_xt_rm->match;
+
+                               if (tmp_xt_rm->completed ||
+                                               (xt_m_t->x6_parse == NULL &&
+                                                xt_m_t->parse == NULL))
+                                       continue;
+
+                               if (c < (int) xt_m_t->option_offset ||
+                                       c >= (int) xt_m_t->option_offset
+                                       + XT_OPTION_OFFSET_SCALE)
+                                       continue;
+
+                               xtables_option_mpcall(c, argv,
+                                                       invert, xt_m_t, NULL);
+
+                               break;
                        }
 
                        break;
                }
        }
 
+       for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+                               tmp_xt_rm = tmp_xt_rm->next)
+               xtables_option_mfcall(tmp_xt_rm->match);
+
+       if (xt_t != NULL)
+               xtables_option_tfcall(xt_t);
+
        if (table_name == NULL)
                table_name = "filter";
 
@@ -1572,7 +1626,7 @@ int main(int argc, char *argv[])
                                        chain, match_name);
 
                        connman_iptables_delete_rule(table, &ip, chain,
-                                       target_name, xt_t, match_name, xt_m);
+                                       target_name, xt_t, xt_m, xt_rm);
 
                        goto commit;
                }
@@ -1582,13 +1636,13 @@ int main(int argc, char *argv[])
                                        chain, match_name);
 
                        connman_iptables_insert_rule(table, &ip, chain,
-                                       target_name, xt_t, match_name, xt_m);
+                                               target_name, xt_t, xt_rm);
                } else {
                        printf("Appending %s to %s (match %s)\n", target_name,
                                        chain, match_name);
 
                        connman_iptables_append_rule(table, &ip, chain,
-                               target_name, xt_t, match_name, xt_m);
+                                               target_name, xt_t, xt_rm);
                }
        }