chiark / gitweb /
resolved: fall back to hardcoded ifindex when checking if a link is the loopback
[elogind.git] / src / resolve / resolved-manager.c
index a2de2edb48f5a76d2398dc3abbd2ca03bcea352a..00aaffe44899bdcf9efb01372ee03c2ac47ac603 100644 (file)
@@ -426,30 +426,33 @@ 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;
 
 eaddrinuse:
-        log_warning("There appears to be another LLMNR respondering running. Turning off LLMNR support.");
+        log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
         m->llmnr_support = SUPPORT_NO;
         manager_llmnr_stop(m);
+
         return 0;
 }
 
@@ -674,7 +677,7 @@ clear:
         return r;
 }
 
-static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
+static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
         _cleanup_free_ char *t  = NULL;
         int r;
 
@@ -695,11 +698,33 @@ static void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
         (*count) ++;
 }
 
+static void write_resolv_conf_search(const char *domain, FILE *f,
+                                     unsigned *count, unsigned *length) {
+        assert(domain);
+        assert(f);
+        assert(length);
+
+        if (*count >= MAXDNSRCH ||
+            *length + strlen(domain) > 256) {
+                if (*count == MAXDNSRCH)
+                        fputs(" # Too many search domains configured, remaining ones ignored.", f);
+                if (*length <= 256)
+                        fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
+
+                return;
+        }
+
+        fprintf(f, " %s", domain);
+
+        (*length) += strlen(domain);
+        (*count) ++;
+}
+
 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;
+        _cleanup_set_free_ Set *dns = NULL, *domains = NULL;
         unsigned count = 0;
         DnsServer *s;
         Iterator i;
@@ -716,6 +741,10 @@ int manager_write_resolv_conf(Manager *m) {
         if (!dns)
                 return -ENOMEM;
 
+        domains = set_new(dns_name_hash_func, dns_name_compare_func);
+        if (!domains)
+                return -ENOMEM;
+
         /* First add the system-wide servers */
         LIST_FOREACH(servers, s, m->dns_servers) {
                 r = set_put(dns, s);
@@ -725,8 +754,10 @@ int manager_write_resolv_conf(Manager *m) {
                         return r;
         }
 
-        /* Then, add the per-link servers */
-        HASHMAP_FOREACH(l, m->links, i)
+        /* Then, add the per-link servers and domains */
+        HASHMAP_FOREACH(l, m->links, i) {
+                char **domain;
+
                 LIST_FOREACH(servers, s, l->dns_servers) {
                         r = set_put(dns, s);
                         if (r == -EEXIST)
@@ -735,6 +766,18 @@ int manager_write_resolv_conf(Manager *m) {
                                 return r;
                 }
 
+                if (!l->unicast_scope)
+                        continue;
+
+                STRV_FOREACH(domain, l->unicast_scope->domains) {
+                        r = set_put(domains, *domain);
+                        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) {
@@ -762,7 +805,19 @@ int manager_write_resolv_conf(Manager *m) {
                 fputs("# No DNS servers known.\n", f);
         else {
                 SET_FOREACH(s, dns, i)
-                        write_resolve_conf_server(s, f, &count);
+                        write_resolv_conf_server(s, f, &count);
+        }
+
+        if (!set_isempty(domains)) {
+                unsigned length = 0;
+                char *domain;
+
+                count = 0;
+
+                fputs("search", f);
+                SET_FOREACH(domain, domains, i)
+                        write_resolv_conf_search(domain, f, &count, &length);
+                fputs("\n", f);
         }
 
         r = fflush_and_check(f);
@@ -786,7 +841,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
         union {
                 struct cmsghdr header; /* For alignment */
-                uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo)))
+                uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
                                + CMSG_SPACE(int) /* ttl/hoplimit */
                                + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
         } control;
@@ -1632,6 +1687,9 @@ fail:
         return r;
 }
 
+/* lo having ifindex 1 is hardcoded in the kernel */
+#define LOOPBACK_IFINDEX 1
+
 int manager_ifindex_is_loopback(Manager *m, int ifindex) {
         Link *l;
         assert(m);
@@ -1640,7 +1698,10 @@ int manager_ifindex_is_loopback(Manager *m, int ifindex) {
                 return -EINVAL;
 
         l = hashmap_get(m->links, INT_TO_PTR(ifindex));
-        if (l->flags & IFF_LOOPBACK)
+        if (!l)
+                /* in case we don't yet track the link, rely on the hardcoded value */
+                return ifindex == LOOPBACK_IFINDEX;
+        else if (l->flags & IFF_LOOPBACK)
                 return 1;
 
         return 0;