iptables: Replace iptables-test program
authorSamuel Ortiz <sameo@linux.intel.com>
Fri, 22 Oct 2010 22:09:30 +0000 (00:09 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 22 Oct 2010 22:09:30 +0000 (00:09 +0200)
The new iptables-test no longer links against the unstable libiptc
library. A link against libxtables is still necessary as the iptables
extensions are only registered against iptables through this library.
Not using it would mean replicating any of the extensions ConnMan could
potentially need.

Makefile.am
configure.ac
tools/iptables-test.c

index 04189d7..cffebd0 100644 (file)
@@ -101,7 +101,7 @@ build_plugindir = $(plugindir)
 build_scriptdir = $(scriptdir)
 endif
 
-AM_CFLAGS = @IPTC_CFLAGS@ @NETLINK_CFLAGS@ @CAPNG_CFLAGS@ \
+AM_CFLAGS = @XTABLES_CFLAGS@ @NETLINK_CFLAGS@ @CAPNG_CFLAGS@ \
                        @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
                                -DCONNMAN_PLUGIN_BUILTIN \
                                -DSTATEDIR=\""$(statedir)"\" \
@@ -160,7 +160,7 @@ tools_polkit_test_LDADD = @DBUS_LIBS@
 
 tools_portal_test_LDADD = @GLIB_LIBS@
 
-tools_iptables_test_LDADD = @IPTC_LIBS@ -lip4tc -lxtables
+tools_iptables_test_LDADD = @GLIB_LIBS@ @XTABLES_LIBS@
 
 if DHCLIENT
 noinst_PROGRAMS += tools/dhclient-test
index 1b52a93..f45486e 100644 (file)
@@ -350,10 +350,10 @@ AM_CONDITIONAL(CLIENT, test "${enable_client}" = "yes")
 AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools],
                [enable testing tools]), [enable_tools=${enableval}])
 if (test "${enable_tools}" = "yes"); then
-       PKG_CHECK_MODULES(IPTC, libiptc, dummy=yes,
-                               AC_MSG_ERROR(iptables library is required))
-       AC_SUBST(IPTC_CFLAGS)
-       AC_SUBST(IPTC_LIBS)
+       PKG_CHECK_MODULES(XTABLES, xtables, dummy=yes,
+                               AC_MSG_ERROR(xtables library is required))
+       AC_SUBST(XTABLES_CFLAGS)
+       AC_SUBST(XTABLES_LIBS)
 
        PKG_CHECK_MODULES(NETLINK, libnl-1, dummy=yes,
                                AC_MSG_ERROR(Netlink library is required))
index b97c520..b23a170 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <sys/errno.h>
-#include <libiptc/libiptc.h>
-#include <libiptc/libip6tc.h>
+#include <sys/socket.h>
 #include <xtables.h>
 
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_quota.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include <glib.h>
+
+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 builtin;
+       int std_target;
+       int jump_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 void print_match(const struct ipt_entry *e)
+static int is_hook_entry(struct connman_iptables *table,
+                               struct ipt_entry *entry)
 {
-       struct xt_entry_match *match;
-       struct xtables_match *xt_match;
+       unsigned int i;
 
-       match = (struct xt_entry_match *)e->elems;
-       if (match == NULL)
-               return;
+       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;
+       }
 
-       xt_match = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
-       if (xt_match == NULL)
-               return;
+       return -1;
+}
 
-       printf("\tMATCH:%s\n", xt_match->m->u.user.name);
+static unsigned long entry_to_offset(struct connman_iptables *table,
+                                       struct ipt_entry *entry)
+{
+       return (void *)entry - (void *)table->blob_entries->entrytable;
 }
 
-static void print_target(const struct ipt_entry *e)
+static int target_to_verdict(char *target_name)
 {
-       struct xt_entry_target *target;
-       struct xtables_target *xt_target;
+       if (!strcmp(target_name, LABEL_ACCEPT))
+               return -NF_ACCEPT - 1;
 
-       target = (void *)e + e->target_offset;
-       if (target == NULL)
-               return;
+       if (!strcmp(target_name, LABEL_DROP))
+               return -NF_DROP - 1;
 
-       xt_target = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
-       if (xt_target == NULL)
-               return;
+       if (!strcmp(target_name, LABEL_QUEUE))
+               return -NF_QUEUE - 1;
+
+       if (!strcmp(target_name, LABEL_RETURN))
+               return XT_RETURN;
 
-       printf("\tTARGET: %s\n", xt_target->t->u.user.name);
+       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 void print_rule(const struct ipt_entry *e, const char *chain)
+static gboolean is_chain(struct connman_iptables *table,
+                               struct connman_iptables_entry *e)
 {
-       /* print chain name */
-       printf("CHAIN %s:\n", chain);
+       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;
 
-       print_match(e);
-       print_target(e);
+       target = ipt_get_target(entry);
+       if (!strcmp(target->u.user.name, IPT_ERROR_TARGET))
+               return TRUE;
+
+       return FALSE;
 }
 
-static void print_tables(struct iptc_handle *h)
+static GList *find_chain_tail(struct connman_iptables *table,
+                               char *chain_name)
 {
-       const char *chain;
-       const struct ipt_entry *rule;
+       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;
+       }
 
-       chain = iptc_first_chain(h);
+       if (list == NULL)
+               return NULL;
 
-       while(chain) {
-               rule = iptc_first_rule(chain, h);
-               while (rule) {
-                       print_rule(rule, chain);
+       chain_head = list;
 
-                       rule = iptc_next_rule(rule, h);
-               }
+       /* Then we look for the next chain */
+       for (list = chain_head->next; list; list = list->next) {
+               tail = list->data;
+               entry = tail->entry;
 
-               chain = iptc_next_chain(h);
+               if (is_chain(table, tail))
+                       return list;
        }
+
+       /* Nothing found, we return the table end */
+       return g_list_last(table->entries);
 }
 
-static struct ipt_entry *build_quota_drop_entry(void)
+static int connman_add_entry(struct connman_iptables *table,
+                               struct ipt_entry *entry, GList *before)
 {
-       struct ipt_entry *e;
+       struct connman_iptables_entry *e;
+
+       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;
+
+       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_builtin_rule(char *target_name,
+               char *match_name, int match_argc, char **match_argv)
+{
+       struct ipt_entry *new_entry;
        size_t match_size, target_size;
-       struct xtables_target *t;
-       struct xtables_match *m;
-       struct xtables_rule_match *matches = NULL;
+       struct xtables_match *xt_m;
+       struct xt_standard_target *target;
+
+       xt_m = NULL;
+       match_size = 0;
 
-       m = xtables_find_match("quota", XTF_LOAD_MUST_SUCCEED, &matches);
-       if (m == NULL)
+       if (match_name) {
+               xt_m = xtables_find_match(match_name, XTF_TRY_LOAD, NULL);
+               if (xt_m == NULL)
+                       return NULL;
+
+               match_size = ALIGN(sizeof(struct xt_entry_match)) + xt_m->size;
+       }
+
+       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;
 
-       match_size = IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
+       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);
+       }
+
+       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);
+
+       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)
+{
+       return NULL;
+}
+
+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 (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);
+
+       return new_entry;
+}
+
+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)
+{
+       GList *chain_tail;
+       struct ipt_entry *new_entry;
+
+       chain_tail = find_chain_tail(table, chain_name);
+       if (chain_tail == NULL)
+               return -EINVAL;
+
+       printf("Chains found\n");
 
-       m->m = xtables_calloc(1, match_size);
-       if (m->m == NULL)
+       new_entry = new_rule(target_name, target_argc, target_argv,
+                               match_name, match_argc, match_argv);
+       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;
-       m->m->u.match_size = match_size;
-       strcpy(m->m->u.user.name, m->name);
-       m->m->u.user.revision = m->revision;
-       if (m->init != NULL)
-               m->init(m->m);
-
-       t = xtables_find_target("DROP", XTF_TRY_LOAD);
-       if (t == NULL) {
-               free(m->m);
+
+       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;
        }
 
-       target_size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + t->size;
+       strcpy(r->name, table->info->name);
+       r->num_entries = table->num_entries;
+       r->size = table->size;
 
-       t->t = xtables_calloc(1, target_size);
-       t->t->u.target_size = target_size;
-       strcpy(t->t->u.user.name, "DROP");
-       t->t->u.user.revision = t->revision;
-       if (t->init != NULL)
-               t->init(t->t);
+       r->num_counters = table->old_entries;
+       r->valid_hooks  = table->info->valid_hooks;
 
-       e = calloc(1, sizeof(struct ipt_entry) + match_size + target_size);
-       if (e == NULL) {
-               free(m->m);
-               free(t->t);
+       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;
        }
 
-       e->target_offset = sizeof(struct ipt_entry) + match_size;
-       e->next_offset = sizeof(struct ipt_entry) + match_size + target_size;
+       return r;
+}
 
-       memcpy(e->elems, m->m, match_size);
-       memcpy(e->elems + match_size, t->t, target_size);
+static void dump_target(struct connman_iptables *table,
+                               struct ipt_entry *entry)
 
-       return e;
+{
+       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 {
+               printf("\ttarget %s\n", target->u.user.name);
+
+               xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
+               if (xt_t == NULL)
+                       return;
+
+               if(xt_t->print != NULL)
+                       xt_t->print(NULL, target, 1);
+       }
 }
 
-static int add_rule(const ipt_chainlabel chain, struct ipt_entry *e,
-                       struct iptc_handle *h)
+static void dump_match(struct connman_iptables *table, struct ipt_entry *entry)
 {
-       if (!iptc_create_chain(chain, h)) {
-               printf("Chain creation error (%s)\n", iptc_strerror(errno));
-               return -1;
+       struct xtables_match *xt_m;
+       struct xt_entry_match *match;
+
+       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;
        }
 
-       if (!iptc_insert_entry(chain, e, 0, h)) {
-               printf("Entry insertion error (%s)\n", iptc_strerror(errno));
-               return -1;
+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 (!iptc_commit(h)) {
-               printf("Commit error (%s)\n", iptc_strerror(errno));
-               return -1;
+       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 remove_rule(const ipt_chainlabel chain, struct iptc_handle *h)
+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)
 {
-       iptc_flush_entries(chain, h);
-       iptc_delete_chain(chain, h);
-       iptc_commit(h);
+       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);
+}
 
-int main(int argc, char *argv[])
+static void connman_iptables_cleanup(struct connman_iptables *table)
 {
-       struct iptc_handle *h;
-       struct ipt_entry *e;
+       close(table->ipt_sock);
+       g_free(table->info);
+       g_free(table->blob_entries);
+       g_free(table);
+}
 
-       if (argc < 2) {
-               printf("Usage: iptables-test [chain-name]\n");
-               return -1;
-       }
+static int add_entry(struct ipt_entry *entry, struct connman_iptables *table)
+{
+       return connman_add_entry(table, entry, NULL);
+}
 
-       h = iptc_init("filter");
-       if (!h) {
-               printf("libiptc initialization error (%s)\n",
-                       iptc_strerror(errno));
-               exit(errno);
-       }
+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;
+}
+
+int main(int argc, char *argv[])
+{
+       struct ipt_replace *repl;
+       struct connman_iptables *table;
 
        xtables_init();
        xtables_set_nfproto(NFPROTO_IPV4);
 
-       e = build_quota_drop_entry();
-       if (e == NULL)
+       table = connman_iptables_init("filter");
+       if (table == NULL)
                return -1;
 
-       add_rule(argv[1], e, h);
+       connman_iptables_dump(table);
 
-       print_tables(h);
+       if (argv[1]) {
+               connman_iptables_add_chain(table, argv[1]);
+
+               connman_iptables_add_rule(table, argv[1],
+                                       "ACCEPT", 0, NULL,
+                                       NULL, 0, NULL);
+
+               repl = connman_iptables_blob(table);
+
+               connman_iptables_replace(table, repl);
+       }
 
-       remove_rule(argv[1], h);
+       connman_iptables_cleanup(table);
 
        return 0;
 }