X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=unit%2Ftest-iptables.c;h=cd261d054132ee0370d9c1cfc726095511dc5e04;hb=cef237e5250062e3943724b36c06f585cafee10b;hp=e378a90b9dba2aa312e157cd8300a22f00572050;hpb=161efbae1a4d554d244c206d5cfa1342fc4220cf;p=platform%2Fupstream%2Fconnman.git diff --git a/unit/test-iptables.c b/unit/test-iptables.c index e378a90..cd261d0 100644 --- a/unit/test-iptables.c +++ b/unit/test-iptables.c @@ -1,8 +1,8 @@ /* + * ConnMan firewall unit tests * - * Connection Manager - * - * Copyright (C) 2013 BWM CarIT GmbH. All rights reserved. + * Copyright (C) 2019 Jolla Ltd. All rights reserved. + * Contact: jussi.laakkonen@jolla.com * * 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 @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifdef HAVE_CONFIG_H @@ -24,239 +19,681 @@ #endif #include +#include +#include +#include +#include +#include +#include + +#include "src/connman.h" + +enum configtype { + TEST_CONFIG_PASS = 0x0001, + TEST_CONFIG_INIT_FAIL = 0x0002, + TEST_CONFIG_FIND_MATCH_FAIL = 0x0004, + TEST_CONFIG_FIND_TARGET_FAIL = 0x0008, + TEST_CONFIG_PARSE_PROTOCOL_FAIL = 0x0010, + TEST_CONFIG_MFCALL_FAIL = 0x0020, + TEST_CONFIG_TFCALL_FAIL = 0x0040, + TEST_CONFIG_MPCALL_FAIL = 0x0080, + TEST_CONFIG_TPCALL_FAIL = 0x0100, + TEST_CONFIG_INSMOD_FAIL = 0x0200, + TEST_CONFIG_COMPATIBLE_REV_FAIL = 0x0400, + TEST_CONFIG_OPTIONS_XFRM_FAIL = 0x0800, + TEST_CONFIG_MERGE_OPTIONS_FAIL = 0x1000, +}; -#include "../src/connman.h" +enum configtype test_config_type = TEST_CONFIG_PASS; -static void test_iptables_chain0(void) +static void set_test_config(enum configtype type) { - int err; + test_config_type = type; +} - err = __connman_iptables_new_chain("filter", "foo"); - g_assert(err == 0); +/* Start of dummies */ - err = __connman_iptables_commit("filter"); - g_assert(err == 0); +/* xtables dummies */ - err = __connman_iptables_delete_chain("filter", "foo"); - g_assert(err == 0); +/* From /usr/include/linux/netfilter_ipv4/ip_tables.h */ +#define IPT_BASE_CTL 64 +#define IPT_SO_SET_REPLACE (IPT_BASE_CTL) +#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1) +#define IPT_SO_GET_INFO (IPT_BASE_CTL) +#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1) - err = __connman_iptables_commit("filter"); - g_assert(err == 0); +/* From /usr/include/linux/netfilter_ipv6/ip6_tables.h */ +#define IP6T_BASE_CTL 64 +#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL) +#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1) +#define IP6T_SO_GET_INFO (IP6T_BASE_CTL) +#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) + +int xt_match_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + return 0; } -static void test_iptables_chain1(void) +int xt_target_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **targetinfo) { - int err; + return 0; +} - err = __connman_iptables_new_chain("filter", "foo"); - g_assert(err == 0); +static void xt_x6_parse(struct xt_option_call *opt) { + return; +} - err = __connman_iptables_commit("filter"); - g_assert(err == 0); +static void xt_x6_fcheck(struct xt_fcheck_call *call) { + return; +} - err = __connman_iptables_flush_chain("filter", "foo"); - g_assert(err == 0); +static struct xtables_match xt_match = { + .version = "1", + .next = NULL, + .name = "tcp", + .real_name = "tcp", + .revision = 1, + .ext_flags = 0, + .family = AF_INET, + .size = XT_ALIGN(sizeof(struct xtables_match)), + .userspacesize = XT_ALIGN(sizeof(struct xtables_match)), + .parse = xt_match_parse, + .extra_opts = NULL, + .x6_parse = xt_x6_parse, + .x6_fcheck = xt_x6_fcheck, + .x6_options = NULL, + .udata_size = XT_ALIGN(sizeof(struct xtables_match)), + .udata = NULL, + .option_offset = 32, + .m = NULL, + .mflags = 0, + .loaded = 1, +}; - err = __connman_iptables_commit("filter"); - g_assert(err == 0); +static struct xtables_target xt_target = { + .version = "1", + .next = NULL, + .name = "ACCEPT", + .real_name = "ACCEPT", + .revision = 1, + .ext_flags = 0, + .family = AF_INET, + .size = XT_ALIGN(sizeof(struct xtables_match)), + .userspacesize = XT_ALIGN(sizeof(struct xtables_match)), + .parse = xt_target_parse, + .extra_opts = NULL, + .x6_parse = xt_x6_parse, + .x6_fcheck = xt_x6_fcheck, + .x6_options = NULL, + .udata_size = XT_ALIGN(sizeof(struct xtables_match)), + .udata = NULL, + .option_offset = 32, + .t = NULL, + .tflags = 0, + .used = 0, + .loaded = 1, +}; + +struct xtables_globals *xt_params = NULL; + +struct xtables_match *xtables_matches = NULL; +struct xtables_target *xtables_targets = NULL; + +static void call_error(const char *src) +{ + g_assert(xt_params); - err = __connman_iptables_delete_chain("filter", "foo"); - g_assert(err == 0); + DBG("%s", src); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + xt_params->exit_err(PARAMETER_PROBLEM, "longjmp() %s", src); } -static void test_iptables_chain2(void) +int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto) { - int err; + DBG("%d", nfproto); - err = __connman_iptables_change_policy("filter", "INPUT", "DROP"); - g_assert(err == 0); + if (test_config_type & TEST_CONFIG_INIT_FAIL) + call_error("xtables_init_all"); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + xt_params = xtp; - err = __connman_iptables_change_policy("filter", "INPUT", "ACCEPT"); - g_assert(err == 0); + return 0; +} + +struct xtables_match *xtables_find_match(const char *name, + enum xtables_tryload tryload, + struct xtables_rule_match **matches) +{ + DBG("name %s type %d", name, tryload); + + if (test_config_type & TEST_CONFIG_FIND_MATCH_FAIL) + call_error("xtables_find_match"); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + *matches = g_try_new0(struct xtables_rule_match, 1); + (*matches)->next = NULL; + (*matches)->match = &xt_match; + (*matches)->completed = 0; + + return &xt_match; } -static void test_iptables_rule0(void) +struct xtables_target *xtables_find_target(const char *name, + enum xtables_tryload tryload) { - int err; + DBG("name %s type %d", name, tryload); + + if (test_config_type & TEST_CONFIG_FIND_TARGET_FAIL) + call_error("xtables_find_target"); - /* Test simple appending and removing a rule */ + return &xt_target; +} - err = __connman_iptables_append("filter", "INPUT", - "-m mark --mark 1 -j LOG"); - g_assert(err == 0); +uint16_t xtables_parse_protocol(const char *s) +{ + DBG("protocol %s", s); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + if (test_config_type & TEST_CONFIG_PARSE_PROTOCOL_FAIL) + call_error("xtables_parse_protocol"); - err = __connman_iptables_delete("filter", "INPUT", - "-m mark --mark 1 -j LOG"); - g_assert(err == 0); + if (!g_strcmp0(s, "tcp")) + return 6; - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + return 0; } +void xtables_option_mfcall(struct xtables_match *m) +{ + DBG(""); + + if (test_config_type & TEST_CONFIG_MFCALL_FAIL) + call_error("xtables_option_mfcall"); -static void test_iptables_rule1(void) + m = &xt_match; + + return; +} + +void xtables_option_tfcall(struct xtables_target *t) { - int err; + DBG(""); + + if (test_config_type & TEST_CONFIG_TFCALL_FAIL) + call_error("xtables_option_tfcall"); - /* Test if we can do NAT stuff */ + t = &xt_target; - err = __connman_iptables_append("nat", "POSTROUTING", - "-s 10.10.1.0/24 -o eth0 -j MASQUERADE"); + return; +} - err = __connman_iptables_commit("nat"); - g_assert(err == 0); +void xtables_option_mpcall(unsigned int c, char **argv, bool invert, + struct xtables_match *m, void *fw) +{ + DBG(""); - err = __connman_iptables_delete("nat", "POSTROUTING", - "-s 10.10.1.0/24 -o eth0 -j MASQUERADE"); + if (test_config_type & TEST_CONFIG_MPCALL_FAIL) + call_error("xtables_option_mpcall"); - err = __connman_iptables_commit("nat"); - g_assert(err == 0); + m = &xt_match; + + return; } -static void test_iptables_rule2(void) +void xtables_option_tpcall(unsigned int c, char **argv, bool invert, + struct xtables_target *t, void *fw) { - int err; + DBG(""); - /* Test if the right rule is removed */ + if (test_config_type & TEST_CONFIG_TPCALL_FAIL) + call_error("xtables_option_tpcall"); - err = __connman_iptables_append("filter", "INPUT", - "-m mark --mark 1 -j LOG"); - g_assert(err == 0); + t = &xt_target; - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + return; +} - err = __connman_iptables_append("filter", "INPUT", - "-m mark --mark 2 -j LOG"); - g_assert(err == 0); +int xtables_insmod(const char *modname, const char *modprobe, bool quiet) +{ + DBG("mod %s modprobe %s quiet %s", modname, modprobe, + quiet ? "true" : "false"); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + if (test_config_type & TEST_CONFIG_INSMOD_FAIL) + call_error("xtables_insmod"); - err = __connman_iptables_delete("filter", "INPUT", - "-m mark --mark 2 -j LOG"); - g_assert(err == 0); + return 0; +} - err = __connman_iptables_commit("filter"); - g_assert(err == 0); +int xtables_compatible_revision(const char *name, uint8_t revision, int opt) +{ + DBG("name %s rev %d opt %d", name, revision, opt); - err = __connman_iptables_delete("filter", "INPUT", - "-m mark --mark 1 -j LOG"); - g_assert(err == 0); + if (test_config_type & TEST_CONFIG_COMPATIBLE_REV_FAIL) + call_error("xtables_compatible_revision"); - err = __connman_iptables_commit("filter"); - g_assert(err == 0); + return 1; } -struct connman_notifier *nat_notifier; +struct option *xtables_options_xfrm(struct option *opt1, struct option *opt2, + const struct xt_option_entry *entry, + unsigned int *dummy) +{ + if (test_config_type & TEST_CONFIG_OPTIONS_XFRM_FAIL) + call_error("xtables_options_xfrm"); -struct connman_service { - char *dummy; -}; + return opt1; +} -char *connman_service_get_interface(struct connman_service *service) +struct option *xtables_merge_options(struct option *orig_opts, + struct option *oldopts, const struct option *newopts, + unsigned int *option_offset) { - return "eth0"; + if (test_config_type & TEST_CONFIG_MERGE_OPTIONS_FAIL) + call_error("xtables_merge_options"); + + return orig_opts; } -int connman_notifier_register(struct connman_notifier *notifier) +/* End of xtables dummies */ + +/* socket dummies */ + +int global_sockfd = 1000; + +int socket(int domain, int type, int protocol) { - nat_notifier = notifier; + DBG("domain %d type %d protocol %d", domain, type, protocol); + return global_sockfd; +} + +int getsockopt(int sockfd, int level, int optname, void *optval, + socklen_t *optlen) +{ + struct ipt_getinfo *info = NULL; + struct ipt_get_entries *entries = NULL; + struct ip6t_getinfo *info6 = NULL; + struct ip6t_get_entries *entries6 = NULL; + + DBG(""); + + g_assert_cmpint(global_sockfd, ==, sockfd); + + switch (level) { + case IPPROTO_IP: + DBG("IPPROTO_IP"); + + switch (optname) { + case IPT_SO_GET_ENTRIES: + DBG("IPT_SO_GET_ENTRIES"); + optval = entries; + break; + case IPT_SO_GET_INFO: + DBG("IPT_SO_GET_INFO"); + optval = info; + break; + default: + DBG("optname %d", optname); + return -1; + } + + break; + case IPPROTO_IPV6: + DBG("IPPROTO_IPV6"); + switch (optname) { + case IP6T_SO_GET_ENTRIES: + DBG("IP6T_SO_GET_ENTRIES"); + optval = entries6; + break; + case IP6T_SO_GET_INFO: + DBG("IP6T_SO_GET_INFO"); + optval = info6; + break; + default: + DBG("optname %d", optname); + return -1; + } + + break; + default: + return -1; + } + + *optlen = 0; return 0; } -void connman_notifier_unregister(struct connman_notifier *notifier) +int setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen) { - nat_notifier = NULL; + DBG(""); + + g_assert_cmpint(global_sockfd, ==, sockfd); + + switch (level) { + case IPPROTO_IP: + DBG("IPPROTO_IP"); + switch (optname) { + case IPT_SO_SET_REPLACE: + DBG("IPT_SO_SET_REPLACE"); + return 0; + case IPT_SO_SET_ADD_COUNTERS: + DBG("IPT_SO_SET_ADD_COUNTERS"); + return 0; + default: + DBG("optname %d", optname); + return -1; + } + + break; + case IPPROTO_IPV6: + DBG("IPPROTO_IPV6"); + + switch (optname) { + case IP6T_SO_SET_REPLACE: + DBG("IP6T_SO_SET_REPLACE"); + return 0; + case IP6T_SO_SET_ADD_COUNTERS: + DBG("IP6T_SO_SET_ADD_COUNTERS"); + return 0; + default: + DBG("optname %d", optname); + return -1; + } + + break; + default: + return -1; + } +} + +/* End of socket dummies */ + +/* End of dummies */ + +static void iptables_test_basic0() +{ + set_test_config(TEST_CONFIG_PASS); + + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT"), ==, 0); + + __connman_iptables_cleanup(); +} + +/* + * These ok0...ok6 tests test the error handling. The setjmp() position is set + * properly for the functions that will trigger it and as a result, depending on + * iptables.c, there will be an error or no error at all. Each of these should + * return gracefully without calling exit(). + */ + +static void iptables_test_jmp_ok0() +{ + set_test_config(TEST_CONFIG_FIND_MATCH_FAIL); + + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp -j ACCEPT"), ==, -EINVAL); + + __connman_iptables_cleanup(); } -static void test_nat_basic0(void) +static void iptables_test_jmp_ok1() { - int err; + set_test_config(TEST_CONFIG_FIND_TARGET_FAIL); + + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp -j ACCEPT"), ==, -EINVAL); - err = __connman_nat_enable("bridge", "192.168.2.1", 24); - g_assert(err == 0); + __connman_iptables_cleanup(); +} + +static void iptables_test_jmp_ok2() +{ + set_test_config(TEST_CONFIG_PARSE_PROTOCOL_FAIL); - /* test that table is empty */ - err = __connman_iptables_append("nat", "POSTROUTING", - "-s 192.168.2.1/24 -o eth0 -j MASQUERADE"); - g_assert(err == 0); + __connman_iptables_init(); - err = __connman_iptables_commit("nat"); - g_assert(err == 0); + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT"), ==, + -EINVAL); - __connman_nat_disable("bridge"); + __connman_iptables_cleanup(); } -static void test_nat_basic1(void) +static void iptables_test_jmp_ok3() { - struct connman_service *service; - int err; + set_test_config(TEST_CONFIG_TFCALL_FAIL); - service = g_try_new0(struct connman_service, 1); - g_assert(service); + __connman_iptables_init(); - nat_notifier->default_changed(service); + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT"), ==, + -EINVAL); - err = __connman_nat_enable("bridge", "192.168.2.1", 24); - g_assert(err == 0); + __connman_iptables_cleanup(); +} - /* test that table is not empty */ - err = __connman_iptables_append("nat", "POSTROUTING", - "-s 192.168.2.1/24 -o eth0 -j MASQUERADE"); - g_assert(err == 0); +static void iptables_test_jmp_ok4() +{ + set_test_config(TEST_CONFIG_MFCALL_FAIL); - err = __connman_iptables_commit("nat"); - g_assert(err == 0); + __connman_iptables_init(); - __connman_nat_disable("bridge"); + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); - /* test that table is empty again */ - err = __connman_iptables_delete("nat", "POSTROUTING", - "-s 192.168.2.1/24 -o eth0 -j MASQUERADE"); - g_assert(err == 0); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT"), ==, + -EINVAL); - err = __connman_iptables_commit("nat"); - g_assert(err == 0); + __connman_iptables_cleanup(); } -int main(int argc, char *argv[]) +static void iptables_test_jmp_ok5() { - int err; + set_test_config(TEST_CONFIG_TPCALL_FAIL); - g_test_init(&argc, &argv, NULL); + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); + + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT " + "--comment test"), ==, -EINVAL); + + __connman_iptables_cleanup(); +} + +static void iptables_test_jmp_ok6() +{ + set_test_config(TEST_CONFIG_MPCALL_FAIL); - __connman_log_init(argv[0], "*", FALSE, FALSE, - "Unit Tests Connection Manager", VERSION); __connman_iptables_init(); - __connman_nat_init(); - g_test_add_func("/iptables/chain0", test_iptables_chain0); - g_test_add_func("/iptables/chain1", test_iptables_chain1); - g_test_add_func("/iptables/chain2", test_iptables_chain2); - g_test_add_func("/iptables/rule0", test_iptables_rule0); - g_test_add_func("/iptables/rule1", test_iptables_rule1); - g_test_add_func("/iptables/rule2", test_iptables_rule2); - g_test_add_func("/nat/basic0", test_nat_basic0); - g_test_add_func("/nat/basic1", test_nat_basic1); + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", "INPUT")); - err = g_test_run(); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", "INPUT", + "-p tcp -m tcp --dport 42 -j ACCEPT"), ==, + -EINVAL); - __connman_nat_cleanup(); __connman_iptables_cleanup(); +} - return err; +/* + * These exit0...exit2 tests invoke longjmp() via xtables exit_err() without + * having env saved with setjmp(). All of these will result calling exit(), thus + * forking is required. + */ + +static void iptables_test_jmp_exit0() +{ + pid_t cpid = 0; + int cstatus = 0; + + /* + * Should work as normal but fork() is needed as exit() is called + * when longjmp() is not allowed. At xtables_init_all() exit_err() is + * not normally called. + */ + set_test_config(TEST_CONFIG_INIT_FAIL); + + /* Child, run iptables test */ + if (fork() == 0) { + __connman_iptables_init(); + + /* + * Address family must be different from previous use because + * otherwise xtables_init_all() is not called. + */ + g_assert(!__connman_iptables_new_chain(AF_INET6, "filter", + "INPUT")); + + __connman_iptables_cleanup(); + exit(0); + } else { + cpid = wait(&cstatus); /* Wait for child */ + } + + DBG("parent %d child %d exit %d", getpid(), cpid, WEXITSTATUS(cstatus)); + + g_assert(WIFEXITED(cstatus)); + g_assert_cmpint(WEXITSTATUS(cstatus), ==, PARAMETER_PROBLEM); } + +static void iptables_test_jmp_exit1() +{ + pid_t cpid = 0; + int cstatus = 0; + + /* + * Should work as normal but fork() is needed as exit() is called + * when longjmp() is not allowed. At xtables_insmod() exit_err() is not + * normally called. + */ + set_test_config(TEST_CONFIG_INSMOD_FAIL); + + if (fork() == 0) { + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", + "INPUT")); + + __connman_iptables_cleanup(); + exit(0); + } else { + cpid = wait(&cstatus); + } + + DBG("parent %d child %d exit %d", getpid(), cpid, WEXITSTATUS(cstatus)); + + g_assert(WIFEXITED(cstatus)); + g_assert_cmpint(WEXITSTATUS(cstatus), ==, PARAMETER_PROBLEM); +} + +static void iptables_test_jmp_exit2() +{ + pid_t cpid = 0; + int cstatus = 0; + + set_test_config(TEST_CONFIG_OPTIONS_XFRM_FAIL| + TEST_CONFIG_MERGE_OPTIONS_FAIL| + TEST_CONFIG_COMPATIBLE_REV_FAIL); + + if (fork() == 0) { + __connman_iptables_init(); + + g_assert(!__connman_iptables_new_chain(AF_INET, "filter", + "INPUT")); + g_assert_cmpint(__connman_iptables_insert(AF_INET, "filter", + "INPUT", "-p tcp -m tcp --dport 42 " + "-j ACCEPT --comment test"), ==, 0); + + __connman_iptables_cleanup(); + exit(0); + } else { + cpid = wait(&cstatus); + } + + DBG("parent %d child %d exit %d", getpid(), cpid, WEXITSTATUS(cstatus)); + + g_assert(WIFEXITED(cstatus)); + g_assert_cmpint(WEXITSTATUS(cstatus), ==, PARAMETER_PROBLEM); +} + +static gchar *option_debug = NULL; + +static bool parse_debug(const char *key, const char *value, + gpointer user_data, GError **error) +{ + if (value) + option_debug = g_strdup(value); + else + option_debug = g_strdup("*"); + + return true; +} + +static GOptionEntry options[] = { + { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, + G_OPTION_ARG_CALLBACK, parse_debug, + "Specify debug options to enable", "DEBUG" }, + { NULL }, +}; + +int main (int argc, char *argv[]) +{ + GOptionContext *context; + GError *error = NULL; + + g_test_init(&argc, &argv, NULL); + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, options, NULL); + + if (!g_option_context_parse(context, &argc, &argv, &error)) { + if (error) { + g_printerr("%s\n", error->message); + g_error_free(error); + } else + g_printerr("An unknown error occurred\n"); + return 1; + } + + g_option_context_free(context); + + __connman_log_init(argv[0], option_debug, false, false, + "Unit Tests Connection Manager", VERSION); + + g_test_add_func("/iptables/test_basic0", iptables_test_basic0); + g_test_add_func("/iptables/test_jmp_ok0", iptables_test_jmp_ok0); + g_test_add_func("/iptables/test_jmp_ok1", iptables_test_jmp_ok1); + g_test_add_func("/iptables/test_jmp_ok2", iptables_test_jmp_ok2); + g_test_add_func("/iptables/test_jmp_ok3", iptables_test_jmp_ok3); + g_test_add_func("/iptables/test_jmp_ok4", iptables_test_jmp_ok4); + g_test_add_func("/iptables/test_jmp_ok5", iptables_test_jmp_ok5); + g_test_add_func("/iptables/test_jmp_ok6", iptables_test_jmp_ok6); + g_test_add_func("/iptables/test_jmp_exit0", iptables_test_jmp_exit0); + g_test_add_func("/iptables/test_jmp_exit1", iptables_test_jmp_exit1); + g_test_add_func("/iptables/test_jmp_exit2", iptables_test_jmp_exit2); + + return g_test_run(); +} + +/* + * Local Variables: + * mode: C + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */