chiark / gitweb /
resolved: skip IPv6 LLMNR if IPv6 is not available
[elogind.git] / src / resolve / resolved-manager.c
index 988aa6e3b1a2fec802c848fddb84bef0345c9d9c..84dad92c53eb81cbf99853f130b761ae9cf45c03 100644 (file)
@@ -426,23 +426,25 @@ static int manager_llmnr_start(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = manager_llmnr_ipv6_udp_fd(m);
-        if (r == -EADDRINUSE)
-                goto eaddrinuse;
-        if (r < 0)
-                return r;
-
         r = manager_llmnr_ipv4_tcp_fd(m);
         if (r == -EADDRINUSE)
                 goto eaddrinuse;
         if (r < 0)
                 return r;
 
-        r = manager_llmnr_ipv6_tcp_fd(m);
-        if (r == -EADDRINUSE)
-                goto eaddrinuse;
-        if (r < 0)
-                return r;
+        if (socket_ipv6_is_supported()) {
+                r = manager_llmnr_ipv6_udp_fd(m);
+                if (r == -EADDRINUSE)
+                        goto eaddrinuse;
+                if (r < 0)
+                        return r;
+
+                r = manager_llmnr_ipv6_tcp_fd(m);
+                if (r == -EADDRINUSE)
+                        goto eaddrinuse;
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 
@@ -450,6 +452,7 @@ eaddrinuse:
         log_warning("There appears to be another LLMNR respondering running. Turning off LLMNR support.");
         m->llmnr_support = SUPPORT_NO;
         manager_llmnr_stop(m);
+
         return 0;
 }
 
@@ -536,10 +539,8 @@ Manager *manager_free(Manager *m) {
 
         dns_scope_free(m->unicast_scope);
 
-        while (m->dns_servers)
-                dns_server_free(m->dns_servers);
-        while (m->fallback_dns_servers)
-                dns_server_free(m->fallback_dns_servers);
+        manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
+        manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
 
         hashmap_free(m->links);
         hashmap_free(m->dns_transactions);
@@ -691,7 +692,7 @@ static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
         }
 
         if (*count == MAXNS)
-                fputs("# Too many DNS servers configured, the following entries may be ignored\n", f);
+                fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
 
         fprintf(f, "nameserver %s\n", t);
         (*count) ++;
@@ -701,6 +702,7 @@ int manager_write_resolv_conf(Manager *m) {
         static const char path[] = "/run/systemd/resolve/resolv.conf";
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_set_free_ Set *dns = NULL;
         unsigned count = 0;
         DnsServer *s;
         Iterator i;
@@ -712,6 +714,41 @@ int manager_write_resolv_conf(Manager *m) {
         /* Read the system /etc/resolv.conf first */
         manager_read_resolv_conf(m);
 
+        /* Add the full list to a set, to filter out duplicates */
+        dns = set_new(dns_server_hash_func, dns_server_compare_func);
+        if (!dns)
+                return -ENOMEM;
+
+        /* First add the system-wide servers */
+        LIST_FOREACH(servers, s, m->dns_servers) {
+                r = set_put(dns, s);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return r;
+        }
+
+        /* Then, add the per-link servers */
+        HASHMAP_FOREACH(l, m->links, i)
+                LIST_FOREACH(servers, s, l->dns_servers) {
+                        r = set_put(dns, s);
+                        if (r == -EEXIST)
+                                continue;
+                        if (r < 0)
+                                return r;
+                }
+
+        /* If we found nothing, add the fallback servers */
+        if (set_isempty(dns)) {
+                LIST_FOREACH(servers, s, m->fallback_dns_servers) {
+                        r = set_put(dns, s);
+                        if (r == -EEXIST)
+                                continue;
+                        if (r < 0)
+                                return r;
+                }
+        }
+
         r = fopen_temporary(path, &f, &temp_path);
         if (r < 0)
                 return r;
@@ -724,15 +761,10 @@ int manager_write_resolv_conf(Manager *m) {
               "# resolv.conf(5) in a different way, replace the symlink by a\n"
               "# static file or a different symlink.\n\n", f);
 
-        LIST_FOREACH(servers, s, m->dns_servers)
-                write_resolve_conf_server(s, f, &count);
-
-        HASHMAP_FOREACH(l, m->links, i)
-                LIST_FOREACH(servers, s, l->dns_servers)
-                        write_resolve_conf_server(s, f, &count);
-
-        if (count == 0) {
-                LIST_FOREACH(servers, s, m->fallback_dns_servers)
+        if (set_isempty(dns))
+                fputs("# No DNS servers known.\n", f);
+        else {
+                SET_FOREACH(s, dns, i)
                         write_resolve_conf_server(s, f, &count);
         }
 
@@ -1740,6 +1772,18 @@ void manager_verify_all(Manager *m) {
                 dns_zone_verify_all(&s->zone);
 }
 
+void manager_flush_dns_servers(Manager *m, DnsServerType t) {
+        assert(m);
+
+        if (t == DNS_SERVER_SYSTEM)
+                while (m->dns_servers)
+                        dns_server_free(m->dns_servers);
+
+        if (t == DNS_SERVER_FALLBACK)
+                while (m->fallback_dns_servers)
+                        dns_server_free(m->fallback_dns_servers);
+}
+
 static const char* const support_table[_SUPPORT_MAX] = {
         [SUPPORT_NO] = "no",
         [SUPPORT_YES] = "yes",