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 v0 9/9] doc: Document WireGuard VPN plugin (Daniel Wagner)
   2. [PATCH v0 5/9] shared: Add Generic Netlink helpers for libmnl
      (Daniel Wagner)
   3. [PATCH v0 8/9] vpn: Add WireGuard support (Daniel Wagner)
   4. Re: question: enable two ethernet interfaces (Daniel Wagner)


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

Message: 1
Date: Fri, 19 Jul 2019 13:21:38 +0200
From: Daniel Wagner <[email protected]>
To: [email protected]
Cc: Daniel Wagner <[email protected]>
Subject: [PATCH v0 9/9] doc: Document WireGuard VPN plugin
Message-ID: <[email protected]>

---
 doc/vpn-config-format.txt | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/doc/vpn-config-format.txt b/doc/vpn-config-format.txt
index 0bc62c08f19a..c262302e6a4f 100644
--- a/doc/vpn-config-format.txt
+++ b/doc/vpn-config-format.txt
@@ -208,6 +208,16 @@ PPTP VPN supports following options (see pptp(8) and 
pppd(8) for details)
  PPPD.NoVJ           novj                 No Van Jacobson compression (O)
 
 
+WireGuard VPN supports following options
+ Option name                              Description
+ WireGuard.Address                        Internal IP address 
(local/netmask/peer)
+ WireGuard.ListPort                       Local listen port
+ WireGuard.PrivateKey                     Private key of interface
+ WireGuard.PublicKey                      Public key of peer
+ WireGuard.AllowedIPs                     See Cryptokey Routing
+ WireGuard.Endpoint                       Server Endpoint
+
+
 Example
 =======
 
@@ -245,3 +255,15 @@ Domain = my.home.network
 OpenVPN.CACert = /etc/certs/cacert.pem
 OpenVPN.Cert = /etc/certs/cert.pem
 OpenVPN.Key = /etc/certs/cert.key
+
+[provider_wireguard]
+Type = wireguard
+Name = Wireguard VPN Tunnel
+Host = 3.2.5.6
+Domain = my.home.network
+WireGuard.Address = 10.2.0.2/24
+WireGuard.ListenPort = 47824
+WireGuard.PrivateKey = qKIj010hDdWSjQQyVCnEgthLXusBgm3I6HWrJUaJymc=
+WireGuard.PublicKey = zzqUfWGIil6QxrAGz77HE5BGUEdD2PgHYnCg3CDKagE=
+WireGuard.AllowedIPs = 0.0.0.0/0, ::/0
+WireGuard.Endpoint = 3.2.5.6:51820
-- 
2.20.1


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

Message: 2
Date: Fri, 19 Jul 2019 13:21:34 +0200
From: Daniel Wagner <[email protected]>
To: [email protected]
Cc: Daniel Wagner <[email protected]>
Subject: [PATCH v0 5/9] shared: Add Generic Netlink helpers for libmnl
Message-ID: <[email protected]>

mnlg.c and mnlg.h are a copy from iproute2.

The call to nl_dump_ext_ack() and nl_dump_ext_ack_done() have been
removed from the code to avoid additional dependencies.

git://git.kernel.org/pub/scm/network/iproute2/iproute2.git
d035cc1b4e83e2589ea2115cdc2fa7c6d3693a5a

The helpers are needed for the WireGuard VPN plugin.
---
 Makefile.plugins  |  12 +-
 configure.ac      |   3 +-
 src/shared/mnlg.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/mnlg.h |  27 ++++
 4 files changed, 362 insertions(+), 5 deletions(-)
 create mode 100644 src/shared/mnlg.c
 create mode 100644 src/shared/mnlg.h

diff --git a/Makefile.plugins b/Makefile.plugins
index 3d4e32f08810..a4d255f363d1 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -66,17 +66,21 @@ if WIREGUARD
 builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h
 if WIREGUARD_BUILTIN
 builtin_vpn_modules += wireguard
-builtin_vpn_sources += vpn/plugins/wireguard.c
-builtin_vpn_cflags += -DWIREGUARD=\"@WIREGUARD@\"
+builtin_vpn_sources += src/shared/mnlg.h src/shared/mnlg.c \
+                       vpn/plugins/wireguard.c
+builtin_vpn_cflags += @LIBMNL_CFLAGS@ -DWIREGUARD=\"@WIREGUARD@\"
+builtin_vpn_libadd += @LIBMNL_LIBS@
 else
 vpn_plugin_LTLIBRARIES += vpn/plugins/wireguard.la
 vpn_plugin_objects += $(plugins_wireguard_la_OBJECTS)
-vpn_plugins_wireguard_la_SOURCES = vpn/plugins/wireguard.c
-vpn_plugins_wireguard_la_CFLAGS = $(plugin_cflags) \
+vpn_plugins_wireguard_la_SOURCES = src/shared/mnlg.h src/shared/mnlg.c \
+                                       vpn/plugins/wireguard.c
+vpn_plugins_wireguard_la_CFLAGS = $(plugin_cflags) @LIBMNL_CFLAGS@ \
                                        -DWIREGUARD=\"@WIREGUARD@\" \
                                        -DVPN_STATEDIR=\""$(vpn_statedir)"\" \
                                        -DSCRIPTDIR=\""$(build_scriptdir)"\"
 vpn_plugins_wireguard_la_LDFLAGS = $(plugin_ldflags)
+vpn_plugins_wireguard_la_LIBADD = @LIBMNL_LIBS@
 endif
 endif
 
diff --git a/configure.ac b/configure.ac
index 537ba5f4007f..3695ef5b2b60 100644
--- a/configure.ac
+++ b/configure.ac
@@ -288,7 +288,8 @@ fi
 AM_CONDITIONAL(XTABLES, test "${found_iptables}" != "no")
 
 found_libmnl="no"
-if (test "${firewall_type}" = "nftables"); then
+if (test "${firewall_type}" = "nftables" -o \
+               "${enable_wireguard}" != "no"); then
        PKG_CHECK_MODULES(LIBMNL, [libmnl >= 1.0.0], [found_libmnl="yes"],
                AC_MSG_ERROR([libmnl >= 1.0.0 not found]))
        AC_SUBST(LIBMNL_CFLAGS)
diff --git a/src/shared/mnlg.c b/src/shared/mnlg.c
new file mode 100644
index 000000000000..6b02059d4490
--- /dev/null
+++ b/src/shared/mnlg.c
@@ -0,0 +1,325 @@
+/*
+ *   mnlg.c    Generic Netlink helpers for libmnl
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <[email protected]>
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+#include "mnlg.h"
+
+#ifndef MNL_ARRAY_SIZE
+#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+
+struct mnlg_socket {
+       struct mnl_socket *nl;
+       char *buf;
+       uint32_t id;
+       uint8_t version;
+       unsigned int seq;
+       unsigned int portid;
+};
+
+static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t 
cmd,
+                                          uint16_t flags, uint32_t id,
+                                          uint8_t version)
+{
+       struct nlmsghdr *nlh;
+       struct genlmsghdr *genl;
+
+       nlh = mnl_nlmsg_put_header(nlg->buf);
+       nlh->nlmsg_type = id;
+       nlh->nlmsg_flags = flags;
+       nlg->seq = time(NULL);
+       nlh->nlmsg_seq = nlg->seq;
+
+       genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
+       genl->cmd = cmd;
+       genl->version = version;
+
+       return nlh;
+}
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+                                 uint16_t flags)
+{
+       return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
+}
+
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh)
+{
+       return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
+}
+
+static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data)
+{
+       return MNL_CB_OK;
+}
+
+static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data)
+{
+       const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+
+       /* Netlink subsystems returns the errno value with different signess */
+       if (err->error < 0)
+               errno = -err->error;
+       else
+               errno = err->error;
+
+       return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
+}
+
+static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
+{
+       int len = *(int *)NLMSG_DATA(nlh);
+
+       if (len < 0) {
+               errno = -len;
+               return MNL_CB_ERROR;
+       }
+       return MNL_CB_STOP;
+}
+
+static mnl_cb_t mnlg_cb_array[NLMSG_MIN_TYPE] = {
+       [NLMSG_NOOP]    = mnlg_cb_noop,
+       [NLMSG_ERROR]   = mnlg_cb_error,
+       [NLMSG_DONE]    = mnlg_cb_stop,
+       [NLMSG_OVERRUN] = mnlg_cb_noop,
+};
+
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data)
+{
+       int err;
+
+       do {
+               err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
+                                         MNL_SOCKET_BUFFER_SIZE);
+               if (err <= 0)
+                       break;
+               err = mnl_cb_run2(nlg->buf, err, nlg->seq, nlg->portid,
+                                 data_cb, data, mnlg_cb_array,
+                                 ARRAY_SIZE(mnlg_cb_array));
+       } while (err > 0);
+
+       return err;
+}
+
+struct group_info {
+       bool found;
+       uint32_t id;
+       const char *name;
+};
+
+static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
+{
+       const struct nlattr **tb = data;
+       int type = mnl_attr_get_type(attr);
+
+       if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch (type) {
+       case CTRL_ATTR_MCAST_GRP_ID:
+               if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+                       return MNL_CB_ERROR;
+               break;
+       case CTRL_ATTR_MCAST_GRP_NAME:
+               if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+                       return MNL_CB_ERROR;
+               break;
+       }
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static void parse_genl_mc_grps(struct nlattr *nested,
+                              struct group_info *group_info)
+{
+       struct nlattr *pos;
+       const char *name;
+
+       mnl_attr_for_each_nested(pos, nested) {
+               struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {};
+
+               mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
+               if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
+                   !tb[CTRL_ATTR_MCAST_GRP_ID])
+                       continue;
+
+               name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+               if (strcmp(name, group_info->name) != 0)
+                       continue;
+
+               group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+               group_info->found = true;
+       }
+}
+
+static int get_group_id_attr_cb(const struct nlattr *attr, void *data)
+{
+       const struct nlattr **tb = data;
+       int type = mnl_attr_get_type(attr);
+
+       if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+               return MNL_CB_ERROR;
+
+       if (type == CTRL_ATTR_MCAST_GROUPS &&
+           mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+               return MNL_CB_ERROR;
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int get_group_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct group_info *group_info = data;
+       struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+       mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb);
+       if (!tb[CTRL_ATTR_MCAST_GROUPS])
+               return MNL_CB_ERROR;
+       parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info);
+       return MNL_CB_OK;
+}
+
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name)
+{
+       struct nlmsghdr *nlh;
+       struct group_info group_info;
+       int err;
+
+       nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+                                NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+       mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->id);
+
+       err = mnlg_socket_send(nlg, nlh);
+       if (err < 0)
+               return err;
+
+       group_info.found = false;
+       group_info.name = group_name;
+       err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info);
+       if (err < 0)
+               return err;
+
+       if (!group_info.found) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP,
+                                   &group_info.id, sizeof(group_info.id));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
+{
+       const struct nlattr **tb = data;
+       int type = mnl_attr_get_type(attr);
+
+       if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+               return MNL_CB_ERROR;
+
+       if (type == CTRL_ATTR_FAMILY_ID &&
+           mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+               return MNL_CB_ERROR;
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+       uint32_t *p_id = data;
+       struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+       struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+       mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb);
+       if (!tb[CTRL_ATTR_FAMILY_ID])
+               return MNL_CB_ERROR;
+       *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+       return MNL_CB_OK;
+}
+
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
+{
+       struct mnlg_socket *nlg;
+       struct nlmsghdr *nlh;
+       int one = 1;
+       int err;
+
+       nlg = malloc(sizeof(*nlg));
+       if (!nlg)
+               return NULL;
+
+       nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE);
+       if (!nlg->buf)
+               goto err_buf_alloc;
+
+       nlg->nl = mnl_socket_open(NETLINK_GENERIC);
+       if (!nlg->nl)
+               goto err_mnl_socket_open;
+
+       /* Older kernels may no support capped/extended ACK reporting */
+       mnl_socket_setsockopt(nlg->nl, NETLINK_CAP_ACK, &one, sizeof(one));
+       mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one, sizeof(one));
+
+       err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID);
+       if (err < 0)
+               goto err_mnl_socket_bind;
+
+       nlg->portid = mnl_socket_get_portid(nlg->nl);
+
+       nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+                                NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+       mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
+
+       err = mnlg_socket_send(nlg, nlh);
+       if (err < 0)
+               goto err_mnlg_socket_send;
+
+       err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id);
+       if (err < 0)
+               goto err_mnlg_socket_recv_run;
+
+       nlg->version = version;
+       return nlg;
+
+err_mnlg_socket_recv_run:
+err_mnlg_socket_send:
+err_mnl_socket_bind:
+       mnl_socket_close(nlg->nl);
+err_mnl_socket_open:
+       free(nlg->buf);
+err_buf_alloc:
+       free(nlg);
+       return NULL;
+}
+
+void mnlg_socket_close(struct mnlg_socket *nlg)
+{
+       mnl_socket_close(nlg->nl);
+       free(nlg->buf);
+       free(nlg);
+}
diff --git a/src/shared/mnlg.h b/src/shared/mnlg.h
new file mode 100644
index 000000000000..4d1babf3b4c2
--- /dev/null
+++ b/src/shared/mnlg.h
@@ -0,0 +1,27 @@
+/*
+ *   mnlg.h    Generic Netlink helpers for libmnl
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <[email protected]>
+ */
+
+#ifndef _MNLG_H_
+#define _MNLG_H_
+
+#include <libmnl/libmnl.h>
+
+struct mnlg_socket;
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+                                 uint16_t flags);
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh);
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void 
*data);
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name);
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version);
+void mnlg_socket_close(struct mnlg_socket *nlg);
+
+#endif /* _MNLG_H_ */
-- 
2.20.1


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

Message: 3
Date: Fri, 19 Jul 2019 13:21:37 +0200
From: Daniel Wagner <[email protected]>
To: [email protected]
Cc: Daniel Wagner <[email protected]>
Subject: [PATCH v0 8/9] vpn: Add WireGuard support
Message-ID: <[email protected]>

Implement a bare minimum for WireGuard support. The parser only
understands minium, e.g. only one peer. To create and manage the
WireGuard devices the upstream example code is used.
---
 vpn/plugins/wireguard.c | 328 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 327 insertions(+), 1 deletion(-)

diff --git a/vpn/plugins/wireguard.c b/vpn/plugins/wireguard.c
index e110eb545943..b28434fe6079 100644
--- a/vpn/plugins/wireguard.c
+++ b/vpn/plugins/wireguard.c
@@ -21,24 +21,350 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
 #include <glib.h>
 
 #define CONNMAN_API_SUBJECT_TO_CHANGE
 #include <connman/plugin.h>
+#include <connman/log.h>
 #include <connman/task.h>
+#include <connman/ipconfig.h>
+#include <connman/inet.h>
 #include <connman/dbus.h>
+#include <connman/setting.h>
 #include <connman/vpn-dbus.h>
 
+#include "../vpn-provider.h"
+#include "../vpn.h"
+
 #include "vpn.h"
 #include "wireguard.h"
 
-static int wg_init(void)
+static int parse_key(const char *str, wg_key key)
 {
+       unsigned char *buf;
+       size_t len;
+
+       buf = g_base64_decode(str, &len);
+
+       if (len != 32) {
+               g_free(buf);
+               return -EINVAL;
+       }
+
+       memcpy(key, buf, 32);
+
+       g_free(buf);
        return 0;
 }
 
+static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer)
+{
+       struct wg_allowedip *curaip;
+       char **tokens;
+       int i, err;
+
+       curaip = NULL;
+       tokens = g_strsplit(allowed_ips, ", ", -1);
+       for (i = 0; tokens[i]; i++) {
+               struct wg_allowedip *allowedip;
+               char buf[INET6_ADDRSTRLEN];
+               char **toks;
+               char *send;
+
+               toks = g_strsplit(tokens[i], "/", -1);
+               if (g_strv_length(toks) != 2) {
+                       g_strfreev(toks);
+                       continue;
+               }
+
+               allowedip = g_malloc0(sizeof(*allowedip));
+
+               err = inet_pton(AF_INET, toks[0], buf);
+               if (err == 1) {
+                       allowedip->family = AF_INET;
+                       memcpy(&allowedip->ip4, buf,
+                               sizeof(allowedip->ip4));
+               } else {
+                       err = inet_pton(AF_INET6, toks[0], buf);
+                       if (err == 1) {
+                               allowedip->family = AF_INET6;
+                               memcpy(&allowedip->ip6, buf,
+                                       sizeof(allowedip->ip6));
+                       }
+               }
+
+               allowedip->cidr = g_ascii_strtoull(toks[1], &send, 10);
+
+               if (err != 1) {
+                       g_strfreev(toks);
+                       g_free(allowedip);
+                       continue;
+               }
+
+               if (curaip == NULL)
+                       peer->first_allowedip = allowedip;
+               else
+                       curaip->next_allowedip = allowedip;
+               curaip = allowedip;
+       }
+
+       peer->last_allowedip = curaip;
+       g_strfreev(tokens);
+
+       return 0;
+}
+
+static int parse_endpoint(const char *endpoint, wg_peer *peer, char **gateway)
+{
+       char **tokens, *end;
+       int err;
+
+       if (endpoint && endpoint[0] == '[') {
+               /*
+                * IPv6 addresses should be in port notification, e.g
+                * "[IPv6 Address]:port"
+                */
+               tokens = g_strsplit(endpoint, "[]:", -1);
+               *gateway = g_strdup(tokens[0]);
+
+               peer->endpoint.addr.sa_family = AF_INET6;
+
+               err = inet_pton(AF_INET6, tokens[0],
+                               &peer->endpoint.addr6.sin6_addr);
+               peer->endpoint.addr6.sin6_port =
+                       htons(g_ascii_strtoull(tokens[1], &end, 10));
+       } else {
+               /* "IPv4Address:port" */
+               tokens = g_strsplit(endpoint, ":", -1);
+               *gateway = g_strdup(tokens[0]);
+
+               peer->endpoint.addr.sa_family = AF_INET;
+
+               err = inet_pton(AF_INET, tokens[0],
+                               &peer->endpoint.addr4.sin_addr);
+               peer->endpoint.addr4.sin_port =
+                       htons(g_ascii_strtoull(tokens[1], &end, 10));
+       }
+       g_strfreev(tokens);
+       if (!err)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int parse_address(const char *address, char *gateway,
+               struct connman_ipaddress **ipaddress)
+{
+       char buf[INET6_ADDRSTRLEN];
+       unsigned char prefixlen;
+       char **tokens;
+       char *end;
+       int err;
+
+       tokens = g_strsplit(address, "/", -1);
+       if (g_strv_length(tokens) != 2) {
+               g_strfreev(tokens);
+               return -EINVAL;
+       }
+
+       prefixlen = g_ascii_strtoull(tokens[1], &end, 10);
+
+       err = inet_pton(AF_INET, tokens[0], buf);
+       if (err == 1) {
+               char *netmask;
+               *ipaddress = connman_ipaddress_alloc(AF_INET);
+
+               netmask = g_strdup_printf("%d.%d.%d.%d",
+                               ((0xffffffff << (32 - prefixlen)) >> 24) & 0xff,
+                               ((0xffffffff << (32 - prefixlen)) >> 16) & 0xff,
+                               ((0xffffffff << (32 - prefixlen)) >> 8) & 0xff,
+                               ((0xffffffff << (32 - prefixlen)) >> 0) & 0xff);
+
+               connman_ipaddress_set_ipv4(*ipaddress, tokens[0],
+                                       netmask, gateway);
+               g_free(netmask);
+       } else {
+               err = inet_pton(AF_INET6, tokens[0], buf);
+               if (err == 1) {
+                       *ipaddress = connman_ipaddress_alloc(AF_INET6);
+                       connman_ipaddress_set_ipv6(*ipaddress, tokens[0],
+                                               prefixlen, gateway);
+               }
+       }
+
+       return 0;
+}
+
+struct ifname_data {
+       char *ifname;
+       bool found;
+};
+
+static void ifname_check_cb(int index, void *user_data)
+{
+       struct ifname_data *data = (struct ifname_data *)user_data;
+       char *ifname;
+
+       ifname = connman_inet_ifname(index);
+
+       if (!g_strcmp0(ifname, data->ifname))
+               data->found = true;
+}
+
+static char *get_ifname(void)
+{
+       struct ifname_data data;
+       int i;
+
+       for (i = 0; i < 256; i++) {
+               data.ifname = g_strdup_printf("wg%d", i);
+               data.found = false;
+               __vpn_ipconfig_foreach(ifname_check_cb, &data);
+
+               if (!data.found)
+                       return data.ifname;
+
+               g_free(data.ifname);
+       }
+
+       return NULL;
+}
+
+struct wireguard_info {
+       struct wg_device device;
+       struct wg_peer peer;
+};
+
+static int wg_connect(struct vpn_provider *provider,
+                       struct connman_task *task, const char *if_name,
+                       vpn_provider_connect_cb_t cb,
+                       const char *dbus_sender, void *user_data)
+{
+       struct wireguard_info *info;
+       struct connman_ipaddress *ipaddress;
+       const char *option;
+       char *gateway, *ifname;
+       int err;
+
+       info = g_malloc(sizeof(struct wireguard_info));
+       info->peer.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS;
+       info->device.flags = WGDEVICE_HAS_PRIVATE_KEY | 
WGDEVICE_HAS_LISTEN_PORT;
+       info->device.first_peer = &info->peer;
+       info->device.last_peer = &info->peer;
+
+       option = vpn_provider_get_string(provider, "WireGuard.ListPort");
+       if (option) {
+               char *end;
+               info->device.listen_port = g_ascii_strtoull(option, &end, 10);
+       }
+
+       option = vpn_provider_get_string(provider, "WireGuard.PrivateKey");
+       if (option) {
+               err = parse_key(option, info->device.private_key);
+               if (err)
+                       return -EINVAL;
+       }
+
+       option = vpn_provider_get_string(provider, "WireGuard.PublicKey");
+       if (option) {
+               err = parse_key(option, info->peer.public_key);
+               if (err)
+                       return -EINVAL;
+       }
+
+       option = vpn_provider_get_string(provider, "WireGuard.AllowedIPs");
+       if (option) {
+               err = parse_allowed_ips(option, &info->peer);
+               if (err)
+                       return -EINVAL;
+       }
+
+       gateway = NULL;
+       option = vpn_provider_get_string(provider, "Wireguard.Endpoint");
+       if (option) {
+               err = parse_endpoint(option, &info->peer, &gateway);
+               if (err) {
+                       g_free(gateway);
+                       return -EINVAL;
+               }
+       }
+
+       option = vpn_provider_get_string(provider, "WireGuard.Address");
+       if (option) {
+               err = parse_address(option, gateway, &ipaddress);
+               if (err) {
+                       g_free(gateway);
+                       return -EINVAL;
+               }
+       }
+       g_free(gateway);
+
+       ifname = get_ifname();
+       if (!ifname) {
+               DBG("Failed to find an usable device name");
+               err = -ENOENT;
+               goto done;
+       }
+       memcpy(info->device.name, ifname, MIN(strlen(ifname), IFNAMSIZ));
+       g_free(ifname);
+
+       err = wg_add_device(info->device.name);
+       if (err) {
+               DBG("Failed to creating wireguard device %s", 
info->device.name);
+               goto done;
+       }
+
+       err = wg_set_device(&info->device);
+       if (err) {
+               DBG("Failed to configure wireguard device %s", 
info->device.name);
+               wg_del_device(info->device.name);
+       }
+
+       vpn_provider_set_plugin_data(provider, info);
+       vpn_set_ifname(provider, info->device.name);
+       if (ipaddress) {
+               vpn_provider_set_ipaddress(provider, ipaddress);
+               connman_ipaddress_free(ipaddress);
+       }
+
+done:
+       if (cb)
+               cb(provider, user_data, err);
+
+       return 0;
+}
+
+static void wg_disconnect(struct vpn_provider *provider)
+{
+       struct wireguard_info *info;
+
+       info = vpn_provider_get_plugin_data(provider);
+       wg_del_device(info->device.name);
+
+       g_free(info);
+}
+
+static struct vpn_driver vpn_driver = {
+       .flags          = VPN_FLAG_NO_TUN | VPN_FLAG_NO_DAEMON,
+       .connect        = wg_connect,
+       .disconnect     = wg_disconnect,
+};
+
+static int wg_init(void)
+{
+       return vpn_register("wireguard", &vpn_driver, WIREGUARD);
+}
+
 static void wg_exit(void)
 {
+       vpn_unregister("wireguard");
 }
 
 CONNMAN_PLUGIN_DEFINE(wireguard, "WireGuard VPN plugin", VERSION,
-- 
2.20.1


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

Message: 4
Date: Fri, 19 Jul 2019 13:26:53 +0200
From: Daniel Wagner <[email protected]>
To: Daniel WANG <[email protected]>
Cc: "[email protected]" <[email protected]>
Subject: Re: question: enable two ethernet interfaces
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252; format=flowed

Hi,

> I observe that by default only eth0 can get IP address from DHCP server. 
> For eth1, IP is an APIPA address, as below:
> 
> *Question:*
> 
>  1. For the same type of ethernet interfaces, does connman only maintain
>     one interface, like eth0?

No, internally ConnMan is tracking all interfaces (unless blacklisted). 
The D-Bus API does not export device infos. So you only see Services 
which map to different interfaces.

>  2. Shall I use session API to enable another interface, like eth1? And
>     create another route table for eth1?

Should not be needed but it probably would work.

>  3. If yes, where can I find the user guide to use session API?

There is only our doc folder which contains all the written down 
information. Not really much I know :/

Thanks,
Daniel


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

Subject: Digest Footer

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


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

End of connman Digest, Vol 45, Issue 13
***************************************

Reply via email to