IPv6 autoconfigured nameservers can be added to resolver
via netlink messages in rtnl.c. Because of this they are
not seen in service object so we need to get those auto
added nameserver to be notified in service.c so that
service can show them to user if necessary.

Fixes BMC#24196
---
 src/service.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 109 insertions(+), 0 deletions(-)

diff --git a/src/service.c b/src/service.c
index 30bf2fb..3a41181 100644
--- a/src/service.c
+++ b/src/service.c
@@ -86,6 +86,7 @@ struct connman_service {
        struct connman_network *network;
        struct connman_provider *provider;
        char **nameservers;
+       char **nameservers_auto;
        char **nameservers_config;
        char **domains;
        char *domainname;
@@ -1423,6 +1424,10 @@ static void append_dns(DBusMessageIter *iter, void 
*user_data)
                return;
        } else if (service->nameservers != NULL) {
                append_nameserver(iter, &service->nameservers);
+
+               if (service->nameservers_auto != NULL)
+                       append_nameserver(iter, &service->nameservers_auto);
+
                return;
        }
 }
@@ -3421,6 +3426,7 @@ static void service_free(gpointer user_data)
 
        g_strfreev(service->nameservers);
        g_strfreev(service->nameservers_config);
+       g_strfreev(service->nameservers_auto);
        g_strfreev(service->domains);
        g_strfreev(service->proxies);
        g_strfreev(service->excludes);
@@ -4220,12 +4226,104 @@ static void service_rp_filter(struct connman_service 
*service,
                connected_networks_count, original_rp_filter);
 }
 
+/*
+ * We track nameservers from resolver as IPv6 autoconf nameservers can be
+ * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt()
+ * for details) and not through service.c
+ */
+static void nameserver_added(const char *interface, gpointer user_data,
+                       const char *nameserver)
+{
+       struct connman_service *service = user_data;
+       gboolean found = FALSE;
+       int i;
+
+       DBG("service %p iface %s nameserver %s",
+                               service, interface, nameserver);
+
+       for (i = 0; service->nameservers_auto != NULL &&
+                                       service->nameservers_auto[i] != NULL; 
i++) {
+               if (g_strcmp0(service->nameservers_auto[i], nameserver) == 0) {
+                       found = TRUE;
+                       break;
+               }
+       }
+
+       if (found == FALSE) {
+               int len;
+
+               if (service->nameservers_auto != NULL) {
+                       len = g_strv_length(service->nameservers_auto);
+                       service->nameservers_auto = g_try_renew(char *,
+                                                       
service->nameservers_auto,
+                                                       len + 2);
+               } else {
+                       len = 0;
+                       service->nameservers_auto = g_try_new0(char *, len + 2);
+               }
+
+               if (service->nameservers_auto == NULL)
+                       return;
+
+               service->nameservers_auto[len] = g_strdup(nameserver);
+               service->nameservers_auto[len + 1] = NULL;
+       }
+}
+
+static void nameserver_removed(const char *interface, gpointer user_data,
+                       const char *nameserver)
+{
+       struct connman_service *service = user_data;
+       gboolean found = FALSE;
+       int i;
+
+       DBG("service %p iface %s nameserver %s",
+                               service, interface, nameserver);
+
+       for (i = 0; service->nameservers_auto != NULL &&
+                               service->nameservers_auto[i] != NULL; i++) {
+               if (g_strcmp0(service->nameservers_auto[i], nameserver) == 0) {
+                       found = TRUE;
+                       break;
+               }
+       }
+
+       if (found == TRUE) {
+               int j, len = g_strv_length(service->nameservers_auto);
+               char **servers;
+
+               if (len == 1) {
+                       g_strfreev(service->nameservers_auto);
+                       service->nameservers_auto = NULL;
+                       return;
+               }
+
+               servers = g_try_new0(char *, len);
+               if (servers == NULL)
+                       return;
+
+               for (i = 0, j = 0; i < len; i++) {
+                       if (g_strcmp0(service->nameservers_auto[i],
+                                       nameserver) != 0) {
+                               servers[j] = g_strdup(
+                                               service->nameservers_auto[i]);
+                               j++;
+                       }
+               }
+               servers[len - 1] = NULL;
+
+               g_strfreev(service->nameservers_auto);
+               service->nameservers_auto = servers;
+       }
+}
+
 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
                                        enum connman_service_state new_state,
                                        enum connman_ipconfig_type type)
 {
        struct connman_ipconfig *ipconfig = NULL;
        enum connman_service_state old_state;
+       const char *ifname;
        int ret;
 
        if (service == NULL)
@@ -4265,6 +4363,13 @@ int __connman_service_ipconfig_indicate_state(struct 
connman_service *service,
        case CONNMAN_SERVICE_STATE_READY:
                update_nameservers(service);
 
+               ifname = connman_ipconfig_get_ifname(ipconfig);
+               if (ifname != NULL)
+                       __connman_resolver_register_notifier(ifname,
+                                                       service,
+                                                       nameserver_added,
+                                                       nameserver_removed);
+
                if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
                        check_proxy_setup(service);
                        service_rp_filter(service, TRUE);
@@ -4280,6 +4385,10 @@ int __connman_service_ipconfig_indicate_state(struct 
connman_service *service,
                if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
                        service_rp_filter(service, FALSE);
 
+               ifname = connman_ipconfig_get_ifname(ipconfig);
+               if (ifname != NULL)
+                       __connman_resolver_unregister_notifier(ifname);
+
                break;
        case CONNMAN_SERVICE_STATE_FAILURE:
                break;
-- 
1.7.1

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to