X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fresolve%2Fresolved-manager.c;h=04ee204074107d54dc2e99c6d90acfa0f4b2d866;hb=be754d5443e5fe44ead733ad509b127409cdb0f0;hp=6bb089451f1b8d1a09d07f1df4e1abe3eb9fb3ff;hpb=87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3;p=elogind.git diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 6bb089451..04ee20407 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -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); @@ -676,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; @@ -697,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 *length, unsigned *count) { + 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; @@ -718,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); @@ -727,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) @@ -737,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) { @@ -764,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); @@ -788,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(CONST_MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo))) + CMSG_SPACE(int) /* ttl/hoplimit */ + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */]; } control; @@ -1771,6 +1824,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",