Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe 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 v1 04/11] vpn: Add provider only on success to hash table
(Daniel Wagner)
2. [PATCH v1 07/11] shared: Add Generic Netlink helpers for libmnl
(Daniel Wagner)
3. [PATCH v1 09/11] vpn: Introduce VPN_FLAG_NO_DAEMON (Daniel Wagner)
----------------------------------------------------------------------
Date: Tue, 5 Nov 2019 08:23:18 +0100
From: Daniel Wagner <[email protected]>
Subject: [PATCH v1 04/11] vpn: Add provider only on success to hash
table
To: [email protected]
Cc: Daniel Wagner <[email protected]>
Message-ID: <[email protected]>
Don't insert the provider before we call
__vpn_provider_create_from_config(). Because if the provider creation
fails we will double free all the values, first when we leave
load_provider() in the error path and later when the
config->provider_table hash table is destroyed.
---
vpn/vpn-config.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/vpn/vpn-config.c b/vpn/vpn-config.c
index c88a99abb2c7..f56e51ee463a 100644
--- a/vpn/vpn-config.c
+++ b/vpn/vpn-config.c
@@ -261,9 +261,6 @@ static int load_provider(GKeyFile *keyfile, const char
*group,
config_provider->config_entry = g_strdup_printf("provider_%s",
config_provider->ident);
- g_hash_table_insert(config->provider_table,
- config_provider->ident, config_provider);
-
err = __vpn_provider_create_from_config(
config_provider->setting_strings,
config_provider->config_ident,
@@ -274,6 +271,10 @@ static int load_provider(GKeyFile *keyfile, const char
*group,
goto err;
}
+ g_hash_table_insert(config->provider_table, config_provider->ident,
+ config_provider);
+
+
connman_info("Added provider configuration %s",
config_provider->ident);
return 0;
--
2.23.0
------------------------------
Date: Tue, 5 Nov 2019 08:23:21 +0100
From: Daniel Wagner <[email protected]>
Subject: [PATCH v1 07/11] shared: Add Generic Netlink helpers for
libmnl
To: [email protected]
Cc: Daniel Wagner <[email protected]>
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.23.0
------------------------------
Date: Tue, 5 Nov 2019 08:23:23 +0100
From: Daniel Wagner <[email protected]>
Subject: [PATCH v1 09/11] vpn: Introduce VPN_FLAG_NO_DAEMON
To: [email protected]
Cc: Daniel Wagner <[email protected]>
Message-ID: <[email protected]>
Add VPN_FLAG_NO_DAEMON to skip forking and monitoring an external
task. Since the state machine inside vpn.c is driven by the external
events we need to fake the event via update_provider_state(). We can't
directly progress the state machine because we are still processing an
D-Bus message after calling vpn_driver->connect(). So defer the call
to update_provider_state via the idle loop.
---
vpn/plugins/vpn.c | 51 +++++++++++++++++++++++++++++++++++++++++++----
vpn/plugins/vpn.h | 3 ++-
2 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index eef8550e6a9c..96a06299be09 100644
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -89,7 +89,7 @@ static int stop_vpn(struct vpn_provider *provider)
vpn_driver_data = g_hash_table_lookup(driver_hash, name);
if (vpn_driver_data && vpn_driver_data->vpn_driver &&
- vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
+ vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN)
return 0;
memset(&ifr, 0, sizeof(ifr));
@@ -540,6 +540,27 @@ static void vpn_task_setup(gpointer user_data)
connman_error("error setting uid %d %s", uid, strerror(errno));
}
+
+static gboolean update_provider_state(gpointer data)
+{
+ struct vpn_provider *provider = data;
+ struct vpn_data *vpn_data;
+ int index;
+
+ DBG("");
+
+ vpn_data = vpn_provider_get_data(provider);
+
+ index = vpn_provider_get_index(provider);
+ DBG("index to watch %d", index);
+ vpn_provider_ref(provider);
+ vpn_data->watch = vpn_rtnl_add_newlink_watch(index,
+ vpn_newlink, provider);
+ connman_inet_ifup(index);
+
+ return FALSE;
+}
+
static int vpn_connect(struct vpn_provider *provider,
vpn_provider_connect_cb_t cb,
const char *dbus_sender, void *user_data)
@@ -595,7 +616,7 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
- if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
+ if (!(vpn_driver_data->vpn_driver->flags & VPN_FLAG_NO_TUN)) {
if (vpn_driver_data->vpn_driver->device_flags) {
tun_flags =
vpn_driver_data->vpn_driver->device_flags(provider);
}
@@ -604,6 +625,26 @@ static int vpn_connect(struct vpn_provider *provider,
goto exist_err;
}
+
+ if (vpn_driver_data && vpn_driver_data->vpn_driver &&
+ vpn_driver_data->vpn_driver->flags &
VPN_FLAG_NO_DAEMON) {
+
+ ret = vpn_driver_data->vpn_driver->connect(provider,
+ NULL, NULL, NULL, NULL, NULL);
+ if (ret) {
+ stop_vpn(provider);
+ goto exist_err;
+ }
+
+ DBG("%s started with dev %s",
+ vpn_driver_data->provider_driver.name, data->if_name);
+
+ data->state = VPN_STATE_CONNECT;
+
+ g_timeout_add(1, update_provider_state, provider);
+ return -EINPROGRESS;
+ }
+
vpn_plugin_data =
vpn_settings_get_vpn_plugin_config(vpn_driver_data->name);
data->task = connman_task_create(vpn_driver_data->program,
@@ -689,7 +730,8 @@ static int vpn_disconnect(struct vpn_provider *provider)
vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT);
}
- connman_task_stop(data->task);
+ if (data->task)
+ connman_task_stop(data->task);
return 0;
}
@@ -713,7 +755,8 @@ static int vpn_remove(struct vpn_provider *provider)
data->watch = 0;
}
- connman_task_stop(data->task);
+ if (data->task)
+ connman_task_stop(data->task);
g_usleep(G_USEC_PER_SEC);
stop_vpn(provider);
diff --git a/vpn/plugins/vpn.h b/vpn/plugins/vpn.h
index 265fd82f62e4..71e04f618fd2 100644
--- a/vpn/plugins/vpn.h
+++ b/vpn/plugins/vpn.h
@@ -28,7 +28,8 @@
extern "C" {
#endif
-#define VPN_FLAG_NO_TUN 1
+#define VPN_FLAG_NO_TUN 1
+#define VPN_FLAG_NO_DAEMON 2
enum vpn_state {
VPN_STATE_UNKNOWN = 0,
--
2.23.0
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list -- [email protected]
To unsubscribe send an email to [email protected]
------------------------------
End of connman Digest, Vol 49, Issue 4
**************************************