resolved-link.c revision 2e1bab34bdb1a5e849060afa8361b865ce39f87f
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering This file is part of systemd.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Copyright 2014 Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is free software; you can redistribute it and/or modify it
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering under the terms of the GNU Lesser General Public License as published by
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering (at your option) any later version.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is distributed in the hope that it will be useful, but
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Lesser General Public License for more details.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering You should have received a copy of the GNU Lesser General Public License
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint link_new(Manager *m, Link **ret, int ifindex) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = hashmap_ensure_allocated(&m->links, NULL);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_search_domain_unlink_all(l->search_domains);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering set_free_free(l->dnssec_negative_trust_anchors);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic void link_allocate_scopes(Link *l) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to allocate DNS scope: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->unicast_scope = dns_scope_free(l->unicast_scope);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->llmnr_support != RESOLVE_SUPPORT_NO &&
baed47c3c20512507e497058d388782400a072f6Lennart Poettering l->manager->llmnr_support != RESOLVE_SUPPORT_NO) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
baed47c3c20512507e497058d388782400a072f6Lennart Poettering l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->llmnr_support != RESOLVE_SUPPORT_NO &&
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->manager->llmnr_support != RESOLVE_SUPPORT_NO &&
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
baed47c3c20512507e497058d388782400a072f6Lennart Poettering l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringvoid link_add_rrs(Link *l, bool force_remove) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint link_update_rtnl(Link *l, sd_netlink_message *m) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *n = NULL;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_rtnl_message_link_get_flags(m, &l->flags);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic int link_update_dns_servers(Link *l) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering _cleanup_strv_free_ char **nameservers = NULL;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = sd_network_link_get_dns(l->ifindex, &nameservers);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering r = in_addr_from_string_auto(*nameserver, &family, &a);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering s = dns_server_find(l->dns_servers, family, &a);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_server_unlink_marked(l->dns_servers);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int link_update_llmnr_support(Link *l) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_network_link_get_llmnr(l->ifindex, &b);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->llmnr_support = resolve_support_from_string(b);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int link_update_mdns_support(Link *l) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_network_link_get_mdns(l->ifindex, &b);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->mdns_support = resolve_support_from_string(b);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int link_update_dnssec_mode(Link *l) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = sd_network_link_get_dnssec(l->ifindex, &m);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if ((l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) ||
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * allow-downgrade mode to full DNSSEC mode, flush it too. */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_cache_flush(&l->unicast_scope->cache);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int link_update_dnssec_negative_trust_anchors(Link *l) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering set_free_free(l->dnssec_negative_trust_anchors);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int link_update_search_domains(Link *l) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering _cleanup_strv_free_ char **domains = NULL;
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = sd_network_link_get_domains(l->ifindex, &domains);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* networkd knows nothing about this interface, and that's fine. */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_search_domain_mark_all(l->search_domains);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = dns_search_domain_find(l->search_domains, *i, &d);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_search_domain_move_back_and_unmark(d);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering dns_search_domain_unlink_marked(l->search_domains);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering dns_search_domain_unlink_all(l->search_domains);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering r = link_update_dnssec_negative_trust_anchors(l);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
72fbdd3349ad30d8a5074ea9a650f0909f96c299Lennart Poettering log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* A link is relevant if it isn't a loopback or pointopoint
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * device, has a link beat, can do multicast and has at least
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * one relevant IP address */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering sd_network_link_get_operational_state(l->ifindex, &state);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (a->family == family && link_address_relevant(a))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart PoetteringLinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart PoetteringDnsServer* link_set_dns_server(Link *l, DnsServer *s) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering l->current_dns_server = dns_server_ref(s);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering dns_cache_flush(&l->unicast_scope->cache);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering /* Change to the next one, but make sure to follow the linked
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering * list only if this server is actually still linked. */
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering link_set_dns_server(l, l->current_dns_server->servers_next);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poetteringint link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering LIST_PREPEND(addresses, l->addresses, a);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart PoetteringLinkAddress *link_address_free(LinkAddress *a) {
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering LIST_REMOVE(addresses, a->link->addresses, a);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
89fef99014662a5a63e7deaedd6292b7fb4ab2f8Lennart Poettering if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
free(a);
return NULL;
assert(a);
if (!force_remove &&
link_address_relevant(a) &&
a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
r = -ENOMEM;
goto fail;
if (!a->llmnr_address_rr) {
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
if (!a->llmnr_ptr_rr) {
r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
goto fail;
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
if (a->llmnr_address_rr) {
if (a->llmnr_ptr_rr) {
if (!force_remove &&
link_address_relevant(a) &&
a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
r = -ENOMEM;
goto fail;
if (!a->llmnr_address_rr) {
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
if (!a->llmnr_ptr_rr) {
r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
goto fail;
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
if (a->llmnr_address_rr) {
if (a->llmnr_ptr_rr) {
fail:
assert(a);
assert(m);
assert(a);