/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
#include <netinet/in.h>
#include <poll.h>
+#include <stdio_ext.h>
#include <sys/ioctl.h>
#if HAVE_LIBIDN2
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
+ r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, manager_process_link, NULL, m, "resolve-NEWLINK");
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
+ r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, manager_process_link, NULL, m, "resolve-DELLINK");
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, manager_process_address, NULL, m, "resolve-NEWADDR");
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELADDR, manager_process_address, NULL, m, "resolve-DELADDR");
if (r < 0)
return r;
r = dns_label_unescape(&p, label, sizeof label);
if (r < 0)
return log_error_errno(r, "Failed to unescape host name: %m");
- if (r == 0) {
- log_error("Couldn't find a single label in hostname.");
- return -EINVAL;
- }
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Couldn't find a single label in hostname.");
#if HAVE_LIBIDN2
r = idn2_to_unicode_8z8z(label, &utf8, 0);
if (k > 0)
r = k;
- if (!utf8_is_valid(label)) {
- log_error("System hostname is not UTF-8 clean.");
- return -EINVAL;
- }
+ if (!utf8_is_valid(label))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "System hostname is not UTF-8 clean.");
decoded = label;
#else
decoded = label; /* no decoding */
if (r < 0)
return log_error_errno(r, "Failed to escape host name: %m");
- if (is_localhost(n)) {
- log_debug("System hostname is 'localhost', ignoring.");
- return -EINVAL;
- }
+ if (is_localhost(n))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "System hostname is 'localhost', ignoring.");
r = dns_name_concat(n, "local", mdns_hostname);
if (r < 0)
return log_error_errno(r, "Failed to determine mDNS hostname: %m");
- *llmnr_hostname = n;
- n = NULL;
-
- *full_hostname = h;
- h = NULL;
+ *llmnr_hostname = TAKE_PTR(n);
+ *full_hostname = TAKE_PTR(h);
return 0;
}
if (!h)
return log_oom();
- *llmnr_hostname = n;
- n = NULL;
-
- *mdns_hostname = m;
- m = NULL;
+ *llmnr_hostname = TAKE_PTR(n);
+ *mdns_hostname = TAKE_PTR(m);
*full_hostname = h;
assert(m);
- m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
+ m->hostname_fd = open("/proc/sys/kernel/hostname",
+ O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (m->hostname_fd < 0) {
log_warning_errno(errno, "Failed to watch hostname: %m");
return 0;
if (!f)
return log_oom();
+ (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+
LIST_FOREACH(scopes, scope, m->dns_scopes)
dns_scope_dump(scope, f);
assert(ret);
- m = new0(Manager, 1);
+ m = new(Manager, 1);
if (!m)
return -ENOMEM;
- m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
- m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
- m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1;
- m->dns_stub_udp_fd = m->dns_stub_tcp_fd = -1;
- m->hostname_fd = -1;
-
- m->llmnr_support = RESOLVE_SUPPORT_YES;
- m->mdns_support = RESOLVE_SUPPORT_YES;
- m->dnssec_mode = DEFAULT_DNSSEC_MODE;
- m->enable_cache = true;
- m->dns_stub_listener_mode = DNS_STUB_LISTENER_UDP;
- m->read_resolv_conf = true;
- m->need_builtin_fallbacks = true;
- m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY;
+ *m = (Manager) {
+ .llmnr_ipv4_udp_fd = -1,
+ .llmnr_ipv6_udp_fd = -1,
+ .llmnr_ipv4_tcp_fd = -1,
+ .llmnr_ipv6_tcp_fd = -1,
+ .mdns_ipv4_fd = -1,
+ .mdns_ipv6_fd = -1,
+ .dns_stub_udp_fd = -1,
+ .dns_stub_tcp_fd = -1,
+ .hostname_fd = -1,
+
+ .llmnr_support = RESOLVE_SUPPORT_YES,
+ .mdns_support = RESOLVE_SUPPORT_YES,
+ .dnssec_mode = DEFAULT_DNSSEC_MODE,
+ .dns_over_tls_mode = DEFAULT_DNS_OVER_TLS_MODE,
+ .enable_cache = true,
+ .dns_stub_listener_mode = DNS_STUB_LISTENER_UDP,
+ .read_resolv_conf = true,
+ .need_builtin_fallbacks = true,
+ .etc_hosts_last = USEC_INFINITY,
+ .etc_hosts_mtime = USEC_INFINITY,
+ .read_etc_hosts = true,
+ };
r = dns_trust_anchor_load(&m->trust_anchor);
if (r < 0)
if (r < 0)
return r;
- sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
- sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+ (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
+ (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
- sd_event_set_watchdog(m->event, true);
+ (void) sd_event_set_watchdog(m->event, true);
r = manager_watch_hostname(m);
if (r < 0)
manager_cleanup_saved_user(m);
- *ret = m;
- m = NULL;
+ *ret = TAKE_PTR(m);
return 0;
}
manager_mdns_stop(m);
manager_dns_stub_stop(m);
- sd_bus_slot_unref(m->prepare_for_sleep_slot);
- sd_event_source_unref(m->bus_retry_event_source);
sd_bus_unref(m->bus);
sd_event_source_unref(m->sigusr1_event_source);
+ EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
} control;
union sockaddr_union sa;
- struct msghdr mh = {};
- struct cmsghdr *cmsg;
struct iovec iov;
+ struct msghdr mh = {
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
ssize_t ms, l;
int r;
if (r < 0)
return r;
- iov.iov_base = DNS_PACKET_DATA(p);
- iov.iov_len = p->allocated;
-
- mh.msg_name = &sa.sa;
- mh.msg_namelen = sizeof(sa);
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
+ iov = (struct iovec) {
+ .iov_base = DNS_PACKET_DATA(p),
+ iov.iov_len = p->allocated,
+ };
l = recvmsg(fd, &mh, 0);
if (l == 0)
p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
}
- *ret = p;
- p = NULL;
+ *ret = TAKE_PTR(p);
return 1;
}
uint16_t port,
const struct in_addr *source,
DnsPacket *p) {
- union sockaddr_union sa = {
- .in.sin_family = AF_INET,
- };
union {
struct cmsghdr header; /* For alignment */
uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
- } control;
- struct msghdr mh = {};
+ } control = {};
+ union sockaddr_union sa;
struct iovec iov;
+ struct msghdr mh = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa.in),
+ };
assert(m);
assert(fd >= 0);
assert(port > 0);
assert(p);
- iov.iov_base = DNS_PACKET_DATA(p);
- iov.iov_len = p->size;
-
- sa.in.sin_addr = *destination;
- sa.in.sin_port = htobe16(port),
+ iov = (struct iovec) {
+ .iov_base = DNS_PACKET_DATA(p),
+ .iov_len = p->size,
+ };
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- mh.msg_name = &sa.sa;
- mh.msg_namelen = sizeof(sa.in);
+ sa = (union sockaddr_union) {
+ .in.sin_family = AF_INET,
+ .in.sin_addr = *destination,
+ .in.sin_port = htobe16(port),
+ };
if (ifindex > 0) {
struct cmsghdr *cmsg;
struct in_pktinfo *pi;
- zero(control);
-
mh.msg_control = &control;
mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
const struct in6_addr *source,
DnsPacket *p) {
- union sockaddr_union sa = {
- .in6.sin6_family = AF_INET6,
- };
union {
struct cmsghdr header; /* For alignment */
uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- } control;
- struct msghdr mh = {};
+ } control = {};
+ union sockaddr_union sa;
struct iovec iov;
+ struct msghdr mh = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa.in6),
+ };
assert(m);
assert(fd >= 0);
assert(port > 0);
assert(p);
- iov.iov_base = DNS_PACKET_DATA(p);
- iov.iov_len = p->size;
-
- sa.in6.sin6_addr = *destination;
- sa.in6.sin6_port = htobe16(port),
- sa.in6.sin6_scope_id = ifindex;
+ iov = (struct iovec) {
+ .iov_base = DNS_PACKET_DATA(p),
+ .iov_len = p->size,
+ };
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- mh.msg_name = &sa.sa;
- mh.msg_namelen = sizeof(sa.in6);
+ sa = (union sockaddr_union) {
+ .in6.sin6_family = AF_INET6,
+ .in6.sin6_addr = *destination,
+ .in6.sin6_port = htobe16(port),
+ .in6.sin6_scope_id = ifindex,
+ };
if (ifindex > 0) {
struct cmsghdr *cmsg;
struct in6_pktinfo *pi;
- zero(control);
-
mh.msg_control = &control;
mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
log_debug("Sending %s packet with id %" PRIu16 " on interface %i/%s.", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family));
if (family == AF_INET)
- return manager_ipv4_send(m, fd, ifindex, &destination->in, port, &source->in, p);
+ return manager_ipv4_send(m, fd, ifindex, &destination->in, port, source ? &source->in : NULL, p);
if (family == AF_INET6)
- return manager_ipv6_send(m, fd, ifindex, &destination->in6, port, &source->in6, p);
+ return manager_ipv6_send(m, fd, ifindex, &destination->in6, port, source ? &source->in6 : NULL, p);
return -EAFNOSUPPORT;
}
}
}
-int manager_next_hostname(Manager *m) {
+static int manager_next_random_name(const char *old, char **ret_new) {
const char *p;
uint64_t u, a;
- char *h, *k;
- int r;
+ char *n;
- assert(m);
-
- p = strchr(m->llmnr_hostname, 0);
+ p = strchr(old, 0);
assert(p);
- while (p > m->llmnr_hostname) {
- if (!strchr("0123456789", p[-1]))
+ while (p > old) {
+ if (!strchr(DIGITS, p[-1]))
break;
p--;
random_bytes(&a, sizeof(a));
u += 1 + a % 10;
- if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
+ if (asprintf(&n, "%.*s%" PRIu64, (int) (p - old), old, u) < 0)
return -ENOMEM;
+ *ret_new = n;
+
+ return 0;
+}
+
+int manager_next_hostname(Manager *m) {
+ _cleanup_free_ char *h = NULL, *k = NULL;
+ int r;
+
+ assert(m);
+
+ r = manager_next_random_name(m->llmnr_hostname, &h);
+ if (r < 0)
+ return r;
+
r = dns_name_concat(h, "local", &k);
- if (r < 0) {
- free(h);
+ if (r < 0)
return r;
- }
log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
- free(m->llmnr_hostname);
- m->llmnr_hostname = h;
-
- free(m->mdns_hostname);
- m->mdns_hostname = k;
+ free_and_replace(m->llmnr_hostname, h);
+ free_and_replace(m->mdns_hostname, k);
manager_refresh_rrs(m);
return true;
}
+DnsOverTlsMode manager_get_dns_over_tls_mode(Manager *m) {
+ assert(m);
+
+ if (m->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
+ return m->dns_over_tls_mode;
+
+ return DNS_OVER_TLS_NO;
+}
+
void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key) {
assert(verdict >= 0);
assert(verdict < _DNSSEC_VERDICT_MAX);
- if (log_get_max_level() >= LOG_DEBUG) {
+ if (DEBUG_LOGGING) {
char s[DNS_RESOURCE_KEY_STRING_MAX];
log_debug("Found verdict for lookup %s: %s",
(void) unlink(p);
}
}
+
+bool manager_next_dnssd_names(Manager *m) {
+ Iterator i;
+ DnssdService *s;
+ bool tried = false;
+ int r;
+
+ assert(m);
+
+ HASHMAP_FOREACH(s, m->dnssd_services, i) {
+ _cleanup_free_ char * new_name = NULL;
+
+ if (!s->withdrawn)
+ continue;
+
+ r = manager_next_random_name(s->name_template, &new_name);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to get new name for service '%s': %m", s->name);
+ continue;
+ }
+
+ free_and_replace(s->name_template, new_name);
+
+ s->withdrawn = false;
+
+ tried = true;
+ }
+
+ if (tried)
+ manager_refresh_rrs(m);
+
+ return tried;
+}