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. [PATCH v4 0/8] session: Add per-interface routing (Lukasz Nowak)
   2. [PATCH v4 1/8] session: Fix default route for ppp services
      (Lukasz Nowak)
   3. [PATCH v4 2/8] session: Add AllowedInterface config parameter
      (Lukasz Nowak)
   4. [PATCH v4 3/8] client: Add session AllowedInterface config
      (Lukasz Nowak)
   5. [PATCH v4 4/8] firewall: Add fwmark based on source ip
      address (Lukasz Nowak)


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

Message: 1
Date: Tue, 31 Jan 2017 14:13:02 +0000
From: Lukasz Nowak <[email protected]>
To: [email protected]
Subject: [PATCH v4 0/8] session: Add per-interface routing
Message-ID: <[email protected]>

From: Lukasz Nowak <[email protected]>

changes from v3:
- fixed compiler warnings
- marked new session config fields as experimental

changes from v2:
- implemented source IP rule in firewall-nftables
- using "*" or "" for AllowedInterface allows any interface

changes from v1:
- added documentation
- split firewall and session changes into separate commits
- cosmetic updates after v1 review

Adding a new feature to the sessions, which allows applications to direct
routed traffic to a specific network interface.

This requires that multiple default routes with gateways are set up, one
for each interface. And then iproute and iptables rules need to be added
to direct traffic based on source ip address, to the correct routing table.
Applications can use bind before connect mechanism, to bind sockets to
required interfaces.

The application side can be tested with:
ping -I <interface_ip> <target_ip>

Use case for this is to have multiple network interfaces available for
external traffic at the same time. It can be used to validate that a full
path to an external server is working properly, by maintaining multiple
tcp connections, one for each interface.

Lukasz Nowak (8):
  session: Fix default route for ppp services
  session: Add AllowedInterface config parameter
  client: Add session AllowedInterface config
  firewall: Add fwmark based on source ip address
  session: Add source ip rule
  session: Remove old session rules and routes after a config change
  client: Add session source ip rule
  doc: Session multi-interface routing

 client/commands.c        |  39 ++++++++++++
 doc/session-api.txt      |  23 +++++++
 doc/session-overview.txt |  31 +++++++++
 include/session.h        |   2 +
 src/connman.h            |   3 +-
 src/firewall-iptables.c  |  11 +++-
 src/firewall-nftables.c  | 108 ++++++++++++++++++++++++++-----
 src/session.c            | 162 ++++++++++++++++++++++++++++++++++++++++++++---
 8 files changed, 353 insertions(+), 26 deletions(-)

-- 
2.7.4



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

Message: 2
Date: Tue, 31 Jan 2017 14:13:03 +0000
From: Lukasz Nowak <[email protected]>
To: [email protected]
Subject: [PATCH v4 1/8] session: Fix default route for ppp services
Message-ID: <[email protected]>

From: Lukasz Nowak <[email protected]>

When a session is connected to a ppp service, ipconfig
will not contain a gateway IP address. Currently setting up
of the session routing table fails, due to
__connman_inet_add_default_to_table returning an error.

In that scenario, INADDR_ANY needs to be used as a gateway.
---
 src/session.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/session.c b/src/session.c
index b1e9e1b..09fc7c3 100644
--- a/src/session.c
+++ b/src/session.c
@@ -351,6 +351,7 @@ static void add_default_route(struct connman_session 
*session)
 {
        struct connman_ipconfig *ipconfig;
        int err;
+       struct in_addr addr = { INADDR_ANY };
 
        if (!session->service)
                return;
@@ -359,6 +360,9 @@ static void add_default_route(struct connman_session 
*session)
        session->index = __connman_ipconfig_get_index(ipconfig);
        session->gateway = g_strdup(__connman_ipconfig_get_gateway(ipconfig));
 
+       if (!session->gateway)
+               session->gateway = g_strdup(inet_ntoa(addr));
+
        DBG("index %d routing table %d default gateway %s",
                session->index, session->mark, session->gateway);
 
-- 
2.7.4



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

Message: 3
Date: Tue, 31 Jan 2017 14:13:04 +0000
From: Lukasz Nowak <[email protected]>
To: [email protected]
Subject: [PATCH v4 2/8] session: Add AllowedInterface config parameter
Message-ID: <[email protected]>

From: Lukasz Nowak <[email protected]>

In order to be able to bind a session to a specific interface,
AllowedInterface config option has been added. It allows to
bind a session to a service with a specified network interface
name (e.g. eth0).

AllowedInterface is supported through both dbus and session policy.
Policy always overrides dbus.
---
 include/session.h |  1 +
 src/session.c     | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/include/session.h b/include/session.h
index 37dfc4e..e8d7e93 100644
--- a/include/session.h
+++ b/include/session.h
@@ -65,6 +65,7 @@ struct connman_session_config {
        enum connman_session_type type;
        bool ecall;
        GSList *allowed_bearers;
+       char *allowed_interface;
 };
 
 typedef int (* connman_session_config_func_t) (struct connman_session *session,
diff --git a/src/session.c b/src/session.c
index 09fc7c3..c5f5792 100644
--- a/src/session.c
+++ b/src/session.c
@@ -63,6 +63,7 @@ struct connman_session {
        struct connman_service *service_last;
        struct connman_session_config *policy_config;
        GSList *user_allowed_bearers;
+       char *user_allowed_interface;
 
        bool ecall;
 
@@ -467,6 +468,7 @@ static void free_session(struct connman_session *session)
 
        destroy_policy_config(session);
        g_slist_free(session->info->config.allowed_bearers);
+       g_free(session->info->config.allowed_interface);
        g_free(session->owner);
        g_free(session->session_path);
        g_free(session->notify_path);
@@ -505,6 +507,7 @@ static void cleanup_session(gpointer user_data)
        update_session_state(session);
 
        g_slist_free(session->user_allowed_bearers);
+       g_free(session->user_allowed_interface);
 
        free_session(session);
 }
@@ -516,6 +519,7 @@ struct creation_data {
        /* user config */
        enum connman_session_type type;
        GSList *allowed_bearers;
+       char *allowed_interface;
 };
 
 static void cleanup_creation_data(struct creation_data *creation_data)
@@ -527,6 +531,7 @@ static void cleanup_creation_data(struct creation_data 
*creation_data)
                dbus_message_unref(creation_data->pending);
 
        g_slist_free(creation_data->allowed_bearers);
+       g_free(creation_data->allowed_interface);
        g_free(creation_data);
 }
 
@@ -725,6 +730,17 @@ static void apply_policy_on_bearers(GSList 
*policy_bearers, GSList *bearers,
        }
 }
 
+static char * apply_policy_on_interface(const char *policy_interface,
+                               const char *user_interface)
+{
+       if (policy_interface)
+               return g_strdup(policy_interface);
+       else if (user_interface)
+               return g_strdup(user_interface);
+       else
+               return NULL;
+}
+
 const char *connman_session_get_owner(struct connman_session *session)
 {
        return session->owner;
@@ -870,6 +886,17 @@ static void append_notify(DBusMessageIter *dict,
                info_last->config.allowed_bearers = 
info->config.allowed_bearers;
        }
 
+       if (session->append_all ||
+                       info->config.allowed_interface != 
info_last->config.allowed_interface) {
+               char *ifname = info->config.allowed_interface;
+               if (!ifname)
+                       ifname = "*";
+               connman_dbus_dict_append_basic(dict, "AllowedInterface",
+                                               DBUS_TYPE_STRING,
+                                               &ifname);
+               info_last->config.allowed_interface = 
info->config.allowed_interface;
+       }
+
        session->append_all = false;
 }
 
@@ -889,7 +916,8 @@ static bool compute_notifiable_changes(struct 
connman_session *session)
                return true;
 
        if (info->config.allowed_bearers != info_last->config.allowed_bearers ||
-                       info->config.type != info_last->config.type)
+                       info->config.type != info_last->config.type ||
+                       info->config.allowed_interface != 
info_last->config.allowed_interface)
                return true;
 
        return false;
@@ -943,6 +971,7 @@ int connman_session_config_update(struct connman_session 
*session)
 {
        struct session_info *info = session->info;
        GSList *allowed_bearers;
+       char *allowed_interface;
        int err;
 
        DBG("session %p", session);
@@ -968,6 +997,10 @@ int connman_session_config_update(struct connman_session 
*session)
                session->user_allowed_bearers,
                &allowed_bearers);
 
+       allowed_interface = apply_policy_on_interface(
+               session->policy_config->allowed_interface,
+               session->user_allowed_interface);
+
        if (session->active)
                set_active_session(session, false);
 
@@ -977,6 +1010,9 @@ int connman_session_config_update(struct connman_session 
*session)
        g_slist_free(info->config.allowed_bearers);
        info->config.allowed_bearers = allowed_bearers;
 
+       g_free(info->config.allowed_interface);
+       info->config.allowed_interface = allowed_interface;
+
        session_activate(session);
 
        info->config.type = apply_policy_on_type(
@@ -1105,6 +1141,26 @@ static DBusMessage *change_session(DBusConnection *conn,
                        info->config.type = apply_policy_on_type(
                                session->policy_config->type,
                                connman_session_parse_connection_type(val));
+               } else if (g_str_equal(name, "AllowedInterface")) {
+                       dbus_message_iter_get_basic(&value, &val);
+                       if (session->active)
+                               set_active_session(session, false);
+
+                       session->active = false;
+                       session_deactivate(session);
+
+                       g_free(session->user_allowed_interface);
+                       /* empty string means allow any interface */
+                       if (0 == g_strcmp0(val, ""))
+                               session->user_allowed_interface = NULL;
+                       else
+                               session->user_allowed_interface = g_strdup(val);
+
+                       info->config.allowed_interface = 
apply_policy_on_interface(
+                               session->policy_config->allowed_interface,
+                               session->user_allowed_interface);
+
+                       session_activate(session);
                } else {
                        goto err;
                }
@@ -1238,11 +1294,18 @@ static int session_policy_config_cb(struct 
connman_session *session,
        session->user_allowed_bearers = creation_data->allowed_bearers;
        creation_data->allowed_bearers = NULL;
 
+       session->user_allowed_interface = creation_data->allowed_interface;
+       creation_data->allowed_interface = NULL;
+
        apply_policy_on_bearers(
                        session->policy_config->allowed_bearers,
                        session->user_allowed_bearers,
                        &info->config.allowed_bearers);
 
+       info->config.allowed_interface = apply_policy_on_interface(
+               session->policy_config->allowed_interface,
+               session->user_allowed_interface);
+
        g_hash_table_replace(session_hash, session->session_path, session);
 
        DBG("add %s", session->session_path);
@@ -1267,6 +1330,7 @@ static int session_policy_config_cb(struct 
connman_session *session,
        info_last->config.priority = info->config.priority;
        info_last->config.roaming_policy = info->config.roaming_policy;
        info_last->config.allowed_bearers = info->config.allowed_bearers;
+       info_last->config.allowed_interface = info->config.allowed_interface;
 
        session->append_all = true;
 
@@ -1354,6 +1418,9 @@ int __connman_session_create(DBusMessage *msg)
                                        
connman_session_parse_connection_type(val);
 
                                user_connection_type = true;
+                       } else if (g_str_equal(key, "AllowedInterface")) {
+                               dbus_message_iter_get_basic(&value, &val);
+                               creation_data->allowed_interface = 
g_strdup(val);
                        } else {
                                err = -EINVAL;
                                goto err;
@@ -1553,6 +1620,7 @@ static bool session_match_service(struct connman_session 
*session,
        enum connman_service_type bearer_type;
        enum connman_service_type service_type;
        GSList *list;
+       char *ifname;
 
        if (policy && policy->allowed)
                return policy->allowed(session, service);
@@ -1560,9 +1628,16 @@ static bool session_match_service(struct connman_session 
*session,
        for (list = session->info->config.allowed_bearers; list; list = 
list->next) {
                bearer_type = GPOINTER_TO_INT(list->data);
                service_type = connman_service_get_type(service);
-
-               if (bearer_type == service_type)
-                       return true;
+               ifname = connman_service_get_interface(service);
+
+               if (bearer_type == service_type &&
+                       (session->info->config.allowed_interface == NULL ||
+                       0 == g_strcmp0(session->info->config.allowed_interface, 
"*") ||
+                       0 == g_strcmp0(session->info->config.allowed_interface, 
ifname))) {
+                               g_free(ifname);
+                               return true;
+               }
+               g_free(ifname);
        }
 
        return false;
-- 
2.7.4



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

Message: 4
Date: Tue, 31 Jan 2017 14:13:05 +0000
From: Lukasz Nowak <[email protected]>
To: [email protected]
Subject: [PATCH v4 3/8] client: Add session AllowedInterface config
Message-ID: <[email protected]>

From: Lukasz Nowak <[email protected]>

Add ability to set the AllowedInterface field in session
config. Using --ifname without a second argument, clears the
allowed interface, i.e. any interface is allowed.
Using "*" also allows any interface.
---
 client/commands.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/client/commands.c b/client/commands.c
index d7f59ef..c41e9b4 100644
--- a/client/commands.c
+++ b/client/commands.c
@@ -1896,6 +1896,7 @@ static int session_config(char *args[], int num,
        int index = 0, res = 0;
        struct config_append append;
        char c;
+       char *ifname;
 
        while (index < num && args[index]) {
                append.opts = &args[index];
@@ -1922,6 +1923,18 @@ static int session_config(char *args[], int num,
                                        DBUS_TYPE_STRING, &args[index + 1]);
                        append.values = 2;
                        break;
+               case 'i':
+                       if (index + 1 < num)
+                               ifname = args[index + 1];
+                       else
+                               ifname = "";
+
+                       res = __connmanctl_dbus_session_change(connection,
+                                       session_path, session_config_return,
+                                       "AllowedInterface", "AllowedInterface",
+                                       DBUS_TYPE_STRING, &ifname);
+                       append.values = 2;
+                       break;
 
                default:
                        res = -EINVAL;
@@ -2209,6 +2222,7 @@ static struct connman_option monitor_options[] = {
 static struct connman_option session_options[] = {
        {"bearers", 'b', "<technology1> [<technology2> [...]]"},
        {"type", 't', "local|internet|any"},
+       {"ifname", 'i', "[<interface_name>]"},
        { NULL, }
 };
 
-- 
2.7.4



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

Message: 5
Date: Tue, 31 Jan 2017 14:13:06 +0000
From: Lukasz Nowak <[email protected]>
To: [email protected]
Subject: [PATCH v4 4/8] firewall: Add fwmark based on source ip
        address
Message-ID: <[email protected]>

From: Lukasz Nowak <[email protected]>

Add an option to enable insertion of firewall MARK into packets,
based on their source ip address. This will be used by the
multi-interface routing functionality of sessions.
---
 src/connman.h           |   3 +-
 src/firewall-iptables.c |  11 ++++-
 src/firewall-nftables.c | 108 +++++++++++++++++++++++++++++++++++++++++-------
 src/session.c           |   1 +
 4 files changed, 105 insertions(+), 18 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index 577c808..ce4d82e 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -1013,7 +1013,8 @@ int __connman_firewall_enable_snat(struct 
firewall_context *ctx,
 int __connman_firewall_disable_snat(struct firewall_context *ctx);
 int __connman_firewall_enable_marking(struct firewall_context *ctx,
                                        enum connman_session_id_type id_type,
-                                       char *id, uint32_t mark);
+                                       char *id, const char *src_ip,
+                                       uint32_t mark);
 int __connman_firewall_disable_marking(struct firewall_context *ctx);
 
 int __connman_firewall_init(void);
diff --git a/src/firewall-iptables.c b/src/firewall-iptables.c
index c58efc1..45943a8 100644
--- a/src/firewall-iptables.c
+++ b/src/firewall-iptables.c
@@ -495,7 +495,8 @@ static void firewall_disable_connmark(void)
 
 int __connman_firewall_enable_marking(struct firewall_context *ctx,
                                        enum connman_session_id_type id_type,
-                                       char *id, uint32_t mark)
+                                       char *id, const char *src_ip,
+                                       uint32_t mark)
 {
        int err;
 
@@ -514,11 +515,19 @@ int __connman_firewall_enable_marking(struct 
firewall_context *ctx,
                                "-m owner --gid-owner %s -j MARK --set-mark %d",
                                        id, mark);
                break;
+       case CONNMAN_SESSION_ID_TYPE_UNKNOWN:
+               break;
        case CONNMAN_SESSION_ID_TYPE_LSM:
        default:
                return -EINVAL;
        }
 
+       if (src_ip) {
+               firewall_add_rule(ctx, "mangle", "OUTPUT",
+                               "-s %s -j MARK --set-mark %d",
+                                       src_ip, mark);
+       }
+
        return firewall_enable_rules(ctx);
 }
 
diff --git a/src/firewall-nftables.c b/src/firewall-nftables.c
index 4d47f20..2503ee2 100644
--- a/src/firewall-nftables.c
+++ b/src/firewall-nftables.c
@@ -798,9 +798,70 @@ err:
        return -ENOMEM;
 }
 
+static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct 
nftnl_rule **res)
+{
+       struct nftnl_rule *rule;
+       struct nftnl_expr *expr;
+       int err;
+       in_addr_t s_addr;
+
+       /*
+        * # nft --debug netlink add rule connman route-output \
+        *      ip saddr 192.168.10.31 mark set 1234
+        *
+        *      ip connman route-output
+        *        [ payload load 4b @ network header + 12 => reg 1 ]
+        *        [ cmp eq reg 1 0x1f0aa8c0 ]
+        *        [ immediate reg 1 0x000004d2 ]
+        *        [ meta set mark with reg 1 ]
+        */
+
+       rule = nftnl_rule_alloc();
+       if (!rule)
+               return -ENOMEM;
+
+       nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
+       nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
+
+       /* family ipv4 */
+       nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
+
+       /* source IP */
+       err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
+                       offsetof(struct iphdr, saddr), sizeof(struct in_addr));
+       if (err < 0)
+               goto err;
+
+       s_addr = inet_addr(src_ip);
+       err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &s_addr, sizeof(s_addr));
+       if (err < 0)
+               goto err;
+
+       expr = nftnl_expr_alloc("immediate");
+       if (!expr)
+               goto err;
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
+       nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
+       nftnl_rule_add_expr(rule, expr);
+
+       expr = nftnl_expr_alloc("meta");
+       if (!expr)
+               goto err;
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
+       nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
+       nftnl_rule_add_expr(rule, expr);
+
+       *res = rule;
+       return 0;
+
+err:
+       return -ENOMEM;
+}
+
 int __connman_firewall_enable_marking(struct firewall_context *ctx,
                                        enum connman_session_id_type id_type,
-                                       char *id, uint32_t mark)
+                                       char *id, const char *src_ip,
+                                       uint32_t mark)
 {
        struct nftnl_rule *rule;
        struct mnl_socket *nl;
@@ -810,29 +871,44 @@ int __connman_firewall_enable_marking(struct 
firewall_context *ctx,
 
        DBG("");
 
-
-       if (id_type != CONNMAN_SESSION_ID_TYPE_UID)
+       if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
+               pw = getpwnam(id);
+               if (!pw)
+                       return -EINVAL;
+               uid = pw->pw_uid;
+       }
+       else if (!src_ip)
                return -ENOTSUP;
 
-       pw = getpwnam(id);
-       if (!pw)
-               return -EINVAL;
-       uid = pw->pw_uid;
-
         err = socket_open_and_bind(&nl);
         if (err < 0)
                return err;
 
-       err = build_rule_marking(uid, mark, &rule);
-       if (err < 0)
-               goto out;
+       if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
+               err = build_rule_marking(uid, mark, &rule);
+               if (err < 0)
+                       goto out;
 
-       ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
-       err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
-                       NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
-                       CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+               ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
+               err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+                               NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+                               CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
 
-       nftnl_rule_free(rule);
+               nftnl_rule_free(rule);
+       }
+
+       if (src_ip) {
+               err = build_rule_src_ip(src_ip, mark, &rule);
+               if (err < 0)
+                       goto out;
+
+               ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
+               err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
+                               NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
+                               CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
+
+               nftnl_rule_free(rule);
+       }
 out:
        mnl_socket_close(nl);
        return err;
diff --git a/src/session.c b/src/session.c
index c5f5792..b7a2808 100644
--- a/src/session.c
+++ b/src/session.c
@@ -286,6 +286,7 @@ static int init_firewall_session(struct connman_session 
*session)
        err =__connman_firewall_enable_marking(fw,
                                        session->policy_config->id_type,
                                        session->policy_config->id,
+                                       NULL,
                                        session->mark);
        if (err < 0) {
                __connman_firewall_destroy(fw);
-- 
2.7.4



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

Subject: Digest Footer

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


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

End of connman Digest, Vol 15, Issue 41
***************************************

Reply via email to