This fix is for following scenario:
 - New interface is coming up.
 - There is radvd in the connected network and it is
   advertising IPv6 addresses and DNS servers.
 - Kernel receives router advertisement and picks up the DNS
   server information which is then routed via netlink to
   rtnl.c:rtnl_newnduseropt() which then creates DNS listener.
 - Kernel activates DAD (duplicate address detection).
 - As the DAD takes some time we now have interface up
   and it only has link local IPv6 address defined.
 - The DNS listener is now using link local source addresses when
   sending queries instead of proper autoconfigured addresses.
 - When DAD is finished, the interface will have autoconfigured
   addresses assigned and corresponding netlink message will cause
   function rtnl.c:process_newaddr() to be called.
 - If all this happens, then we re-create DNS listener
   in dnsproxy.c so that listener will have a proper
   (autoconfigured) source address when sending DNS packets.
---
 src/connman.h  |    1 +
 src/resolver.c |   33 +++++++++++++++++++++++++++++++++
 src/rtnl.c     |   14 ++++++++++++++
 3 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/src/connman.h b/src/connman.h
index 317af70..314f7e8 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -196,6 +196,7 @@ int __connman_resolver_init(connman_bool_t dnsproxy);
 void __connman_resolver_cleanup(void);
 int __connman_resolvfile_append(const char *interface, const char *domain, 
const char *server);
 int __connman_resolvfile_remove(const char *interface, const char *domain, 
const char *server);
+int __connman_resolver_redo_servers(const char *interface);
 
 void __connman_storage_migrate(void);
 GKeyFile *__connman_storage_open_global();
diff --git a/src/resolver.c b/src/resolver.c
index 9796717..cead9c3 100644
--- a/src/resolver.c
+++ b/src/resolver.c
@@ -468,6 +468,39 @@ void connman_resolver_flush(void)
        return;
 }
 
+int __connman_resolver_redo_servers(const char *interface)
+{
+       GSList *list;
+
+       if (dnsproxy_enabled == FALSE)
+               return 0;
+
+       DBG("interface %s", interface);
+
+       if (interface == NULL)
+               return -EINVAL;
+
+       for (list = entry_list; list; list = list->next) {
+               struct entry_data *entry = list->data;
+
+               if (entry->timeout == 0 ||
+                               g_strcmp0(entry->interface, interface) != 0)
+                       continue;
+
+               /*
+                * We remove the server, and then re-create so that it will
+                * use proper source addresses when sending DNS queries.
+                */
+               __connman_dnsproxy_remove(entry->interface, entry->domain,
+                                       entry->server);
+
+               __connman_dnsproxy_append(entry->interface, entry->domain,
+                                       entry->server);
+       }
+
+       return 0;
+}
+
 static void free_entry(gpointer data)
 {
        struct entry_data *entry = data;
diff --git a/src/rtnl.c b/src/rtnl.c
index 39afb12..251d9cd 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -601,6 +601,20 @@ static void process_newaddr(unsigned char family, unsigned 
char prefixlen,
 
        __connman_ipconfig_newaddr(index, family, label,
                                        prefixlen, ip_string);
+
+       if (family == AF_INET6) {
+               /*
+                * Re-create RDNSS configured servers if there are any
+                * for this interface. This is done because we might
+                * have now properly configured interface with proper
+                * autoconfigured address.
+                */
+               char *interface = connman_inet_ifname(index);
+
+               __connman_resolver_redo_servers(interface);
+
+               g_free(interface);
+       }
 }
 
 static void process_deladdr(unsigned char family, unsigned char prefixlen,
-- 
1.7.5.4

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to