resolved-manager.c revision 9176a57c101d51b4a7fb4141240b5ce03abac57d
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_netlink_message_get_type(mm, &type);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_warning_errno(r, "Failed to process RTNL link message: %m");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_netlink_message_get_type(mm, &type);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_rtnl_message_addr_get_family(mm, &family);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_netlink_message_read_in_addr(mm, IFA_LOCAL, &address.in);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_netlink_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_netlink_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_netlink_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering a = link_find_address(l, family, &address);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = link_address_new(l, &a, family, &address);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* First, subscribe to interfaces coming and going */
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering r = sd_netlink_attach_event(m->rtnl, m->event, 0);
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart 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 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_netlink_message_request_dump(req, true);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek r = sd_netlink_call(m->rtnl, req, 0, &reply);
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering for (i = reply; i; i = sd_netlink_message_next(i)) {
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek reply = sd_netlink_message_unref(reply);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek /* Finally, enumerate all addresses, too */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek r = sd_netlink_message_request_dump(req, true);
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering r = sd_netlink_call(m->rtnl, req, 0, &reply);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek for (i = reply; i; i = sd_netlink_message_next(i)) {
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering r = manager_process_address(m->rtnl, i, m);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poetteringstatic int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek sd_network_monitor_flush(m->network_monitor);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering log_warning_errno(r, "Could not update resolv.conf: %m");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringstatic int manager_network_monitor_listen(Manager *m) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_network_monitor_new(&m->network_monitor, NULL);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fd = sd_network_monitor_get_fd(m->network_monitor);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering events = sd_network_monitor_get_events(m->network_monitor);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringstatic int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering _cleanup_free_ char *h = NULL, *n = NULL;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering const char *p;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Extract and normalize the first label of the locally
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering * configured hostname, and check it's not "localhost". */
fd0b4602f6332c3f1660eb208c8f5c719709a009Lennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return log_error_errno(r, "Failed to unescape host name: %m");
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering log_error("Couldn't find a single label in hosntame.");
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering k = dns_label_undo_idna(label, r, label, sizeof(label));
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering return log_error_errno(k, "Failed to undo IDNA: %m");
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poettering log_error("System hostname is not UTF-8 clean.");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return log_error_errno(r, "Failed to escape host name: %m");
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek log_debug("System hostname is 'localhost', ignoring.");
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek r = dns_name_concat(n, "local", mdns_hostname);
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to determine mDNS hostname: %m");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering r = determine_hostname(&llmnr_hostname, &mdns_hostname);
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering return 0; /* ignore invalid hostnames */
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek log_info("System hostname changed to '%s'.", llmnr_hostname);
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek m->llmnr_hostname = llmnr_hostname;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek m->mdns_hostname = mdns_hostname;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek llmnr_hostname = mdns_hostname = NULL;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekstatic int manager_watch_hostname(Manager *m) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_warning_errno(errno, "Failed to watch hostname: %m");
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek m->hostname_fd = safe_close(m->hostname_fd);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to add hostname event source: %m");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_info("Defaulting to hostname 'linux'.");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek m->llmnr_hostname = strdup("linux");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek m->mdns_hostname = strdup("linux.local");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_info("Using system hostname '%s'.", m->llmnr_hostname);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekstatic int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *buffer = NULL;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *f = NULL;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering LIST_FOREACH(scopes, scope, m->dns_scopes)
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering _cleanup_(manager_freep) Manager *m = NULL;
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poettering m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek sd_event_set_watchdog(m->event, true);
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek r = manager_network_monitor_listen(m);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering dns_server_unlink_all(m->fallback_dns_servers);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering dns_search_domain_unlink_all(m->search_domains);
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek dns_scope_free(m->unicast_scope);
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek hashmap_free(m->dns_transactions);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_event_source_unref(m->network_event_source);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_network_monitor_unref(m->network_monitor);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_event_source_unref(m->rtnl_event_source);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_bus_slot_unref(m->prepare_for_sleep_slot);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_event_source_unref(m->bus_retry_event_source);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek sd_event_source_unref(m->sigusr1_event_source);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek dns_resource_key_unref(m->llmnr_host_ipv4_key);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek dns_resource_key_unref(m->llmnr_host_ipv6_key);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering sd_event_source_unref(m->hostname_event_source);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poetteringint manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering struct cmsghdr header; /* For alignment */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering p->sender_port = be16toh(sa.in.sin_port);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering p->sender_port = be16toh(sa.in6.sin6_port);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering } else if (cmsg->cmsg_level == IPPROTO_IP) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
case IP_TTL:
p->ifindex = 0;
if (p->ifindex <= 0)
*ret = p;
p = NULL;
return -errno;
return -ETIMEDOUT;
return -errno;
return -ETIMEDOUT;
log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p));
static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
} control;
assert(m);
assert(p);
if (ifindex > 0) {
static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
} control;
assert(m);
assert(p);
if (ifindex > 0) {
int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
assert(m);
assert(p);
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));
return -EAFNOSUPPORT;
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);
assert(m);
if (m->llmnr_hostname) {
if (m->mdns_hostname)
DnsServer *s;
Iterator i;
Link *l;
assert(m);
if (r == -EEXIST)
if (r == -EEXIST)
if (r == -EEXIST)
DnsSearchDomain *d;
Iterator i;
Link *l;
assert(m);
if (r == -EEXIST)
if (r == -EEXIST)