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
***************************************