diff options
Diffstat (limited to 'src/resolve/resolved-link.c')
-rw-r--r-- | src/resolve/resolved-link.c | 150 |
1 files changed, 121 insertions, 29 deletions
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 1e8f88024b..b203f19dbb 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -63,15 +63,27 @@ int link_new(Manager *m, Link **ret, int ifindex) { return 0; } +void link_flush_settings(Link *l) { + assert(l); + + l->llmnr_support = RESOLVE_SUPPORT_YES; + l->mdns_support = RESOLVE_SUPPORT_NO; + l->dnssec_mode = _DNSSEC_MODE_INVALID; + + dns_server_unlink_all(l->dns_servers); + dns_search_domain_unlink_all(l->search_domains); + + l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors); +} + Link *link_free(Link *l) { if (!l) return NULL; - dns_server_unlink_all(l->dns_servers); - dns_search_domain_unlink_all(l->search_domains); + link_flush_settings(l); while (l->addresses) - link_address_free(l->addresses); + (void) link_address_free(l->addresses); if (l->manager) hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex)); @@ -82,18 +94,17 @@ Link *link_free(Link *l) { dns_scope_free(l->mdns_ipv4_scope); dns_scope_free(l->mdns_ipv6_scope); - set_free_free(l->dnssec_negative_trust_anchors); - free(l); return NULL; } -static void link_allocate_scopes(Link *l) { +void link_allocate_scopes(Link *l) { int r; assert(l); - if (l->dns_servers) { + if (link_relevant(l, AF_UNSPEC, false) && + l->dns_servers) { if (!l->unicast_scope) { r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) @@ -102,7 +113,7 @@ static void link_allocate_scopes(Link *l) { } else l->unicast_scope = dns_scope_free(l->unicast_scope); - if (link_relevant(l, AF_INET) && + if (link_relevant(l, AF_INET, true) && l->llmnr_support != RESOLVE_SUPPORT_NO && l->manager->llmnr_support != RESOLVE_SUPPORT_NO) { if (!l->llmnr_ipv4_scope) { @@ -113,7 +124,7 @@ static void link_allocate_scopes(Link *l) { } else l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope); - if (link_relevant(l, AF_INET6) && + if (link_relevant(l, AF_INET6, true) && l->llmnr_support != RESOLVE_SUPPORT_NO && l->manager->llmnr_support != RESOLVE_SUPPORT_NO && socket_ipv6_is_supported()) { @@ -125,7 +136,7 @@ static void link_allocate_scopes(Link *l) { } else l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope); - if (link_relevant(l, AF_INET) && + if (link_relevant(l, AF_INET, true) && l->mdns_support != RESOLVE_SUPPORT_NO && l->manager->mdns_support != RESOLVE_SUPPORT_NO) { if (!l->mdns_ipv4_scope) { @@ -136,7 +147,7 @@ static void link_allocate_scopes(Link *l) { } else l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope); - if (link_relevant(l, AF_INET6) && + if (link_relevant(l, AF_INET6, true) && l->mdns_support != RESOLVE_SUPPORT_NO && l->manager->mdns_support != RESOLVE_SUPPORT_NO) { if (!l->mdns_ipv6_scope) { @@ -277,6 +288,26 @@ clear: return r; } +void link_set_dnssec_mode(Link *l, DnssecMode mode) { + + assert(l); + + if (l->dnssec_mode == mode) + return; + + if ((l->dnssec_mode == _DNSSEC_MODE_INVALID) || + (l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) || + (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) { + + /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the + * allow-downgrade mode to full DNSSEC mode, flush it too. */ + if (l->unicast_scope) + dns_cache_flush(&l->unicast_scope->cache); + } + + l->dnssec_mode = mode; +} + static int link_update_dnssec_mode(Link *l) { _cleanup_free_ char *m = NULL; DnssecMode mode; @@ -298,16 +329,7 @@ static int link_update_dnssec_mode(Link *l) { goto clear; } - if ((l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) || - (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) { - - /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the - * allow-downgrade mode to full DNSSEC mode, flush it too. */ - if (l->unicast_scope) - dns_cache_flush(&l->unicast_scope->cache); - } - - l->dnssec_mode = mode; + link_set_dnssec_mode(l, mode); return 0; @@ -395,11 +417,45 @@ clear: return r; } -int link_update_monitor(Link *l) { +static int link_is_unmanaged(Link *l) { + _cleanup_free_ char *state = NULL; + int r; + + assert(l); + + r = sd_network_link_get_setup_state(l->ifindex, &state); + if (r == -ENODATA) + return 1; + if (r < 0) + return r; + + return STR_IN_SET(state, "pending", "unmanaged"); +} + +static void link_read_settings(Link *l) { int r; assert(l); + /* Read settings from networkd, except when networkd is not managing this interface. */ + + r = link_is_unmanaged(l); + if (r < 0) { + log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name); + return; + } + if (r > 0) { + + /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */ + if (l->is_managed) + link_flush_settings(l); + + l->is_managed = false; + return; + } + + l->is_managed = true; + r = link_update_dns_servers(l); if (r < 0) log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name); @@ -423,35 +479,47 @@ int link_update_monitor(Link *l) { r = link_update_search_domains(l); if (r < 0) log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name); +} +int link_update_monitor(Link *l) { + assert(l); + + link_read_settings(l); link_allocate_scopes(l); link_add_rrs(l, false); return 0; } -bool link_relevant(Link *l, int family) { +bool link_relevant(Link *l, int family, bool multicast) { _cleanup_free_ char *state = NULL; LinkAddress *a; assert(l); - /* A link is relevant if it isn't a loopback or pointopoint - * device, has a link beat, can do multicast and has at least - * one relevant IP address */ + /* A link is relevant for multicast traffic if it isn't a loopback or pointopoint device, has a link beat, can + * do multicast and has at least one relevant IP address */ - if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT)) + if (l->flags & (IFF_LOOPBACK|IFF_DORMANT)) return false; - if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) + if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP)) return false; + if (multicast) { + if (l->flags & IFF_POINTOPOINT) + return false; + + if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST) + return false; + } + sd_network_link_get_operational_state(l->ifindex, &state); if (state && !STR_IN_SET(state, "unknown", "degraded", "routable")) return false; LIST_FOREACH(addresses, a, l->addresses) - if (a->family == family && link_address_relevant(a)) + if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a)) return true; return false; @@ -512,6 +580,30 @@ void link_next_dns_server(Link *l) { link_set_dns_server(l, l->dns_servers); } +DnssecMode link_get_dnssec_mode(Link *l) { + assert(l); + + if (l->dnssec_mode != _DNSSEC_MODE_INVALID) + return l->dnssec_mode; + + return manager_get_dnssec_mode(l->manager); +} + +bool link_dnssec_supported(Link *l) { + DnsServer *server; + + assert(l); + + if (link_get_dnssec_mode(l) == DNSSEC_NO) + return false; + + server = link_get_dns_server(l); + if (server) + return dns_server_dnssec_supported(server); + + return true; +} + int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) { LinkAddress *a; |