resolved-link.c revision bda2c408f8a739c19161818bcc842107f60652a2
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Lennart Poettering
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/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint link_new(Manager *m, Link **ret, int ifindex) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = hashmap_ensure_allocated(&m->links, NULL, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void link_allocate_scopes(Link *l) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering log_warning("Failed to allocate DNS scope: %s", strerror(-r));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l->unicast_scope = dns_scope_free(l->unicast_scope);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l->manager->llmnr_support != SUPPORT_NO) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l->manager->llmnr_support != SUPPORT_NO &&
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringvoid link_add_rrs(Link *l, bool force_remove) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mackint link_update_rtnl(Link *l, sd_rtnl_message *m) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack const char *n = NULL;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack r = sd_rtnl_message_link_get_flags(m, &l->flags);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int link_update_dns_servers(Link *l) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering _cleanup_strv_free_ char **nameservers = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_network_link_get_dns(l->ifindex, &nameservers);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering r = in_addr_from_string_auto(*nameserver, &family, &a);
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersenstatic int link_update_llmnr_support(Link *l) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_network_link_get_llmnr(l->ifindex, &b);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering } else if (r > 0)
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering r = sd_network_link_get_domains(l->ifindex,
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering /* A link is relevant if it isn't a loopback or pointopoint
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen * device, has a link beat, can do multicast and has at least
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering * one relevant IP address */
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering sd_network_link_get_operational_state(l->ifindex, &state);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (a->family == family && link_address_relevant(a))
bda2c408f8a739c19161818bcc842107f60652a2Tom GundersenLinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart PoetteringDnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart PoetteringDnsServer* link_set_dns_server(Link *l, DnsServer *s) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering in_addr_to_string(s->family, &s->address, &ip);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_cache_flush(&l->unicast_scope->cache);
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering if (l->current_dns_server->servers_next) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering link_set_dns_server(l, l->current_dns_server->servers_next);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringint link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering LIST_PREPEND(addresses, l->addresses, a);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart PoetteringLinkAddress *link_address_free(LinkAddress *a) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering LIST_REMOVE(addresses, a->link->addresses, a);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_resource_record_unref(a->llmnr_address_rr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering dns_resource_record_unref(a->llmnr_ptr_rr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringvoid link_address_add_rrs(LinkAddress *a, bool force_remove) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a->link->manager->llmnr_support == SUPPORT_YES) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering a->llmnr_address_rr->a.in_addr = a->in_addr.in;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering log_warning("Failed to add A record to LLMNR zone: %s", strerror(-r));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->link->manager->llmnr_support == SUPPORT_YES) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_debug("Failed to update address RRs: %s", strerror(-r));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringint link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_rtnl_message_addr_get_flags(m, &a->flags);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering sd_rtnl_message_addr_get_scope(m, &a->scope);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))