resolved-link.c revision 0eac462399c8e87bcce252cf058eba9f2678f2bd
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2014 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringint link_new(Manager *m, Link **ret, int ifindex) {
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering r = hashmap_ensure_allocated(&m->links, NULL);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic void link_allocate_scopes(Link *l) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering log_warning_errno(r, "Failed to allocate DNS scope: %m");
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen l->unicast_scope = dns_scope_free(l->unicast_scope);
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering l->manager->llmnr_support != SUPPORT_NO) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering l->manager->llmnr_support != SUPPORT_NO &&
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringvoid link_add_rrs(Link *l, bool force_remove) {
25d042e81516246b1ebf706a57c47ac19abb0b8aLennart Poetteringint link_update_rtnl(Link *l, sd_netlink_message *m) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const char *n = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_rtnl_message_link_get_flags(m, &l->flags);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poetteringstatic int link_update_dns_servers(Link *l) {
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering _cleanup_strv_free_ char **nameservers = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_network_link_get_dns(l->ifindex, &nameservers);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = in_addr_from_string_auto(*nameserver, &family, &a);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int link_update_llmnr_support(Link *l) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_network_link_get_llmnr(l->ifindex, &b);
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek } else if (r > 0)
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek l->llmnr_support = SUPPORT_YES;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering l->unicast_scope->domains = strv_free(l->unicast_scope->domains);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_network_link_get_domains(l->ifindex,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering /* A link is relevant if it isn't a loopback or pointopoint
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * device, has a link beat, can do multicast and has at least
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering * one relevant IP address */
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering sd_network_link_get_operational_state(l->ifindex, &state);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (a->family == family && link_address_relevant(a))
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart PoetteringLinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringvoid link_flush_marked_dns_servers(Link *l) {
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering LIST_FOREACH_SAFE(servers, s, next, l->dns_servers) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart PoetteringDnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr))
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-SzmekDnsServer* link_set_dns_server(Link *l, DnsServer *s) {
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering in_addr_to_string(s->family, &s->address, &ip);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering l->current_dns_server = dns_server_ref(s);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering dns_cache_flush(&l->unicast_scope->cache);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering /* Change to the next one, but make sure to follow the linked
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering * list only if this server is actually still linked. */
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering link_set_dns_server(l, l->current_dns_server->servers_next);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poetteringint link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering LIST_PREPEND(addresses, l->addresses, a);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart PoetteringLinkAddress *link_address_free(LinkAddress *a) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering LIST_REMOVE(addresses, a->link->addresses, a);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen dns_resource_record_unref(a->llmnr_address_rr);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering dns_resource_record_unref(a->llmnr_ptr_rr);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmekvoid link_address_add_rrs(LinkAddress *a, bool force_remove) {
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering a->link->manager->llmnr_support == SUPPORT_YES) {
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (!a->link->manager->llmnr_host_ipv4_key) {
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (!a->link->manager->llmnr_host_ipv4_key) {
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek a->llmnr_address_rr->a.in_addr = a->in_addr.in;
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->link->manager->llmnr_support == SUPPORT_YES) {
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering if (!a->link->manager->llmnr_host_ipv6_key) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (!a->link->manager->llmnr_host_ipv6_key) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen log_debug_errno(r, "Failed to update address RRs: %m");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringint link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = sd_rtnl_message_addr_get_flags(m, &a->flags);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering sd_rtnl_message_addr_get_scope(m, &a->scope);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poetteringbool link_address_relevant(LinkAddress *a) {
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))