Re: [PATCH 4/4] session: Use subnet route creation and deletion APIs
by Daniel Wagner
Hi Jian,
On 10/05/2017 12:34 PM, Jian Liang wrote:
> From: Jian Liang <jianliang(a)tycoint.com>
>
> Subnet route needs to be create after the default route in order to have
> the gateway information ready. It needs to be deleted before default route
> to the gateway is deleted for the same reason.
>
> Signed-off-by: Jian Liang <jianliang(a)tycoint.com>
Not needed
> ---
> src/session.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/src/session.c b/src/session.c
> index 965ac06..e43411e 100644
> --- a/src/session.c
> +++ b/src/session.c
> @@ -367,6 +367,24 @@ static void del_default_route(struct connman_session *session)
> session->index = -1;
> }
>
> +static void del_default_subnet_route(struct connman_session *session)
> +{
> + struct connman_ipconfig *ipconfig;
> +
> + if (!session->gateway)
> + return;
> +
> + ipconfig = __connman_service_get_ip4config(session->service);
> +
> + DBG("index %d routing table %d default gateway %s prefixlen %u",
> + session->index, session->mark, session->gateway,
> + __connman_ipconfig_get_prefixlen(ipconfig));
> +
> + __connman_inet_del_subnet_from_table(session->mark,
> + session->index, session->gateway,
> + __connman_ipconfig_get_prefixlen(ipconfig));
Please move the __connman_inet_del_subnet_from_table call into the
del_default_route() function. We are going to call both function
back-to-back and there is much code in common.
> +}
> +
> static void add_default_route(struct connman_session *session)
> {
> struct connman_ipconfig *ipconfig;
> @@ -392,6 +410,33 @@ static void add_default_route(struct connman_session *session)
> DBG("session %p %s", session, strerror(-err));
> }
>
> +static void add_default_subnet_route(struct connman_session *session)
> +{
> + struct connman_ipconfig *ipconfig;
> + int err;
> + struct in_addr addr = { INADDR_ANY };
> +
> + if (!session->service)
> + return;
> +
> + ipconfig = __connman_service_get_ip4config(session->service);
> + 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 prefixlen %u",
> + session->index, session->mark, session->gateway,
> + __connman_ipconfig_get_prefixlen(ipconfig));
What about "gateway %s/%u" ?
> +
> + err = __connman_inet_add_subnet_to_table(session->mark,
> + session->index, session->gateway,
> + __connman_ipconfig_get_prefixlen(ipconfig));
Same here. Just move it to add_default_route().
> + if (err < 0)
> + DBG("session add subnet route %p %s", session, strerror(-err));
> +}
> +
> static void del_nat_rules(struct connman_session *session)
> {
> struct fw_snat *fw_snat;
> @@ -464,6 +509,7 @@ static void cleanup_routing_table(struct connman_session *session)
> session->policy_routing = false;
> }
>
> + del_default_subnet_route(session);
> del_default_route(session);
> }
>
> @@ -478,6 +524,7 @@ static void update_routing_table(struct connman_session *session)
> cleanup_routing_table(session);
> init_routing_table(session);
> add_default_route(session);
> + add_default_subnet_route(session);
> }
>
> static void cleanup_nat_rules(struct connman_session *session)
>
Thanks,
Daniel
3 years, 3 months
Re: [PATCH 2/4] inet: Implement subnet route creation/deletion in iproute_default_modify
by Daniel Wagner
Hi Jian,
On 10/05/2017 12:34 PM, Jian Liang wrote:
> From: Jian Liang <jianliang(a)tycoint.com>
>
> - Calculate subnet address base on gateway address and prefixlen
> - Differentiate creation of routes to gateway and subnet
>
> Signed-off-by: Jian Liang <jianliang(a)tycoint.com>
We don't do the SoB in this project.
> ---
> src/inet.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/src/inet.c b/src/inet.c
> index ab8aec8..dc8a97f 100644
> --- a/src/inet.c
> +++ b/src/inet.c
> @@ -2802,6 +2802,9 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
> unsigned char buf[sizeof(struct in6_addr)];
> int ret, len;
> int family = connman_inet_check_ipaddress(gateway);
> + char *dst = NULL;
> +
> + DBG("gateway %s prefixlen %u table %u", gateway, prefixlen, table_id);
What about "gateway %/%u" ?
>
> switch (family) {
> case AF_INET:
> @@ -2814,7 +2817,20 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
> return -EINVAL;
> }
>
> - ret = inet_pton(family, gateway, buf);
> + if (prefixlen) {
> + struct in_addr ipv4_subnet_addr, ipv4_mask;
> +
> + memset(&ipv4_subnet_addr, 0, sizeof(ipv4_subnet_addr));
> + ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
> + ipv4_subnet_addr.s_addr = inet_addr(gateway);
> + ipv4_subnet_addr.s_addr &= ipv4_mask.s_addr;
> +
> + DBG("subnet %s", inet_ntoa(ipv4_subnet_addr));
Is this DBG() really helpful? It looks like a low level debug statement.
> + dst = g_strdup(inet_ntoa(ipv4_subnet_addr));
> + }
> +
> + ret = inet_pton(family, dst ? dst : gateway, buf);
> + g_free(dst);
> if (ret <= 0)
> return -EINVAL;
>
> @@ -2831,8 +2847,9 @@ static int iproute_default_modify(int cmd, uint32_t table_id, int ifindex,
> rth.req.u.r.rt.rtm_type = RTN_UNICAST;
> rth.req.u.r.rt.rtm_dst_len = prefixlen;
>
> - __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req), RTA_GATEWAY,
> - buf, len);
> + __connman_inet_rtnl_addattr_l(&rth.req.n, sizeof(rth.req),
> + prefixlen > 0 ? RTA_DST : RTA_GATEWAY, buf, len);
> +
> if (table_id < 256) {
> rth.req.u.r.rt.rtm_table = table_id;
> } else {
>
Thanks,
Daniel
3 years, 3 months
[PATCH] session: Add ContextIdentifier
by Daniel Wagner
From: Bjoern Thorwirth <external.bjoern.thorwirth(a)de.bosch.com>
The calling process, that implements the session API is identified by
the user ID as it is runs. All processes of the same user share the
same list of allowed bearers, and the same priority for choosing
between available bearers.
This extension allows processes to select a service context dependent
behaviour for which the routing decision is made.
This is an extention to session API interface. Helps to enable a
service differentiation for processes run by the same user. Allows
ConnMan to differentiate between bearer usage permissions and the
respective priorities based on the requested service type.
---
Hi,
after an offline discussion with Bjorn, we came to the conclusion that
my idea with AllowedServices is going into the wrong
direction. At least for his use case.
Propably I got confused by the name 'Session'. By calling this
ContextIdentifier we should avoid this confusion. In the end it is
just an additonal information given by the application to support the
bearer selection algorithm. Currently, the session code in ConnMan
doesn't make use of it, but a session plugin can use it. That is what
Bjorn does.
Thanks,
Daniel
doc/session-api.txt | 11 +++++++++++
include/session.h | 1 +
src/session.c | 17 +++++++++++++++++
3 files changed, 29 insertions(+)
diff --git a/doc/session-api.txt b/doc/session-api.txt
index e8da5224dbf7..46ac5f3dc94a 100644
--- a/doc/session-api.txt
+++ b/doc/session-api.txt
@@ -205,3 +205,14 @@ Settings string State [readonly]
a default route. When the source IP rule is enabled,
an application can select which session/interface to
send traffic on, using bind-before-connect mechanism.
+
+ string ContextIdentifier [readwrite] [experimental]
+
+ The application can provide an identifier for a
+ session. If an application runs several session
+ at the same time, the additional information
+ can be used by ConnMan to assign different
+ bearers according the identifier. For example
+ a web browser creates per tab a session. For
+ each session a different should bearer be
+ assigned.
diff --git a/include/session.h b/include/session.h
index 5106e886b9ab..39f3368554ed 100644
--- a/include/session.h
+++ b/include/session.h
@@ -74,6 +74,7 @@ struct connman_session_config {
GSList *allowed_bearers;
char *allowed_interface;
bool source_ip_rule;
+ char *context_identifier;
};
typedef int (* connman_session_config_func_t) (struct connman_session *session,
diff --git a/src/session.c b/src/session.c
index 9e3c55941ee6..108228a820a7 100644
--- a/src/session.c
+++ b/src/session.c
@@ -548,6 +548,7 @@ struct creation_data {
GSList *allowed_bearers;
char *allowed_interface;
bool source_ip_rule;
+ char *context_identifier;
};
static void cleanup_creation_data(struct creation_data *creation_data)
@@ -557,6 +558,8 @@ static void cleanup_creation_data(struct creation_data *creation_data)
if (creation_data->pending)
dbus_message_unref(creation_data->pending);
+ if (creation_data->context_identifier)
+ g_free(creation_data->context_identifier);
g_slist_free(creation_data->allowed_bearers);
g_free(creation_data->allowed_interface);
@@ -927,6 +930,17 @@ static void append_notify(DBusMessageIter *dict,
}
if (session->append_all ||
+ info->config.context_identifier != info_last->config.context_identifier) {
+ char *ifname = info->config.context_identifier;
+ if (!ifname)
+ ifname = "";
+ connman_dbus_dict_append_basic(dict, "Context_Identifier",
+ DBUS_TYPE_STRING,
+ &ifname);
+ info_last->config.context_identifier = info->config.context_identifier;
+ }
+
+ if (session->append_all ||
info->config.source_ip_rule != info_last->config.source_ip_rule) {
dbus_bool_t source_ip_rule = FALSE;
if (info->config.source_ip_rule)
@@ -1474,6 +1488,9 @@ int __connman_session_create(DBusMessage *msg)
connman_session_parse_connection_type(val);
user_connection_type = true;
+ } else if (g_str_equal(key, "ContextIdentifier")) {
+ dbus_message_iter_get_basic(&value, &val);
+ creation_data->context_identifier = g_strdup(val);
} else if (g_str_equal(key, "AllowedInterface")) {
dbus_message_iter_get_basic(&value, &val);
creation_data->allowed_interface = g_strdup(val);
--
2.9.5
3 years, 3 months
[PATCH 1/2] dns: support for systemd-resolved and backend selection.
by Ismo Puustinen
During configure, use --with-dns-backend to declare which DNS backend
you want to use during build. The two options available are "internal"
and "systemd-resolved".
The internal backend works as previously. The systemd-resolved backend
configures systemd-resolved over D-Bus.
The "-r" command line option for connmand still works. It means that the
DNS servers (either internal DNS proxy or systemd-resolved) aren't used,
and instead connmand just updates /etc/resolv.conf file.
---
Makefile.am | 15 +-
configure.ac | 14 ++
src/dns-systemd-resolved.c | 378 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 405 insertions(+), 2 deletions(-)
create mode 100644 src/dns-systemd-resolved.c
diff --git a/Makefile.am b/Makefile.am
index e67a7a55..97f1c87d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -120,11 +120,18 @@ src_connmand_SOURCES = $(gdhcp_sources) $(gweb_sources) $(backtrace_sources) \
src/storage.c src/dbus.c src/config.c \
src/technology.c src/counter.c src/ntp.c \
src/session.c src/tethering.c src/wpad.c src/wispr.c \
- src/stats.c src/dnsproxy.c src/6to4.c \
+ src/stats.c src/6to4.c \
src/ippool.c src/bridge.c src/nat.c src/ipaddress.c \
src/inotify.c src/ipv6pd.c src/peer.c \
src/peer_service.c src/machine.c src/util.c
+if INTERNAL_DNS_BACKEND
+src_connmand_SOURCES += src/dnsproxy.c
+endif
+if SYSTEMD_RESOLVED_DNS_BACKEND
+src_connmand_SOURCES += src/dns-systemd-resolved.c
+endif
+
src_connmand_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ \
-lresolv -ldl -lrt
@@ -178,7 +185,11 @@ vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \
endif
BUILT_SOURCES = $(local_headers) src/builtin.h $(service_files) \
- scripts/connman scripts/connman_resolvconf.conf
+ scripts/connman
+
+if INTERNAL_DNS_BACKEND
+BUILT_SOURCES += scripts/connman_resolvconf.conf
+endif
if VPN
BUILT_SOURCES += vpn/builtin.h
diff --git a/configure.ac b/configure.ac
index 4baa6852..4feccc08 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,4 +433,18 @@ AM_CONDITIONAL(VPN, test "${enable_openconnect}" != "no" -o \
"${enable_l2tp}" != "no" -o \
"${enable_pptp}" != "no")
+AC_MSG_CHECKING(which DNS backend to use)
+AC_ARG_WITH(dns-backend, AC_HELP_STRING([--with-dns-backend=TYPE],
+ [specify which DNS backend to use: internal or systemd-resolved [default=internal]]),
+ [dns_backend=${withval}],
+ [dns_backend="internal"])
+
+if (test "${dns_backend}" != "internal" -a \
+ "${dns_backend}" != "systemd-resolved"); then
+ AC_MSG_ERROR(no suitable DNS backend defined)
+fi
+AM_CONDITIONAL(INTERNAL_DNS_BACKEND, test "${dns_backend}" = "internal")
+AM_CONDITIONAL(SYSTEMD_RESOLVED_DNS_BACKEND, test "${dns_backend}" = "systemd-resolved")
+AC_MSG_RESULT(${dns_backend})
+
AC_OUTPUT(Makefile include/version.h connman.pc)
diff --git a/src/dns-systemd-resolved.c b/src/dns-systemd-resolved.c
new file mode 100644
index 00000000..3cb752e6
--- /dev/null
+++ b/src/dns-systemd-resolved.c
@@ -0,0 +1,378 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <gdbus.h>
+#include <glib.h>
+#include <connman/dbus.h>
+
+#include "connman.h"
+
+#define SYSTEMD_RESOLVED_SERVICE "org.freedesktop.resolve1"
+#define SYSTEMD_RESOLVED_PATH "/org/freedesktop/resolve1"
+
+static GTree *interface_map = NULL;
+static DBusConnection *connection = NULL;
+static GDBusClient *client = NULL;
+static GDBusProxy *resolved_proxy = NULL;
+
+struct dns_interface {
+ GList *domains;
+ GList *servers;
+ int index;
+};
+
+static gint int_cmp(gconstpointer a, gconstpointer b, void *data)
+{
+ gint ai = GPOINTER_TO_UINT(a);
+ gint bi = GPOINTER_TO_UINT(b);
+
+ return ai - bi;
+}
+
+static void free_dns_interface(gpointer data)
+{
+ struct dns_interface *iface = data;
+
+ DBG("%p", data);
+
+ if (!iface)
+ return;
+
+ g_list_free_full(iface->domains, free);
+ g_list_free_full(iface->servers, free);
+
+ free(iface);
+}
+
+static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ int result;
+ unsigned int i;
+ int type;
+ char ipv4_bytes[4];
+ char ipv6_bytes[16];
+ GList *list;
+ DBusMessageIter address_array, struct_array, byte_array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(iay)",
+ &address_array);
+
+ for (list = iface->servers; list; list = g_list_next(list)) {
+ char *server = list->data;
+
+ DBG("index: %d, server: %s", iface->index, server);
+
+ dbus_message_iter_open_container(&address_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ type = connman_inet_check_ipaddress(server);
+
+ if (type == AF_INET) {
+
+ result = inet_pton(type, server, ipv4_bytes);
+
+ if (!result) {
+ DBG("Failed to parse IPv4 address: %s",
+ server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv4_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv4_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ } else if (type == AF_INET6) {
+
+ result = inet_pton(type, server, ipv6_bytes);
+
+ if (!result) {
+ DBG("Failed to parse IPv6 address: %s",
+ server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv6_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv6_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ }
+
+ dbus_message_iter_close_container(&address_array,
+ &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &address_array);
+}
+
+static void setlinkdomains_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ GList *list;
+ DBusMessageIter domain_array, struct_array;
+ gboolean only_routing = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(sb)",
+ &domain_array);
+
+ for (list = iface->domains; list; list = g_list_next(list)) {
+ char *domain = list->data;
+
+ DBG("index: %d, domain: %s", iface->index, domain);
+
+ dbus_message_iter_open_container(&domain_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_STRING,
+ &domain);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_BOOLEAN,
+ &only_routing);
+
+ dbus_message_iter_close_container(&domain_array, &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &domain_array);
+}
+
+static int set_systemd_resolved_values(struct dns_interface *iface)
+{
+ if (!resolved_proxy || !iface)
+ return -ENOENT;
+
+ /* No async error processing -- just fire and forget */
+
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDNS",
+ setlinkdns_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDomains",
+ setlinkdomains_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void remove_values(struct dns_interface *iface, const char *domain,
+ const char *server)
+{
+ if (!iface)
+ return;
+
+ if (domain)
+ iface->domains = g_list_remove(iface->domains, domain);
+
+ if (server)
+ iface->servers = g_list_remove(iface->servers, server);
+}
+
+static bool is_empty(struct dns_interface *iface)
+{
+ if (!iface)
+ return FALSE;
+
+ return (!iface->domains && !iface->servers);
+}
+
+int __connman_dnsproxy_remove(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+ int ret = 0;
+
+ DBG("");
+
+ if (!interface_map || index < 0)
+ return -EINVAL;
+
+ iface = g_tree_lookup(interface_map, GUINT_TO_POINTER(index));
+
+ if (!iface)
+ return -EINVAL;
+
+ remove_values(iface, domain, server);
+
+ ret = set_systemd_resolved_values(iface);
+
+ if (is_empty(iface))
+ g_tree_remove(interface_map, GUINT_TO_POINTER(index));
+
+ /* freed during g_tree_remove */
+ iface = NULL;
+
+ return ret;
+}
+
+static GList *replace_to_end(GList *str_list, const char *str)
+{
+ GList *list;
+
+ for (list = str_list; list; list = g_list_next(list)) {
+ char *orig = list->data;
+
+ if (strcmp(orig, str) == 0) {
+ str_list = g_list_remove(str_list, orig);
+ free(orig);
+ break;
+ }
+ }
+
+ return g_list_append(str_list, strdup(str));
+}
+
+int __connman_dnsproxy_append(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+
+ DBG("");
+
+ if (!interface_map || index < 0)
+ return -EINVAL;
+
+ iface = g_tree_lookup(interface_map, GUINT_TO_POINTER(index));
+
+ if (!iface) {
+ iface = g_new0(struct dns_interface, 1);
+ if (!iface)
+ return -ENOMEM;
+ g_tree_insert(interface_map, GUINT_TO_POINTER(index), iface);
+ }
+
+ if (domain)
+ iface->domains = replace_to_end(iface->domains, domain);
+
+ if (server)
+ iface->servers = replace_to_end(iface->servers, server);
+
+ iface->index = index;
+
+ return set_systemd_resolved_values(iface);
+}
+
+int __connman_dnsproxy_add_listener(int index)
+{
+ DBG("");
+
+ return -ENXIO;
+}
+
+void __connman_dnsproxy_remove_listener(int index)
+{
+ DBG("");
+}
+
+static int setup_resolved(void)
+{
+ connection = connman_dbus_get_connection();
+
+ if (!connection)
+ return -ENXIO;
+
+ client = g_dbus_client_new(connection, SYSTEMD_RESOLVED_SERVICE,
+ SYSTEMD_RESOLVED_PATH);
+
+ if (!client)
+ return -EINVAL;
+
+ resolved_proxy = g_dbus_proxy_new(client, SYSTEMD_RESOLVED_PATH,
+ "org.freedesktop.resolve1.Manager");
+
+ if (!resolved_proxy)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_dnsproxy_init(void)
+{
+ int ret;
+
+ DBG("");
+
+ if ((ret = setup_resolved()) < 0)
+ return ret;
+
+ interface_map = g_tree_new_full(int_cmp, NULL, NULL,
+ free_dns_interface);
+
+ if (!interface_map)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __connman_dnsproxy_cleanup(void)
+{
+ DBG("");
+
+ if (interface_map) {
+ g_tree_destroy(interface_map);
+ interface_map = NULL;
+ }
+
+ if (resolved_proxy) {
+ g_dbus_proxy_unref(resolved_proxy);
+ resolved_proxy = NULL;
+ }
+
+ if (client) {
+ g_dbus_client_unref(client);
+ client = NULL;
+ }
+
+ if (connection) {
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
+}
--
2.13.6
3 years, 3 months
[PATCH v2 1/2] dns: support for systemd-resolved and backend selection.
by Ismo Puustinen
During configure, use --with-dns-backend to declare which DNS backend
you want to use during build. The two options available are "internal"
and "systemd-resolved".
The internal backend works as previously. The systemd-resolved backend
configures systemd-resolved over D-Bus.
The "-r" command line option for connmand still works. It means that the
DNS servers (either internal DNS proxy or systemd-resolved) aren't used,
and instead connmand just updates /etc/resolv.conf file.
---
Makefile.am | 15 +-
configure.ac | 14 ++
src/dns-systemd-resolved.c | 454 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 481 insertions(+), 2 deletions(-)
create mode 100644 src/dns-systemd-resolved.c
diff --git a/Makefile.am b/Makefile.am
index e67a7a55..97f1c87d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -120,11 +120,18 @@ src_connmand_SOURCES = $(gdhcp_sources) $(gweb_sources) $(backtrace_sources) \
src/storage.c src/dbus.c src/config.c \
src/technology.c src/counter.c src/ntp.c \
src/session.c src/tethering.c src/wpad.c src/wispr.c \
- src/stats.c src/dnsproxy.c src/6to4.c \
+ src/stats.c src/6to4.c \
src/ippool.c src/bridge.c src/nat.c src/ipaddress.c \
src/inotify.c src/ipv6pd.c src/peer.c \
src/peer_service.c src/machine.c src/util.c
+if INTERNAL_DNS_BACKEND
+src_connmand_SOURCES += src/dnsproxy.c
+endif
+if SYSTEMD_RESOLVED_DNS_BACKEND
+src_connmand_SOURCES += src/dns-systemd-resolved.c
+endif
+
src_connmand_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ \
-lresolv -ldl -lrt
@@ -178,7 +185,11 @@ vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \
endif
BUILT_SOURCES = $(local_headers) src/builtin.h $(service_files) \
- scripts/connman scripts/connman_resolvconf.conf
+ scripts/connman
+
+if INTERNAL_DNS_BACKEND
+BUILT_SOURCES += scripts/connman_resolvconf.conf
+endif
if VPN
BUILT_SOURCES += vpn/builtin.h
diff --git a/configure.ac b/configure.ac
index 4baa6852..4feccc08 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,4 +433,18 @@ AM_CONDITIONAL(VPN, test "${enable_openconnect}" != "no" -o \
"${enable_l2tp}" != "no" -o \
"${enable_pptp}" != "no")
+AC_MSG_CHECKING(which DNS backend to use)
+AC_ARG_WITH(dns-backend, AC_HELP_STRING([--with-dns-backend=TYPE],
+ [specify which DNS backend to use: internal or systemd-resolved [default=internal]]),
+ [dns_backend=${withval}],
+ [dns_backend="internal"])
+
+if (test "${dns_backend}" != "internal" -a \
+ "${dns_backend}" != "systemd-resolved"); then
+ AC_MSG_ERROR(no suitable DNS backend defined)
+fi
+AM_CONDITIONAL(INTERNAL_DNS_BACKEND, test "${dns_backend}" = "internal")
+AM_CONDITIONAL(SYSTEMD_RESOLVED_DNS_BACKEND, test "${dns_backend}" = "systemd-resolved")
+AC_MSG_RESULT(${dns_backend})
+
AC_OUTPUT(Makefile include/version.h connman.pc)
diff --git a/src/dns-systemd-resolved.c b/src/dns-systemd-resolved.c
new file mode 100644
index 00000000..a7d9c6d8
--- /dev/null
+++ b/src/dns-systemd-resolved.c
@@ -0,0 +1,454 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <gdbus.h>
+#include <glib.h>
+#include <connman/dbus.h>
+
+#include "connman.h"
+
+#define SYSTEMD_RESOLVED_SERVICE "org.freedesktop.resolve1"
+#define SYSTEMD_RESOLVED_PATH "/org/freedesktop/resolve1"
+
+static GTree *interface_map = NULL;
+static DBusConnection *connection = NULL;
+static GDBusClient *client = NULL;
+static GDBusProxy *resolved_proxy = NULL;
+
+/* update after a full set of instructions has been received */
+static guint update_interfaces_source = 0;
+
+struct dns_interface {
+ GList *domains;
+ GList *servers;
+ int index;
+ bool needs_domain_update;
+ bool needs_server_update;
+};
+
+static gint int_cmp(gconstpointer a, gconstpointer b, void *data)
+{
+ gint ai = GPOINTER_TO_UINT(a);
+ gint bi = GPOINTER_TO_UINT(b);
+
+ return ai - bi;
+}
+
+static void free_dns_interface(gpointer data)
+{
+ struct dns_interface *iface = data;
+
+ if (!iface)
+ return;
+
+ g_list_free_full(iface->domains, g_free);
+ g_list_free_full(iface->servers, g_free);
+
+ g_free(iface);
+}
+
+static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ int result;
+ unsigned int i;
+ int type;
+ char ipv4_bytes[4];
+ char ipv6_bytes[16];
+ GList *list;
+ DBusMessageIter address_array, struct_array, byte_array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(iay)",
+ &address_array);
+
+ for (list = iface->servers; list; list = g_list_next(list)) {
+ char *server = list->data;
+
+ DBG("index: %d, server: %s", iface->index, server);
+
+ dbus_message_iter_open_container(&address_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ type = connman_inet_check_ipaddress(server);
+
+ if (type == AF_INET) {
+ result = inet_pton(type, server, ipv4_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv4 address: %s",
+ server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv4_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv4_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ } else if (type == AF_INET6) {
+ result = inet_pton(type, server, ipv6_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv6 address: %s",
+ server);
+ return;
+ }
+
+ dbus_message_iter_append_basic(&struct_array,
+ DBUS_TYPE_INT32, &type);
+
+ dbus_message_iter_open_container(&struct_array,
+ DBUS_TYPE_ARRAY, "y", &byte_array);
+
+ for (i = 0; i < sizeof(ipv6_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array,
+ DBUS_TYPE_BYTE,
+ &(ipv6_bytes[i]));
+ }
+
+ dbus_message_iter_close_container(&struct_array,
+ &byte_array);
+ }
+
+ dbus_message_iter_close_container(&address_array,
+ &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &address_array);
+}
+
+static void setlinkdomains_append(DBusMessageIter *iter, void *user_data)
+{
+ struct dns_interface *iface = user_data;
+ GList *list;
+ DBusMessageIter domain_array, struct_array;
+ gboolean only_routing = FALSE;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &iface->index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(sb)",
+ &domain_array);
+
+ for (list = iface->domains; list; list = g_list_next(list)) {
+ char *domain = list->data;
+
+ DBG("index: %d, domain: %s", iface->index, domain);
+
+ dbus_message_iter_open_container(&domain_array,
+ DBUS_TYPE_STRUCT, NULL, &struct_array);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_STRING,
+ &domain);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_BOOLEAN,
+ &only_routing);
+
+ dbus_message_iter_close_container(&domain_array, &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &domain_array);
+}
+
+static int set_systemd_resolved_values(struct dns_interface *iface)
+{
+ if (!resolved_proxy || !iface)
+ return -ENOENT;
+
+ /* No async error processing -- just fire and forget */
+
+ if (iface->needs_server_update) {
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDNS",
+ setlinkdns_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ iface->needs_server_update = FALSE;
+ }
+
+ if (iface->needs_domain_update) {
+ if (!g_dbus_proxy_method_call(resolved_proxy, "SetLinkDomains",
+ setlinkdomains_append, NULL, iface, NULL))
+ return -EINVAL;
+
+ iface->needs_domain_update = FALSE;
+ }
+
+ return 0;
+}
+
+static bool is_empty(struct dns_interface *iface)
+{
+ if (!iface)
+ return FALSE;
+
+ return (!iface->domains && !iface->servers);
+}
+
+static gboolean update_interface(gpointer key, gpointer value, gpointer data)
+{
+ struct dns_interface *iface = value;
+ GList **removed_items = data;
+
+ set_systemd_resolved_values(iface);
+
+ if (is_empty(iface))
+ *removed_items = g_list_prepend(*removed_items, iface);
+
+ /* don't stop the tree traversal */
+ return FALSE;
+}
+
+static int update_systemd_resolved(gpointer data)
+{
+ GList *removed_items = NULL, *list;
+
+ if (!interface_map) {
+ DBG("no interface map when updating");
+ return G_SOURCE_REMOVE;
+ }
+
+ g_tree_foreach(interface_map, update_interface, &removed_items);
+
+ for (list = removed_items; list; list = g_list_next(list)) {
+ struct dns_interface *iface = list->data;
+ g_tree_remove(interface_map, GUINT_TO_POINTER(iface->index));
+ }
+
+ g_list_free(removed_items);
+
+ update_interfaces_source = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static GList *remove_string(GList *str_list, const char *str)
+{
+ GList *match = NULL;
+
+ match = g_list_find_custom(str_list, str,
+ (GCompareFunc) g_strcmp0);
+
+ if (match) {
+ g_free(match->data);
+ return g_list_delete_link(str_list, match);
+ }
+
+ return str_list;
+}
+
+static void remove_values(struct dns_interface *iface, const char *domain,
+ const char *server)
+{
+ if (!iface)
+ return;
+
+ if (domain) {
+ iface->domains = remove_string(iface->domains, domain);
+ iface->needs_domain_update = TRUE;
+ }
+
+ if (server) {
+ iface->servers = remove_string(iface->servers, server);
+ iface->needs_server_update = TRUE;
+ }
+}
+
+int __connman_dnsproxy_remove(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+
+ DBG("%d, %s, %s", index, domain ? domain : "no domain",
+ server ? server : "no server");
+
+ if (!interface_map || index < 0)
+ return -EINVAL;
+
+ iface = g_tree_lookup(interface_map, GUINT_TO_POINTER(index));
+
+ if (!iface)
+ return -EINVAL;
+
+ remove_values(iface, domain, server);
+
+ if (!update_interfaces_source)
+ update_interfaces_source = g_idle_add(update_systemd_resolved,
+ NULL);
+
+ return 0;
+}
+
+static GList *replace_to_end(GList *str_list, const char *str)
+{
+ GList *list;
+
+ for (list = str_list; list; list = g_list_next(list)) {
+ char *orig = list->data;
+
+ if (g_strcmp0(orig, str) == 0) {
+ str_list = g_list_remove(str_list, orig);
+ g_free(orig);
+ break;
+ }
+ }
+
+ return g_list_append(str_list, g_strdup(str));
+}
+
+int __connman_dnsproxy_append(int index, const char *domain,
+ const char *server)
+{
+ struct dns_interface *iface;
+
+ DBG("%d, %s, %s", index, domain ? domain : "no domain",
+ server ? server : "no server");
+
+ if (!interface_map || index < 0)
+ return -EINVAL;
+
+ iface = g_tree_lookup(interface_map, GUINT_TO_POINTER(index));
+
+ if (!iface) {
+ iface = g_new0(struct dns_interface, 1);
+ if (!iface)
+ return -ENOMEM;
+
+ iface->index = index;
+ g_tree_insert(interface_map, GUINT_TO_POINTER(index), iface);
+ }
+
+ if (domain) {
+ iface->domains = replace_to_end(iface->domains, domain);
+ iface->needs_domain_update = TRUE;
+ }
+
+ if (server) {
+ iface->servers = replace_to_end(iface->servers, server);
+ iface->needs_server_update = TRUE;
+ }
+
+ if (!update_interfaces_source)
+ update_interfaces_source = g_idle_add(update_systemd_resolved,
+ NULL);
+
+ return 0;
+}
+
+int __connman_dnsproxy_add_listener(int index)
+{
+ DBG("");
+
+ return -ENXIO;
+}
+
+void __connman_dnsproxy_remove_listener(int index)
+{
+ DBG("");
+}
+
+static int setup_resolved(void)
+{
+ connection = connman_dbus_get_connection();
+
+ if (!connection)
+ return -ENXIO;
+
+ client = g_dbus_client_new(connection, SYSTEMD_RESOLVED_SERVICE,
+ SYSTEMD_RESOLVED_PATH);
+
+ if (!client)
+ return -EINVAL;
+
+ resolved_proxy = g_dbus_proxy_new(client, SYSTEMD_RESOLVED_PATH,
+ "org.freedesktop.resolve1.Manager");
+
+ if (!resolved_proxy)
+ return -EINVAL;
+
+ return 0;
+}
+
+int __connman_dnsproxy_init(void)
+{
+ int ret;
+
+ DBG("");
+
+ if ((ret = setup_resolved()) < 0)
+ return ret;
+
+ interface_map = g_tree_new_full(int_cmp, NULL, NULL,
+ free_dns_interface);
+
+ if (!interface_map)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __connman_dnsproxy_cleanup(void)
+{
+ DBG("");
+
+ if (update_interfaces_source) {
+ /* It might be that we don't get to an idle loop anymore, so
+ * run the update function once more to clean up.
+ */
+ g_source_remove(update_interfaces_source);
+ update_systemd_resolved(NULL);
+ update_interfaces_source = 0;
+ }
+
+ if (interface_map) {
+ g_tree_destroy(interface_map);
+ interface_map = NULL;
+ }
+
+ if (resolved_proxy) {
+ g_dbus_proxy_unref(resolved_proxy);
+ resolved_proxy = NULL;
+ }
+
+ if (client) {
+ g_dbus_client_unref(client);
+ client = NULL;
+ }
+
+ if (connection) {
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
+}
--
2.13.6
3 years, 3 months
[PATCH 1/2] resolver: add support for systemd-resolved.
by Ismo Puustinen
If systemd-resolved is running, use it for DNS address resolution. In
this case just deliver the DNS addresses to systemd-resolved and do not
run our own DNS proxy. The systemd-resolved support is selected to
be used if command line option "-s" is passed to connmand. This
implicitly disables connmand's DNS proxy.
---
src/connman.h | 2 +-
src/main.c | 5 +-
src/resolver.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 229 insertions(+), 12 deletions(-)
diff --git a/src/connman.h b/src/connman.h
index 21b70802..1f7afdbc 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -249,7 +249,7 @@ char **__connman_inet_get_pnp_nameservers(const char *pnp_file);
#include <connman/resolver.h>
-int __connman_resolver_init(gboolean dnsproxy);
+int __connman_resolver_init(gboolean dnsproxy, gboolean resolved);
void __connman_resolver_cleanup(void);
void __connman_resolver_append_fallback_nameservers(void);
int __connman_resolvfile_append(int index, const char *domain, const char *server);
diff --git a/src/main.c b/src/main.c
index b78a0461..2cb5c56e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -511,6 +511,7 @@ static gchar *option_noplugin = NULL;
static gchar *option_wifi = NULL;
static gboolean option_detach = TRUE;
static gboolean option_dnsproxy = TRUE;
+static gboolean option_resolved = FALSE;
static gboolean option_backtrace = TRUE;
static gboolean option_version = FALSE;
@@ -572,6 +573,8 @@ static GOptionEntry options[] = {
{ "nodnsproxy", 'r', G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_dnsproxy,
"Don't enable DNS Proxy" },
+ { "resolvedproxy", 's', 0, G_OPTION_ARG_NONE, &option_resolved,
+ "Use systemd-resolved for DNS management" },
{ "nobacktrace", 0, G_OPTION_FLAG_REVERSE,
G_OPTION_ARG_NONE, &option_backtrace,
"Don't print out backtrace information" },
@@ -762,7 +765,7 @@ int main(int argc, char *argv[])
__connman_plugin_init(option_plugin, option_noplugin);
- __connman_resolver_init(option_dnsproxy);
+ __connman_resolver_init(option_dnsproxy, option_resolved);
__connman_rtnl_start();
__connman_dhcp_init();
__connman_dhcpv6_init();
diff --git a/src/resolver.c b/src/resolver.c
index 75ea5ba6..62abb4a2 100644
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -32,11 +32,15 @@
#include <sys/stat.h>
#include <resolv.h>
#include <netdb.h>
+#include <gdbus.h>
+#include <connman/dbus.h>
#include "connman.h"
#define RESOLV_CONF_STATEDIR STATEDIR"/resolv.conf"
#define RESOLV_CONF_ETC "/etc/resolv.conf"
+#define SYSTEMD_RESOLVED_SERVICE "org.freedesktop.resolve1"
+#define SYSTEMD_RESOLVED_PATH "/org/freedesktop/resolve1"
#define RESOLVER_FLAG_PUBLIC (1 << 0)
@@ -58,6 +62,9 @@ struct entry_data {
static GSList *entry_list = NULL;
static bool dnsproxy_enabled = false;
+static DBusConnection *connection = NULL;
+static GDBusClient *client = NULL;
+static GDBusProxy *resolved_proxy = NULL;
struct resolvfile_entry {
int index;
@@ -67,6 +74,154 @@ struct resolvfile_entry {
static GList *resolvfile_list = NULL;
+static void revertlink_append(DBusMessageIter *iter, void *user_data)
+{
+ int *index = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, index);
+}
+
+static int resolved_remove_all(int index)
+{
+ gboolean result;
+
+ result = g_dbus_proxy_method_call(resolved_proxy, "RevertLink",
+ revertlink_append, NULL, &index, NULL);
+
+ if (result == FALSE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void setlinkdns_append(DBusMessageIter *iter, void *user_data)
+{
+ struct resolvfile_entry *entry = NULL;
+ int result, *index = user_data;
+ unsigned i;
+ int type;
+ char ipv4_bytes[4];
+ char ipv6_bytes[16];
+ GList *list;
+
+ DBusMessageIter address_array, struct_array, byte_array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(iay)",
+ &address_array);
+
+ for (list = g_list_first(resolvfile_list); list; list = g_list_next(list)) {
+ entry = list->data;
+
+ DBG("setlinkdns_append: index: %d, server: %s, domain: %s",
+ entry->index, entry->server ? entry->server : "NULL",
+ entry->domain ? entry->domain : "NULL");
+
+ if (entry->index != *index || entry->server == NULL)
+ continue;
+
+ dbus_message_iter_open_container(&address_array, DBUS_TYPE_STRUCT, NULL,
+ &struct_array);
+
+ type = connman_inet_check_ipaddress(entry->server);
+
+ if (type == AF_INET) {
+ result = inet_pton(type, entry->server, ipv4_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv4 address: %s", entry->server);
+ return;
+ }
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_INT32,
+ &type);
+ dbus_message_iter_open_container(&struct_array, DBUS_TYPE_ARRAY,
+ "y", &byte_array);
+ for (i = 0; i < sizeof(ipv4_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array, DBUS_TYPE_BYTE,
+ &(ipv4_bytes[i]));
+ }
+ dbus_message_iter_close_container(&struct_array, &byte_array);
+ }
+ else {
+ result = inet_pton(type, entry->server, ipv6_bytes);
+ if (!result) {
+ DBG("Failed to parse IPv4 address: %s", entry->server);
+ return;
+ }
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_INT32,
+ &type);
+ dbus_message_iter_open_container(&struct_array, DBUS_TYPE_ARRAY,
+ "y", &byte_array);
+ for (i = 0; i < sizeof(ipv6_bytes); i++) {
+ dbus_message_iter_append_basic(&byte_array, DBUS_TYPE_BYTE,
+ &(ipv6_bytes[i]));
+ }
+ dbus_message_iter_close_container(&struct_array, &byte_array);
+ }
+ dbus_message_iter_close_container(&address_array, &struct_array);
+ }
+
+ dbus_message_iter_close_container(iter, &address_array);
+}
+
+static void setlinkdomains_append(DBusMessageIter *iter, void *user_data)
+{
+ struct resolvfile_entry *entry;
+ int *index = user_data;
+ DBusMessageIter domain_array, struct_array;
+ gboolean only_routing = FALSE;
+ GList *list;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, index);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(sb)",
+ &domain_array);
+
+ for (list = g_list_first(resolvfile_list); list; list = g_list_next(list)) {
+ entry = list->data;
+
+ DBG("setlinkdomains_append: index: %d, server: %s, domain: %s",
+ entry->index, entry->server ? entry->server : "NULL",
+ entry->domain ? entry->domain : "NULL");
+
+ if (entry->index != *index || entry->domain == NULL)
+ continue;
+
+ dbus_message_iter_open_container(&domain_array, DBUS_TYPE_STRUCT, NULL,
+ &struct_array);
+
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_STRING,
+ &entry->domain);
+ dbus_message_iter_append_basic(&struct_array, DBUS_TYPE_BOOLEAN,
+ &only_routing);
+
+ dbus_message_iter_close_container(&domain_array, &struct_array);
+ }
+ dbus_message_iter_close_container(iter, &domain_array);
+}
+
+static int resolved_export(int index)
+{
+ gboolean result;
+
+ if (!resolved_proxy)
+ return -ENOENT;
+
+ /* No async error processing -- just fire and forget */
+
+ result = g_dbus_proxy_method_call(resolved_proxy, "SetLinkDNS",
+ setlinkdns_append, NULL, &index, NULL);
+ if (result == FALSE)
+ return -EINVAL;
+
+ result = g_dbus_proxy_method_call(resolved_proxy, "SetLinkDomains",
+ setlinkdomains_append, NULL, &index, NULL);
+ if (result == FALSE)
+ return -EINVAL;
+
+ return 0;
+}
+
static void resolvfile_remove_entries(GList *entries)
{
GList *list;
@@ -188,11 +343,14 @@ int __connman_resolvfile_append(int index, const char *domain,
resolvfile_list = g_list_append(resolvfile_list, entry);
+ if (resolved_proxy)
+ return resolved_export(index);
+
return resolvfile_export();
}
-int __connman_resolvfile_remove(int index, const char *domain,
- const char *server)
+static int __connman_resolvfile_remove_entry(int index, const char *domain,
+ const char *server, gboolean remove_from_resolved)
{
GList *list, *matches = NULL;
@@ -215,9 +373,22 @@ int __connman_resolvfile_remove(int index, const char *domain,
resolvfile_remove_entries(matches);
+ if (resolved_proxy) {
+ if (remove_from_resolved)
+ return resolved_export(index);
+ else
+ return 0; /* whole link is reset later */
+ }
+
return resolvfile_export();
}
+int __connman_resolvfile_remove(int index, const char *domain,
+ const char *server)
+{
+ return __connman_resolvfile_remove_entry(index, domain, server, TRUE);
+}
+
void __connman_resolver_append_fallback_nameservers(void)
{
GSList *list;
@@ -269,7 +440,7 @@ static void remove_fallback_nameservers(void)
}
}
-static void remove_entries(GSList *entries)
+static void remove_entries(GSList *entries, int index)
{
GSList *list;
@@ -282,8 +453,8 @@ static void remove_entries(GSList *entries)
__connman_dnsproxy_remove(entry->index, entry->domain,
entry->server);
} else {
- __connman_resolvfile_remove(entry->index, entry->domain,
- entry->server);
+ __connman_resolvfile_remove_entry(entry->index, entry->domain,
+ entry->server, index < 0 ? TRUE : FALSE);
}
if (entry->timeout)
@@ -295,6 +466,9 @@ static void remove_entries(GSList *entries)
g_slist_free(entries);
+ if (resolved_proxy && index >= 0)
+ resolved_remove_all(index);
+
__connman_resolver_append_fallback_nameservers();
}
@@ -316,7 +490,7 @@ static gboolean resolver_expire_cb(gpointer user_data)
entry->server, true);
}
- remove_entries(list);
+ remove_entries(list, -1);
return FALSE;
}
@@ -538,7 +712,7 @@ int connman_resolver_remove(int index, const char *domain, const char *server)
if (!matches)
return -ENOENT;
- remove_entries(matches);
+ remove_entries(matches, -1);
return 0;
}
@@ -570,7 +744,10 @@ int connman_resolver_remove_all(int index)
if (!matches)
return -ENOENT;
- remove_entries(matches);
+ if (resolved_proxy)
+ return resolved_remove_all(index);
+
+ remove_entries(matches, index);
return 0;
}
@@ -652,12 +829,34 @@ static void free_resolvfile(gpointer data)
g_free(entry);
}
-int __connman_resolver_init(gboolean dnsproxy)
+int __connman_resolver_init(gboolean dnsproxy, gboolean resolved)
{
int i;
char **ns;
- DBG("dnsproxy %d", dnsproxy);
+ DBG("dnsproxy %d, resolved %d", dnsproxy, resolved);
+
+ if (resolved) {
+ connection = connman_dbus_get_connection();
+
+ if (connection) {
+ client = g_dbus_client_new(connection,
+ SYSTEMD_RESOLVED_SERVICE, SYSTEMD_RESOLVED_PATH);
+ if (!client)
+ DBG("Failed to initialize proxy for systemd-resolved");
+ else {
+ resolved_proxy = g_dbus_proxy_new(client, SYSTEMD_RESOLVED_PATH,
+ "org.freedesktop.resolve1.Manager");
+
+ if (resolved_proxy) {
+ /* setup succeeded, disable dnsproxy */
+ dnsproxy = FALSE;
+ }
+ else
+ DBG("Failed to initialize proxy for systemd-resolved");
+ }
+ }
+ }
/* get autoip nameservers */
ns = __connman_inet_get_pnp_nameservers(NULL);
@@ -706,4 +905,19 @@ void __connman_resolver_cleanup(void)
g_slist_free(entry_list);
entry_list = NULL;
}
+
+ if (resolved_proxy) {
+ g_dbus_proxy_unref(resolved_proxy);
+ resolved_proxy = NULL;
+ }
+
+ if (client) {
+ g_dbus_client_unref(client);
+ client = NULL;
+ }
+
+ if (connection) {
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
}
--
2.13.5
3 years, 3 months
[PATCH v2] gsupplicant: Updates to handling of security change
by Harish Jenny K N
Changing of security type of one BSS is resulting in removing of
GSupplicantNetwork and other BSSs objects in the group.
The corresponding entries for other BSS in the same group are not
removed in other hash tables like bss_mapping and interface->bss_mapping.
This commit only deletes the network when there is a single entry in
network->bss_table during change in security for one bss.
This commit also avoids accessing any deleted bss object when reply
is got from async dbus call, by deleting any pending dbus calls
associated with the bss object.
---
gsupplicant/supplicant.c | 48 +++++++++++++++++++++++++++++++-----------------
1 file changed, 31 insertions(+), 17 deletions(-)
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 4f79012..5aa6e29 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -755,6 +755,8 @@ static void remove_bss(gpointer data)
{
struct g_supplicant_bss *bss = data;
+ supplicant_dbus_property_call_cancel_all(bss);
+
g_free(bss->path);
g_free(bss);
}
@@ -2064,7 +2066,7 @@ static void interface_bss_added_without_keys(DBusMessageIter *iter,
supplicant_dbus_property_get_all(bss->path,
SUPPLICANT_INTERFACE ".BSS",
- bss_property, bss, NULL);
+ bss_property, bss, bss);
bss_compute_security(bss);
if (add_or_replace_bss_to_network(bss) < 0)
@@ -2747,18 +2749,16 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
if (old_security != bss->security) {
struct g_supplicant_bss *new_bss;
- SUPPLICANT_DBG("New network security for %s", bss->ssid);
+ SUPPLICANT_DBG("New network security for %s with path %s",
+ bss->ssid, bss->path);
/* Security change policy:
- * - we first copy the current bss into a new one with
+ * - We first copy the current bss into a new one with
* its own pointer (path)
- * - we remove the current bss related network which will
- * tell the plugin about such removal. This is done due
- * to the fact that a security change means a group change
- * so a complete network change.
- * (current bss becomes invalid as well)
- * - we add the new bss: it adds new network and tell the
- * plugin about it. */
+ * - Clear the old bss pointer and remove the network completely
+ * if there are no more BSSs in the bss table.
+ * - The new bss will be added either to an existing network
+ * or an additional network will be created */
new_bss = g_try_new0(struct g_supplicant_bss, 1);
if (!new_bss)
@@ -2767,15 +2767,29 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
memcpy(new_bss, bss, sizeof(struct g_supplicant_bss));
new_bss->path = g_strdup(bss->path);
- g_hash_table_remove(interface->network_table, network->group);
+ if (network->best_bss == bss) {
+ network->best_bss = NULL;
+ network->signal = BSS_UNKNOWN_STRENGTH;
+ }
+
+ g_hash_table_remove(bss_mapping, path);
+
+ g_hash_table_remove(interface->bss_mapping, path);
+ g_hash_table_remove(network->bss_table, path);
+
+ update_network_signal(network);
+
+ if (g_hash_table_size(network->bss_table) == 0)
+ g_hash_table_remove(interface->network_table,
+ network->group);
if (add_or_replace_bss_to_network(new_bss) < 0) {
- /* Remove entries in hash tables to handle the
- * failure in add_or_replace_bss_to_network
- */
- g_hash_table_remove(bss_mapping, path);
- g_hash_table_remove(interface->bss_mapping, path);
- g_hash_table_remove(network->bss_table, path);
+ /* Prevent a memory leak on failure in
+ * add_or_replace_bss_to_network */
+ SUPPLICANT_DBG("Failed to add bss %s to network table",
+ new_bss->path);
+ g_free(new_bss->path);
+ g_free(new_bss);
}
return;
--
1.9.1
3 years, 3 months
Re: [PATCH] rtnl: Fix a debug print out
by Daniel Wagner
Hi Jian,
On 09/06/2017 05:54 PM, Jian Liang wrote:
> From: Jian Liang <jianliang(a)tycoint.com>
>
> In <linux/netlink.h>, nlmsghdr is defined as
>
> struct nlmsghdr {
> __u32 nlmsg_len; /* Length of message including header. */
> __u16 nlmsg_type; /* Type of message content. */
> __u16 nlmsg_flags; /* Additional flags. */
> __u32 nlmsg_seq; /* Sequence number. */
> __u32 nlmsg_pid; /* Sender port ID. */
> };
>
> DBG print out should use %u instead of %d
Sorry for the delay with this one. I have missed to apply it. Patch
applied now.
Thanks,
Daniel
3 years, 3 months