resolved-manager.c revision 3ffd4af22052963e7a29431721ee204e634bea75
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2014 Tom Gundersen <teg@jklm.no>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is free software; you can redistribute it and/or modify it
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen under the terms of the GNU Lesser General Public License as published by
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (at your option) any later version.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is distributed in the hope that it will be useful, but
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Lesser General Public License for more details.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen You should have received a copy of the GNU Lesser General Public License
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
8b43440b7ef4b81c69c31de7ff820dc07a780254Lennart Poetteringstatic int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_get_type(mm, &type);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning_errno(r, "Failed to process RTNL link message: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_get_type(mm, &type);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_addr_get_family(mm, &family);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_read_in_addr(mm, IFA_LOCAL, &address.in);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a = link_find_address(l, family, &address);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = link_address_new(l, &a, family, &address);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning_errno(r, "Failed to process RTNL address message: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int manager_rtnl_listen(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering /* First, subscribe to interfaces coming and going */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_attach_event(m->rtnl, m->event, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Then, enumerate all links */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_request_dump(req, true);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_call(m->rtnl, req, 0, &reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = reply; i; i = sd_netlink_message_next(i)) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Finally, enumerate all addresses, too */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_request_dump(req, true);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_call(m->rtnl, req, 0, &reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = reply; i; i = sd_netlink_message_next(i)) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = manager_process_address(m->rtnl, i, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sd_network_monitor_flush(m->network_monitor);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning_errno(r, "Could not update resolv.conf: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int manager_network_monitor_listen(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_network_monitor_new(&m->network_monitor, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fd = sd_network_monitor_get_fd(m->network_monitor);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering events = sd_network_monitor_get_events(m->network_monitor);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
2d8950384f3137aafcce22b29912b2b61e6d86fbLennart Poettering _cleanup_free_ char *h = NULL, *n = NULL;
2d8950384f3137aafcce22b29912b2b61e6d86fbLennart Poettering const char *p;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Extract and normalize the first label of the locally
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * configured hostname, and check it's not "localhost". */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return log_error_errno(r, "Failed to unescape host name: %m");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_error("Couldn't find a single label in hosntame.");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering k = dns_label_undo_idna(label, r, label, sizeof(label));
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return log_error_errno(k, "Failed to undo IDNA: %m");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_error("System hostname is not UTF-8 clean.");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return log_error_errno(r, "Failed to escape host name: %m");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_debug("System hostname is 'localhost', ignoring.");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_name_concat(n, "local", mdns_hostname);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return log_error_errno(r, "Failed to determine mDNS hostname: %m");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = determine_hostname(&llmnr_hostname, &mdns_hostname);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return 0; /* ignore invalid hostnames */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_info("System hostname changed to '%s'.", llmnr_hostname);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poetteringstatic int manager_watch_hostname(Manager *m) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_warning_errno(errno, "Failed to watch hostname: %m");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering m->hostname_fd = safe_close(m->hostname_fd);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering return log_error_errno(r, "Failed to add hostname event source: %m");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_info("Defaulting to hostname 'linux'.");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering m->mdns_hostname = strdup("linux.local");
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering log_info("Using system hostname '%s'.", m->llmnr_hostname);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poetteringstatic int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering LIST_FOREACH(scopes, scope, m->dns_scopes)
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering _cleanup_(manager_freep) Manager *m = NULL;
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
bc7702b098b63031767174206f5df14a8ccb45cfDaniel Mack sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
dd0bc0f1414cc1d0fa73a29470bd14944e4942d3Lennart Poettering r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering sd_bus_slot_unref(m->prepare_for_sleep_slot);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering sd_event_source_unref(m->bus_retry_event_source);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen sd_event_source_unref(m->sigusr1_event_source);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering dns_resource_key_unref(m->llmnr_host_ipv4_key);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering dns_resource_key_unref(m->llmnr_host_ipv6_key);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering sd_event_source_unref(m->hostname_event_source);
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poetteringint manager_read_resolv_conf(Manager *m) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering /* Reads the system /etc/resolv.conf, if it exists and is not
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering * symlinked to our own resolv.conf instance */
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering /* Have we already seen the file? */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Is it symlinked to our own file? */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = log_error_errno(errno, "Failed to stat open file: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering FOREACH_LINE(line, f, r = -errno; goto clear) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *a;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = in_addr_from_string_auto(a, &family, &address);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning("Failed to parse name server %s.", a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Whenever /etc/resolv.conf changes, start using the first
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering * DNS server of it. This is useful to deal with broken
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering * network managing implementations (like NetworkManager),
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering * that when connecting to a VPN place both the VPN DNS
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering * servers and the local ones in /etc/resolv.conf. Without
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * resetting the DNS server to use back to the first entry we
2a1288ff89322a2f49c79f6d1832c8164c14a05cLennart Poettering * will continue to use the local one thus being unable to
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * resolve VPN domains. */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering manager_set_dns_server(m, m->dns_servers);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = in_addr_to_string(s->family, &s->address, &t);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fputs(" # Too many search domains configured, remaining ones ignored.", f);
86ad4cd709ced8daf2b75ab564dece1ce82ffed9Tom Gundersen fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "# Third party programs must not access this file directly, but\n"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "# only through the symlink at /etc/resolv.conf. To manage\n"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "# resolv.conf(5) in a different way, replace the symlink by a\n"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "# static file or a different symlink.\n\n", f);
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen write_resolv_conf_search(domain, f, &count, &length);
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen static const char path[] = "/run/systemd/resolve/resolv.conf";
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen /* Read the system /etc/resolv.conf first */
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen /* Add the full list to a set, to filter out duplicates */
deb3f3d335d64601bb2d8a7520d8303f99d8a071Lennart Poettering domains = ordered_set_new(&dns_name_hash_ops);
72290734be81e83e6ef9520c07692f68095eb5b2Tom Gundersen /* First add the system-wide servers */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Then, add the per-link servers and domains */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering LIST_FOREACH(servers, s, l->dns_servers) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen STRV_FOREACH(domain, l->unicast_scope->domains) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* If we found nothing, add the fallback servers */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = fopen_temporary_label(path, path, &f, &temp_path);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = write_resolv_conf_contents(f, dns, domains);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringint manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct cmsghdr header; /* For alignment */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering p->sender_port = be16toh(sa.in.sin_port);
e1c959948c0e31d6997bcdfbabfbd077784b2baeLennart Poettering p->sender_port = be16toh(sa.in6.sin6_port);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering } else if (cmsg->cmsg_level == IPPROTO_IP) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering /* The Linux kernel sets the interface index to the loopback
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering * device if the packet came from the local host since it
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering * avoids the routing table in such a case. Let's unset the
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering * interface index in such a case. */
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering /* If we don't know the interface index still, we look for the
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering * first local interface with a matching address. Yuck! */
556a22945fcc88ca27ae7ecc46c9bb2727e37895Lennart Poettering p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int write_loop(int fd, void *message, size_t length) {
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poetteringint manager_write(Manager *m, int fd, DnsPacket *p) {
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering r = write_loop(fd, DNS_PACKET_DATA(p), p->size);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poetteringstatic int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poetteringstatic int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering struct cmsghdr header; /* For alignment */
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poetteringint manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering log_debug("Sending %s packet with id %u on interface %i/%s", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family));
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart PoetteringDnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers)
9176a57c101d51b4a7fb4141240b5ce03abac57dLennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart PoetteringDnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart Poettering in_addr_to_string(s->family, &s->address, &ip);
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart Poettering log_info("Switching to system DNS server %s.", strna(ip));
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart Poettering dns_cache_flush(&m->unicast_scope->cache);
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart PoetteringDnsServer *manager_get_dns_server(Manager *m) {
c69fa7e3c44240bedc0ee1bd89fecf954783ac85Lennart Poettering /* Try to read updates resolv.conf */
59c5b5974d106c5ebad080739b41d0e92ab74d29Lennart Poettering manager_set_dns_server(m, m->dns_servers);
59c5b5974d106c5ebad080739b41d0e92ab74d29Lennart Poettering /* No DNS servers configured, let's see if there are
59c5b5974d106c5ebad080739b41d0e92ab74d29Lennart Poettering * any on any links. If not, we use the fallback
if (!found)
return m->current_dns_server;
assert(m);
if (!m->current_dns_server)
Link *l;
Iterator i;
if (l->mtu <= 0)
return mtu;
LinkAddress *a;
assert(m);
Iterator i;
Link *l;
assert(m);
link_add_rrs(l, true);
link_add_rrs(l, false);
uint64_t u, a;
assert(m);
assert(p);
while (p > m->llmnr_hostname) {
if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
random_bytes(&a, sizeof(a));
return -ENOMEM;
free(h);
log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
m->llmnr_hostname = h;
m->mdns_hostname = k;
LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
Iterator i;
Link *l;
assert(m);
LinkAddress *a;
return NULL;
assert(m);
assert(p);
Link *l;
assert(m);
assert(p);
return NULL;
return l->llmnr_ipv4_scope;
return l->llmnr_ipv6_scope;
return NULL;
DnsScope *s;
assert(m);
DnsServer *s;
assert(m);
if (t == DNS_SERVER_SYSTEM)
while (m->dns_servers) {
s = m->dns_servers;
dns_server_unref(s);
if (t == DNS_SERVER_FALLBACK)
while (m->fallback_dns_servers) {
s = m->fallback_dns_servers;
dns_server_unref(s);
assert(m);
if (m->llmnr_hostname) {
if (m->mdns_hostname)