resolved-link.c revision da927ba997d68401563b927f92e6e40e021a8e5c
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering/***
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering This file is part of systemd.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Copyright 2014 Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering (at your option) any later version.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering systemd is distributed in the hope that it will be useful, but
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering Lesser General Public License for more details.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering***/
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include <net/if.h>
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "sd-network.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "strv.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering#include "missing.h"
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering#include "resolved-link.h"
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint link_new(Manager *m, Link **ret, int ifindex) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_(link_freep) Link *l = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(m);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(ifindex > 0);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = hashmap_ensure_allocated(&m->links, NULL);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = new0(Link, 1);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return -ENOMEM;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->ifindex = ifindex;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support = SUPPORT_YES;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->manager = m;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (ret)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering *ret = l;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart PoetteringLink *link_free(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering while (l->addresses)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_address_free(l->addresses);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->manager)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_scope_free(l->unicast_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_scope_free(l->llmnr_ipv4_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_scope_free(l->llmnr_ipv6_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering while (l->dns_servers)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_server_free(l->dns_servers);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering free(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic void link_allocate_scopes(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->dns_servers) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->unicast_scope) {
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering if (r < 0)
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering log_warning_errno(r, "Failed to allocate DNS scope: %m");
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering }
1c7dd82563ff2e71a067aea20d2acb2d0553644bLennart Poettering } else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->unicast_scope = dns_scope_free(l->unicast_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (link_relevant(l, AF_INET) &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support != SUPPORT_NO &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->manager->llmnr_support != SUPPORT_NO) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->llmnr_ipv4_scope) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (link_relevant(l, AF_INET6) &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support != SUPPORT_NO &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->manager->llmnr_support != SUPPORT_NO &&
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering socket_ipv6_is_supported()) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->llmnr_ipv6_scope) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringvoid link_add_rrs(Link *l, bool force_remove) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LinkAddress *a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH(addresses, a, l->addresses)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_address_add_rrs(a, force_remove);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint link_update_rtnl(Link *l, sd_rtnl_message *m) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering const char *n = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(m);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = sd_rtnl_message_link_get_flags(m, &l->flags);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (sd_rtnl_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering strncpy(l->name, n, sizeof(l->name)-1);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char_array_0(l->name);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_allocate_scopes(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_add_rrs(l, false);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int link_update_dns_servers(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_strv_free_ char **nameservers = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering char **nameserver;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering DnsServer *s, *nx;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = sd_network_link_get_dns(l->ifindex, &nameservers);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto clear;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH(servers, s, l->dns_servers)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s->marked = true;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering STRV_FOREACH(nameserver, nameservers) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering union in_addr_union a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int family;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = in_addr_from_string_auto(*nameserver, &family, &a);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto clear;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s = link_find_dns_server(l, family, &a);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (s)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering s->marked = false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann goto clear;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (s->marked)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_server_free(s);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringclear:
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering while (l->dns_servers)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_server_free(l->dns_servers);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int link_update_llmnr_support(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *b = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = sd_network_link_get_llmnr(l->ifindex, &b);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto clear;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = parse_boolean(b);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (streq(b, "resolve"))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support = SUPPORT_RESOLVE;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering goto clear;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering } else if (r > 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support = SUPPORT_YES;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering else
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->llmnr_support = SUPPORT_NO;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringclear:
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann l->llmnr_support = SUPPORT_YES;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringstatic int link_update_domains(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering int r;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->unicast_scope)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering strv_free(l->unicast_scope->domains);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->unicast_scope->domains = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering r = sd_network_link_get_domains(l->ifindex,
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering &l->unicast_scope->domains);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (r < 0)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return r;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint link_update_monitor(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_update_dns_servers(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_update_llmnr_support(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_allocate_scopes(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_update_domains(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_add_rrs(l, false);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return 0;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringbool link_relevant(Link *l, int family) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *state = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LinkAddress *a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering /* A link is relevant if it isn't a loopback or pointopoint
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering * device, has a link beat, can do multicast and has at least
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering * one relevant IP address */
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering sd_network_link_get_operational_state(l->ifindex, &state);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH(addresses, a, l->addresses)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (a->family == family && link_address_relevant(a))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return true;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return false;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart PoetteringLinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LinkAddress *a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH(addresses, a, l->addresses)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart PoetteringDnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering DnsServer *s;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LIST_FOREACH(servers, s, l->dns_servers)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr))
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return s;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart PoetteringDnsServer* link_set_dns_server(Link *l, DnsServer *s) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->current_dns_server == s)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return s;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (s) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering _cleanup_free_ char *ip = NULL;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering in_addr_to_string(s->family, &s->address, &ip);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering l->current_dns_server = s;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->unicast_scope)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering dns_cache_flush(&l->unicast_scope->cache);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return s;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart PoetteringDnsServer *link_get_dns_server(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->current_dns_server)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_set_dns_server(l, l->dns_servers);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return l->current_dns_server;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringvoid link_next_dns_server(Link *l) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (!l->current_dns_server)
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering if (l->current_dns_server->servers_next) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_set_dns_server(l, l->current_dns_server->servers_next);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering return;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering }
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering link_set_dns_server(l, l->dns_servers);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering}
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poetteringint link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering LinkAddress *a;
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(l);
edce2aed3aa93b84f7b4c70412bdb665da2977b0Lennart Poettering assert(in_addr);
a = new0(LinkAddress, 1);
if (!a)
return -ENOMEM;
a->family = family;
a->in_addr = *in_addr;
a->link = l;
LIST_PREPEND(addresses, l->addresses, a);
if (ret)
*ret = a;
return 0;
}
LinkAddress *link_address_free(LinkAddress *a) {
if (!a)
return NULL;
if (a->link) {
LIST_REMOVE(addresses, a->link->addresses, a);
if (a->llmnr_address_rr) {
if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
}
if (a->llmnr_ptr_rr) {
if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
}
}
dns_resource_record_unref(a->llmnr_address_rr);
dns_resource_record_unref(a->llmnr_ptr_rr);
free(a);
return NULL;
}
void link_address_add_rrs(LinkAddress *a, bool force_remove) {
int r;
assert(a);
if (a->family == AF_INET) {
if (!force_remove &&
link_address_relevant(a) &&
a->link->llmnr_ipv4_scope &&
a->link->llmnr_support == SUPPORT_YES &&
a->link->manager->llmnr_support == SUPPORT_YES) {
if (!a->link->manager->host_ipv4_key) {
a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
if (!a->link->manager->host_ipv4_key) {
r = -ENOMEM;
goto fail;
}
}
if (!a->llmnr_address_rr) {
a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
}
a->llmnr_address_rr->a.in_addr = a->in_addr.in;
a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
}
if (!a->llmnr_ptr_rr) {
r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
if (r < 0)
goto fail;
a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
}
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
if (r < 0)
log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
if (r < 0)
log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
} else {
if (a->llmnr_address_rr) {
if (a->link->llmnr_ipv4_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
}
if (a->llmnr_ptr_rr) {
if (a->link->llmnr_ipv4_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
}
}
}
if (a->family == AF_INET6) {
if (!force_remove &&
link_address_relevant(a) &&
a->link->llmnr_ipv6_scope &&
a->link->llmnr_support == SUPPORT_YES &&
a->link->manager->llmnr_support == SUPPORT_YES) {
if (!a->link->manager->host_ipv6_key) {
a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
if (!a->link->manager->host_ipv6_key) {
r = -ENOMEM;
goto fail;
}
}
if (!a->llmnr_address_rr) {
a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
}
a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
}
if (!a->llmnr_ptr_rr) {
r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
if (r < 0)
goto fail;
a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
}
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
if (r < 0)
log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
if (r < 0)
log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
} else {
if (a->llmnr_address_rr) {
if (a->link->llmnr_ipv6_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
}
if (a->llmnr_ptr_rr) {
if (a->link->llmnr_ipv6_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
}
}
}
return;
fail:
log_debug_errno(r, "Failed to update address RRs: %m");
}
int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
int r;
assert(a);
assert(m);
r = sd_rtnl_message_addr_get_flags(m, &a->flags);
if (r < 0)
return r;
sd_rtnl_message_addr_get_scope(m, &a->scope);
link_allocate_scopes(a->link);
link_add_rrs(a->link, false);
return 0;
}
bool link_address_relevant(LinkAddress *a) {
assert(a);
if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
return false;
if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
return false;
return true;
}