X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fresolve%2Fresolved-manager.c;h=c4a5b08773995b26b7c123f66f40fc703b52f6e5;hp=a2de2edb48f5a76d2398dc3abbd2ca03bcea352a;hb=0e3434aeb1eed951fdbeddacc6126e10d82a1c8b;hpb=3e684349c2cead2e6fd2f816c34eb17daba23a49 diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index a2de2edb4..c4a5b0877 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -34,6 +34,7 @@ #include "socket-util.h" #include "af-list.h" #include "utf8.h" +#include "fileio-label.h" #include "resolved-dns-domain.h" #include "resolved-conf.h" @@ -426,30 +427,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 +678,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,12 +699,66 @@ 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) ++; +} + +static int write_resolv_conf_contents(FILE *f, Set *dns, Set *domains) { + Iterator i; + + fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n" + "# Third party programs must not access this file directly, but\n" + "# only through the symlink at /etc/resolv.conf. To manage\n" + "# resolv.conf(5) in a different way, replace the symlink by a\n" + "# static file or a different symlink.\n\n", f); + + if (set_isempty(dns)) + fputs("# No DNS servers known.\n", f); + else { + DnsServer *s; + unsigned count = 0; + + SET_FOREACH(s, dns, i) + write_resolv_conf_server(s, f, &count); + } + + if (!set_isempty(domains)) { + unsigned length = 0, count = 0; + char *domain; + + fputs("search", f); + SET_FOREACH(domain, domains, i) + write_resolv_conf_search(domain, f, &count, &length); + fputs("\n", f); + } + + return fflush_and_check(f); +} + + 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; + _cleanup_set_free_ Set *dns = NULL, *domains = NULL; DnsServer *s; Iterator i; Link *l; @@ -712,10 +770,14 @@ int manager_write_resolv_conf(Manager *m) { 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); + dns = set_new(&dns_server_hash_ops); if (!dns) return -ENOMEM; + domains = set_new(&dns_name_hash_ops); + if (!domains) + return -ENOMEM; + /* First add the system-wide servers */ LIST_FOREACH(servers, s, m->dns_servers) { r = set_put(dns, s); @@ -725,8 +787,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 +799,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) { @@ -746,26 +822,13 @@ int manager_write_resolv_conf(Manager *m) { } } - r = fopen_temporary(path, &f, &temp_path); + r = fopen_temporary_label(path, path, &f, &temp_path); if (r < 0) return r; fchmod(fileno(f), 0644); - fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n" - "# Third party programs must not access this file directly, but\n" - "# only through the symlink at /etc/resolv.conf. To manage\n" - "# resolv.conf(5) in a different way, replace the symlink by a\n" - "# static file or a different symlink.\n\n", f); - - if (set_isempty(dns)) - fputs("# No DNS servers known.\n", f); - else { - SET_FOREACH(s, dns, i) - write_resolve_conf_server(s, f, &count); - } - - r = fflush_and_check(f); + r = write_resolv_conf_contents(f, dns, domains); if (r < 0) goto fail; @@ -786,7 +849,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; @@ -897,7 +960,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { * device if the packet came from the local host since it * avoids the routing table in such a case. Let's unset the * interface index in such a case. */ - if (p->ifindex > 0 && manager_ifindex_is_loopback(m, p->ifindex) != 0) + if (p->ifindex == LOOPBACK_IFINDEX) p->ifindex = 0; /* If we don't know the interface index still, we look for the @@ -1632,20 +1695,6 @@ fail: return r; } -int manager_ifindex_is_loopback(Manager *m, int ifindex) { - Link *l; - assert(m); - - if (ifindex <= 0) - return -EINVAL; - - l = hashmap_get(m->links, INT_TO_PTR(ifindex)); - if (l->flags & IFF_LOOPBACK) - return 1; - - return 0; -} - int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) { LinkAddress *a;