Send connman mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."


Today's Topics:

   1. Void Linux, dbus, connman, kills machines networking
      (Ryan Rosemie)
   2. Re: Annoying 169.254.x.x settings casually disrupting my
      connection :( (Gabriele Zaverio)
   3. [PATCH 1/2] iptables: Unroll stack in case of iptables error.
      (Jussi Laakkonen)
   4. [PATCH 2/2] unit: Add unit test for iptables.c longjmp() use.
      (Jussi Laakkonen)


----------------------------------------------------------------------

Message: 1
Date: Mon, 4 Feb 2019 19:41:10 -0500
From: Ryan Rosemie <[email protected]>
To: [email protected]
Subject: Void Linux, dbus, connman, kills machines networking
Message-ID:
        <caongcvxcg8cifs_donknok2d4vcjic0cwqgufyxrh6ghino...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

I'm running into problem with my Void Linux install. This isn't my first
time doing a minimal install of void, and not the first time using connman,
but now I seem to have an issue with connman and dbus.

Firstly connman needs dbus, if I don't enable dbus I get:

Error: failed to connect to socket /run/dbus/system_bus_socket: No
such file or directory

When dbus is enabled to my network shuts off, even my hardware network
light on my laptop for Ethernet goes off. Although connman shows that I'm
on a network, I cant access anything even by Ethernet. Any ideas?

I do have dchcp disabled, wpa_supplicant isn't on a fresh install of void
linux.

Any help would be great! I love connman and I don't want to use anything
else!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
<http://lists.01.org/pipermail/connman/attachments/20190204/0d67e48b/attachment-0001.html>

------------------------------

Message: 2
Date: Tue, 5 Feb 2019 14:43:35 +0100
From: Gabriele Zaverio <[email protected]>
To: [email protected]
Subject: Re: Annoying 169.254.x.x settings casually disrupting my
        connection :(
Message-ID:
        <cane_fbv1fuuktxgmgvoka2t3xksxwtdnyvpsetsvsvavulq...@mail.gmail.com>
Content-Type: text/plain; charset="UTF-8"

Any help ? :(

On 1/31/19, Gabriele Zaverio <[email protected]> wrote:
> Hi there,
>
> I have this problem - from time to time this 169.254.x.x network come
> up totally unwanted - even if I set my interfaces by hand (ifconfig /
> ip etc).
>
> A lot of times I'm correctly configured for my LAN / Internet, and
> suddendly I can't connect anymore. And ifconfig show that somehow my
> interface is set to some 169.254.x.x address.
>
> IMPORTANT NOTE:
> I'm using Devuan GNU/Linux, so I don't have (don't want!) any systemd
> bloatware around.
> I don't have avahi-daemon or similar bloatware installed
> This happens with dhclient running or not running.
>
> I'm searching for a way to BLOCK this behaviour.
>
> How can I FORBID this "Zeroconf / RFC3927 / apipa / whatever"
> abomination to disrupt my network settings?
>
> Please help me, my only way around this is to tweak the entire connman
> source code :(
>
> PS: *NO SYSTEMD*
>
> Thank you everybody! :)
>
> --
> 73 de IW9HGS - Gabriele "Asbesto Molesto" Zaverio
> Museo dell'Informatica funzionante - Freaknet Computer Museum
> http://museum.freaknet.org || http://freaknet.org/asbesto
> GPG Fingerprint: 8935 5586 7F2D 9C5E 51B6  BBC5 EA15 9A4E 613D 44D7
>


-- 
73 de IW9HGS - Gabriele "Asbesto Molesto" Zaverio
Museo dell'Informatica funzionante - Freaknet Computer Museum
http://museum.freaknet.org || http://freaknet.org/asbesto
GPG Fingerprint: 8935 5586 7F2D 9C5E 51B6  BBC5 EA15 9A4E 613D 44D7


------------------------------

Message: 3
Date: Tue,  5 Feb 2019 16:45:40 +0200
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 1/2] iptables: Unroll stack in case of iptables error.
Message-ID: <[email protected]>

This commit introduces a mechanism to catch iptables errors if the
iptables rule is not valid and to restore the previous state before the
error. This is implemented with setjmp() to save the environment (stack)
and longjmp() in iptables.c:iptables_exit() to restore the saved
environment and ignore the invalid rule. This avoids exit() for connman
in such situation and allows to ignore the invalid rules.

The iptables_exit() is added to the iptables_globals as exit
function and this is called when iptables encounters an error with rule
or commit. The environment is saved in each place where xtables
functions, which may result in exit_err() to be called (see
iptables/xtables.c). Furthermore the exit_err() is also called by
xtables_error() directly as it is defined in xtables.h: #define
xtables_error (xt_params->exit_err).

The enum xtables_exittype, which starts from 1, is used as value for the
longjmp() to indicate that an error has occurred.

This commit introduces the following. Before calling any iptables
function do enable_jmp() before calling setjmp(), and if setjmp()
returns from longjmp() via iptables error the error is handled properly
and disable_jmp() is called to disallow further use. The same
disable_jmp() is called after the xtables/iptables operation is
completed without errors.

And to avoid looping, can_jmp() is also checked before iptables_exit()
can call longjmp(). If the jmp state is not saved connman has to exit().
---
 src/iptables.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 1 deletion(-)

diff --git a/src/iptables.c b/src/iptables.c
index 305a553f..9a7fca80 100644
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -32,6 +32,7 @@
 #include <sys/socket.h>
 #include <xtables.h>
 #include <inttypes.h>
+#include <setjmp.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
@@ -194,6 +195,25 @@ struct iptables_replace {
        struct ip6t_replace *r6;
 };
 
+static jmp_buf env_state;
+static bool jmp_set = false;
+
+static void enable_jmp()
+{
+       jmp_set = true;
+}
+
+static void disable_jmp()
+{
+       jmp_set = false;
+}
+
+static bool can_jmp()
+{
+       DBG("%s", jmp_set ? "true" : "false");
+       return jmp_set;
+}
+
 typedef int (*iterate_entries_cb_t)(struct connman_iptables_entry *entry,
                                        int builtin, unsigned int hook,
                                        size_t size, unsigned int offset,
@@ -1873,6 +1893,7 @@ static void dump_target(struct connman_iptables_entry 
*entry)
 {
        struct xtables_target *xt_t;
        struct xt_entry_target *target;
+       int err;
 
        target = iptables_entry_get_target(entry);
 
@@ -1910,13 +1931,34 @@ static void dump_target(struct connman_iptables_entry 
*entry)
                        break;
                }
 
+               enable_jmp();
+
+               if ((err = setjmp(env_state)) != 0) {
+                       DBG("setjmp() called by longjmp() with value %d", err);
+                       disable_jmp();
+                       return;
+               }
+
                xt_t = xtables_find_target(get_standard_target(entry->type),
                                                XTF_LOAD_MUST_SUCCEED);
 
+               disable_jmp();
+
                if (xt_t->print)
                        xt_t->print(NULL, target, 1);
        } else {
+               enable_jmp();
+
+               if ((err = setjmp(env_state)) != 0) {
+                       DBG("setjmp() called by longjmp() with value %d", err);
+                       disable_jmp();
+                       return;
+               }
+
                xt_t = xtables_find_target(target->u.user.name, XTF_TRY_LOAD);
+
+               disable_jmp();
+
                if (!xt_t) {
                        DBG("\ttarget %s", target->u.user.name);
                        return;
@@ -1937,6 +1979,7 @@ static void dump_match(struct connman_iptables_entry 
*entry)
        struct xtables_match *xt_m;
        struct xt_entry_match *match;
        u_int16_t target_offset;
+       int err;
 
        target_offset = iptables_entry_get_target_offset(entry);
 
@@ -1960,7 +2003,18 @@ static void dump_match(struct connman_iptables_entry 
*entry)
        if (!strlen(match->u.user.name))
                return;
 
+       enable_jmp();
+
+       if ((err = setjmp(env_state)) != 0) {
+               DBG("setjmp() called by longjmp() with value %d", err);
+               disable_jmp();
+               return;
+       }
+
        xt_m = xtables_find_match(match->u.user.name, XTF_TRY_LOAD, NULL);
+
+       disable_jmp();
+
        if (!xt_m)
                goto out;
 
@@ -2553,10 +2607,63 @@ static struct option iptables_opts[] = {
        {NULL},
 };
 
+void iptables_exit(enum xtables_exittype status, const char *msg, ...)
+                       __attribute__((noreturn, format(printf,2,3)));
+
+void iptables_exit(enum xtables_exittype status, const char *msg, ...)
+{
+       va_list args;
+       gchar str[256] = { 0 };
+
+       switch (status) {
+       case OTHER_PROBLEM:
+               DBG("OTHER_PROBLEM");
+               break;
+       case PARAMETER_PROBLEM:
+               DBG("PARAMETER_PROBLEM");
+               break;
+       case VERSION_PROBLEM:
+               DBG("VERSION_PROBLEM");
+               break;
+       case RESOURCE_PROBLEM:
+               DBG("RESOURCE_PROBLEM");
+               break;
+       case XTF_ONLY_ONCE:
+               DBG("XTF_ONLY_ONCE");
+               break;
+       case XTF_NO_INVERT:
+               DBG("XTF_NO_INVERT");
+               break;
+       case XTF_BAD_VALUE:
+               DBG("XTF_BAD_VALUE");
+               break;
+       case XTF_ONE_ACTION:
+               DBG("XTF_ONE_ACTION");
+               break;
+       }
+
+       va_start(args, msg);
+       vsnprintf(str, 256, msg, args);
+       va_end(args);
+
+       connman_error("iptables rule error: %s", str);
+
+       if (can_jmp()) {
+               DBG("calling longjmp()");
+                /* enum xtables_exittype begins from 1 */
+               longjmp(env_state, status);
+       }
+
+       connman_error("exit because of iptables error");
+
+       exit(status);
+}
+
 struct xtables_globals iptables_globals = {
        .option_offset = 0,
        .opts = iptables_opts,
        .orig_opts = iptables_opts,
+       .exit_err = iptables_exit,
 #if XTABLES_VERSION_CODE > 10
        .compat_rev = xtables_compatible_revision,
 #endif
@@ -2566,6 +2673,7 @@ struct xtables_globals ip6tables_globals = {
        .option_offset = 0,
        .opts = iptables_opts,
        .orig_opts = iptables_opts,
+       .exit_err = iptables_exit,
 #if XTABLES_VERSION_CODE > 10
        .compat_rev = xtables_compatible_revision,
 #endif
@@ -2578,6 +2686,7 @@ static struct xtables_target *prepare_target(struct 
connman_iptables *table,
        bool is_builtin, is_user_defined;
        GList *chain_head = NULL;
        size_t target_size;
+       int err;
 
        is_builtin = false;
        is_user_defined = false;
@@ -2595,12 +2704,22 @@ static struct xtables_target *prepare_target(struct 
connman_iptables *table,
                        is_user_defined = true;
        }
 
+       enable_jmp();
+
+       if ((err = setjmp(env_state)) != 0) {
+               DBG("setjmp() called by longjmp() with value %d", err);
+               disable_jmp();
+               return NULL;
+       }
+
        if (is_builtin || is_user_defined)
                xt_t = xtables_find_target(get_standard_target(table->type),
                                                XTF_LOAD_MUST_SUCCEED);
        else 
                xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
 
+       disable_jmp();
+
        if (!xt_t)
                return NULL;
 
@@ -2701,12 +2820,23 @@ static struct xtables_match *prepare_matches(struct 
connman_iptables *table,
 {
        struct xtables_match *xt_m;
        size_t match_size;
+       int err;
 
        if (!table || !match_name)
                return NULL;
 
+       enable_jmp();
+
+       if ((err = setjmp(env_state)) != 0) {
+               DBG("setjmp() called by longjmp() with value %d", err);
+               disable_jmp();
+               return NULL;
+       }
+
        xt_m = xtables_find_match(match_name, XTF_LOAD_MUST_SUCCEED, xt_rm);
 
+       disable_jmp();
+
        switch (table->type) {
        case AF_INET:
                match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
@@ -2960,6 +3090,7 @@ static int parse_xt_modules(int c, bool invert,
        struct xtables_rule_match *rm;
        struct ipt_entry fw;
        struct ip6t_entry fw6;
+       int err;
 
        switch (ctx->type) {
        case AF_INET:
@@ -2997,6 +3128,14 @@ static int parse_xt_modules(int c, bool invert,
                                        + XT_OPTION_OFFSET_SCALE)
                        continue;
 
+               enable_jmp();
+
+               if ((err = setjmp(env_state)) != 0) {
+                       DBG("setjmp() called by longjmp() with value %d", err);
+                       disable_jmp();
+                       return -EINVAL;
+               }
+
                switch (ctx->type) {
                case AF_INET:
                        xtables_option_mpcall(c, ctx->argv, invert, m, &fw);
@@ -3005,6 +3144,8 @@ static int parse_xt_modules(int c, bool invert,
                        xtables_option_mpcall(c, ctx->argv, invert, m, &fw6);
                        break;
                }
+
+               disable_jmp();
        }
 
        if (!ctx->xt_t)
@@ -3018,6 +3159,14 @@ static int parse_xt_modules(int c, bool invert,
                                        + XT_OPTION_OFFSET_SCALE)
                return 0;
 
+       enable_jmp();
+
+       if ((err = setjmp(env_state)) != 0) {
+               DBG("setjmp() called by longjmp() with value %d", err);
+               disable_jmp();
+               return -EINVAL;
+       }
+
        switch (ctx->type) {
        case AF_INET:
                xtables_option_tpcall(c, ctx->argv, invert, ctx->xt_t, &fw);
@@ -3027,19 +3176,43 @@ static int parse_xt_modules(int c, bool invert,
                break;
        }
 
+       disable_jmp();
+
        return 0;
 }
 
 static int final_check_xt_modules(struct parse_context *ctx)
 {
        struct xtables_rule_match *rm;
+       int err;
+
+       for (rm = ctx->xt_rm; rm; rm = rm->next) {
+               enable_jmp();
+
+               if ((err = setjmp(env_state)) != 0) {
+                       DBG("setjmp() called by longjmp() with value %d", err);
+                       disable_jmp();
+                       return -EINVAL;
+               }
 
-       for (rm = ctx->xt_rm; rm; rm = rm->next)
                xtables_option_mfcall(rm->match);
 
+               disable_jmp();
+       }
+
+       enable_jmp();
+
+       if ((err = setjmp(env_state)) != 0) {
+               DBG("setjmp() called by longjmp() with value %d", err);
+               disable_jmp();
+               return -EINVAL;
+       }
+
        if (ctx->xt_t)
                xtables_option_tfcall(ctx->xt_t);
 
+       disable_jmp();
+
        return 0;
 }
 
@@ -3269,8 +3442,22 @@ static int parse_rule_spec(struct connman_iptables 
*table,
 
                        break;
                case 'p':
+                       enable_jmp();
+
+                       if ((err = setjmp(env_state)) != 0) {
+                               DBG("setjmp() called by longjmp() with value "
+                                                       "%d", err);
+                               disable_jmp();
+
+                               /* Errors from parse_rule_spec are negative */
+                               err = -EINVAL;
+                               goto out;
+                       }
+
                        ctx->proto = xtables_parse_protocol(optarg);
 
+                       disable_jmp();
+
                        /*
                         * If protocol was set add it to ipt_ip.
                         * xtables_parse_protocol() returns 0 or
@@ -3312,6 +3499,8 @@ static int parse_rule_spec(struct connman_iptables *table,
                        err = parse_xt_modules(c, invert, ctx);
                        if (err == 1)
                                continue;
+                       else if (err == -EINVAL)
+                               goto out;
 
                        break;
                }
-- 
2.19.2



------------------------------

Message: 4
Date: Tue,  5 Feb 2019 16:45:41 +0200
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 2/2] unit: Add unit test for iptables.c longjmp() use.
Message-ID: <[email protected]>

This adds a unit test to run at build for testing longjmp() use in
iptables.c. The tests test both cases to 1) handle longjmp() when
setjmp() was properly called to save env and 2) exit() when longjmp() is
called via xtables exit_err() from a location that normally does not
call it.
---
 .gitignore           |   1 +
 Makefile.am          |  11 +-
 unit/test-iptables.c | 699 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 710 insertions(+), 1 deletion(-)
 create mode 100644 unit/test-iptables.c

diff --git a/.gitignore b/.gitignore
index b7cc1348..b43336c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ tools/session-test
 tools/netlink-test
 unit/test-ippool
 unit/test-nat
+unit/test-iptables
 
 doc/*.bak
 doc/*.stamp
diff --git a/Makefile.am b/Makefile.am
index 8bb49f0f..745bef05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -381,7 +381,8 @@ tools_session_test_LDADD = gdbus/libgdbus-internal.la \
                                @GLIB_LIBS@ @DBUS_LIBS@ -ldl
 
 if XTABLES
-noinst_PROGRAMS += tools/iptables-test tools/ip6tables-test tools/iptables-unit
+noinst_PROGRAMS += tools/iptables-test tools/ip6tables-test 
tools/iptables-unit \
+                  unit/test-iptables
 
 tools_iptables_test_SOURCES = $(backtrace_sources) src/log.c src/iptables.c \
                                tools/iptables-test.c
@@ -399,6 +400,14 @@ tools_iptables_unit_SOURCES = $(backtrace_sources) 
src/log.c \
                tools/iptables-unit.c
 tools_iptables_unit_LDADD = gdbus/libgdbus-internal.la \
                                @GLIB_LIBS@ @DBUS_LIBS@ @XTABLES_LIBS@ -ldl
+
+TESTS += unit/test-iptables
+
+unit_test_iptables_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS) @GLIB_CFLAGS@
+unit_test_iptables_SOURCES = $(backtrace_sources) src/connman.h src/log.c \
+                                                            
unit/test-iptables.c src/iptables.c
+unit_test_iptables_LDADD = @GLIB_LIBS@ -ldl
+
 endif
 
 tools_dnsproxy_test_SOURCES = tools/dnsproxy-test.c
diff --git a/unit/test-iptables.c b/unit/test-iptables.c
new file mode 100644
index 00000000..cd261d05
--- /dev/null
+++ b/unit/test-iptables.c
@@ -0,0 +1,699 @@
+/*
+ *  ConnMan firewall unit tests
+ *
+ *  Copyright (C) 2019 Jolla Ltd. All rights reserved.
+ *  Contact: [email protected]
+ *
+ *  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
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gdbus.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <xtables.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#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,
+};
+
+enum configtype test_config_type = TEST_CONFIG_PASS;
+
+static void set_test_config(enum configtype type)
+{
+       test_config_type = type;
+}
+
+/* Start of dummies */
+
+/* xtables dummies */
+
+/* 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)
+
+/* 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;
+}
+
+int xt_target_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_target **targetinfo)
+{
+       return 0;
+}
+
+static void xt_x6_parse(struct xt_option_call *opt) {
+       return;
+}
+
+static void xt_x6_fcheck(struct xt_fcheck_call *call) {
+       return;
+}
+
+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,
+};
+
+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);
+
+       DBG("%s", src);
+
+       xt_params->exit_err(PARAMETER_PROBLEM, "longjmp() %s", src);
+}
+
+int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto)
+{
+       DBG("%d", nfproto);
+
+       if (test_config_type & TEST_CONFIG_INIT_FAIL)
+               call_error("xtables_init_all");
+
+       xt_params = xtp;
+
+       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");
+
+       *matches = g_try_new0(struct xtables_rule_match, 1);
+       (*matches)->next = NULL;
+       (*matches)->match = &xt_match;
+       (*matches)->completed = 0;
+
+       return &xt_match;
+}
+
+struct xtables_target *xtables_find_target(const char *name,
+                       enum xtables_tryload tryload)
+{
+       DBG("name %s type %d", name, tryload);
+
+       if (test_config_type & TEST_CONFIG_FIND_TARGET_FAIL)
+               call_error("xtables_find_target");
+
+       return &xt_target;
+}
+
+uint16_t xtables_parse_protocol(const char *s)
+{
+       DBG("protocol %s", s);
+
+       if (test_config_type & TEST_CONFIG_PARSE_PROTOCOL_FAIL)
+               call_error("xtables_parse_protocol");
+
+       if (!g_strcmp0(s, "tcp"))
+               return 6;
+
+       return 0;
+}
+
+void xtables_option_mfcall(struct xtables_match *m)
+{
+       DBG("");
+
+       if (test_config_type & TEST_CONFIG_MFCALL_FAIL)
+               call_error("xtables_option_mfcall");
+
+       m = &xt_match;
+
+       return;
+}
+
+void xtables_option_tfcall(struct xtables_target *t)
+{
+       DBG("");
+
+       if (test_config_type & TEST_CONFIG_TFCALL_FAIL)
+               call_error("xtables_option_tfcall");
+
+       t = &xt_target;
+
+       return;
+}
+
+void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
+                       struct xtables_match *m, void *fw)
+{
+       DBG("");
+
+       if (test_config_type & TEST_CONFIG_MPCALL_FAIL)
+               call_error("xtables_option_mpcall");
+
+       m = &xt_match;
+
+       return;
+}
+
+void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
+                       struct xtables_target *t, void *fw)
+{
+       DBG("");
+
+       if (test_config_type & TEST_CONFIG_TPCALL_FAIL)
+               call_error("xtables_option_tpcall");
+
+       t = &xt_target;
+
+       return;
+}
+
+int xtables_insmod(const char *modname, const char *modprobe, bool quiet)
+{
+       DBG("mod %s modprobe %s quiet %s", modname, modprobe,
+                               quiet ? "true" : "false");
+
+       if (test_config_type & TEST_CONFIG_INSMOD_FAIL)
+               call_error("xtables_insmod");
+
+       return 0;
+}
+
+int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
+{
+       DBG("name %s rev %d opt %d", name, revision, opt);
+
+       if (test_config_type & TEST_CONFIG_COMPATIBLE_REV_FAIL)
+               call_error("xtables_compatible_revision");
+
+       return 1;
+}
+
+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");
+
+       return opt1;
+}
+
+struct option *xtables_merge_options(struct option *orig_opts,
+                       struct option *oldopts, const struct option *newopts,
+                       unsigned int *option_offset)
+{
+       if (test_config_type & TEST_CONFIG_MERGE_OPTIONS_FAIL)
+               call_error("xtables_merge_options");
+
+       return orig_opts;
+}
+
+/* End of xtables dummies */
+
+/* socket dummies */
+
+int global_sockfd = 1000;
+
+int socket(int domain, int type, int protocol)
+{
+       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;
+}
+
+int setsockopt(int sockfd, int level, int optname, const void *optval,
+                       socklen_t optlen)
+{
+       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 iptables_test_jmp_ok1()
+{
+       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);
+
+       __connman_iptables_cleanup();
+}
+
+static void iptables_test_jmp_ok2()
+{
+       set_test_config(TEST_CONFIG_PARSE_PROTOCOL_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 --dport 42 -j ACCEPT"), ==,
+                               -EINVAL);
+
+       __connman_iptables_cleanup();
+}
+
+static void iptables_test_jmp_ok3()
+{
+       set_test_config(TEST_CONFIG_TFCALL_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 --dport 42 -j ACCEPT"), ==,
+                               -EINVAL);
+
+       __connman_iptables_cleanup();
+}
+
+static void iptables_test_jmp_ok4()
+{
+       set_test_config(TEST_CONFIG_MFCALL_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 --dport 42 -j ACCEPT"), ==,
+                               -EINVAL);
+
+       __connman_iptables_cleanup();
+}
+
+static void iptables_test_jmp_ok5()
+{
+       set_test_config(TEST_CONFIG_TPCALL_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 --dport 42 -j ACCEPT "
+                               "--comment test"), ==, -EINVAL);
+
+       __connman_iptables_cleanup();
+}
+
+static void iptables_test_jmp_ok6()
+{
+       set_test_config(TEST_CONFIG_MPCALL_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 --dport 42 -j ACCEPT"), ==,
+                               -EINVAL);
+
+       __connman_iptables_cleanup();
+}
+
+/*
+ * 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:
+ */
-- 
2.19.2



------------------------------

Subject: Digest Footer

_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman


------------------------------

End of connman Digest, Vol 40, Issue 3
**************************************

Reply via email to