/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <net/if.h>
-#include <stdio_ext.h>
+#include <linux/if.h>
+#include <unistd.h>
#include "sd-network.h"
#include "alloc-util.h"
+#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
-#include "missing.h"
+#include "log-link.h"
#include "mkdir.h"
#include "parse-util.h"
#include "resolved-link.h"
#include "resolved-llmnr.h"
#include "resolved-mdns.h"
+#include "socket-netlink.h"
#include "string-util.h"
#include "strv.h"
+#include "tmpfile-util.h"
int link_new(Manager *m, Link **ret, int ifindex) {
_cleanup_(link_freep) Link *l = NULL;
if (r < 0)
return r;
- l = new0(Link, 1);
+ l = new(Link, 1);
if (!l)
return -ENOMEM;
- l->ifindex = ifindex;
- l->llmnr_support = RESOLVE_SUPPORT_YES;
- l->mdns_support = RESOLVE_SUPPORT_NO;
- l->dnssec_mode = _DNSSEC_MODE_INVALID;
- l->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
- l->operstate = IF_OPER_UNKNOWN;
+ *l = (Link) {
+ .ifindex = ifindex,
+ .default_route = -1,
+ .llmnr_support = RESOLVE_SUPPORT_YES,
+ .mdns_support = RESOLVE_SUPPORT_NO,
+ .dnssec_mode = _DNSSEC_MODE_INVALID,
+ .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
+ .operstate = IF_OPER_UNKNOWN,
+ };
if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0)
return -ENOMEM;
void link_flush_settings(Link *l) {
assert(l);
+ l->default_route = -1;
l->llmnr_support = RESOLVE_SUPPORT_YES;
l->mdns_support = RESOLVE_SUPPORT_NO;
l->dnssec_mode = _DNSSEC_MODE_INVALID;
dns_scope_free(l->mdns_ipv6_scope);
free(l->state_file);
+ free(l->ifname);
return mfree(l);
}
(void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate);
if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
- strncpy(l->name, n, sizeof(l->name)-1);
- char_array_0(l->name);
+ r = free_and_strdup(&l->ifname, n);
+ if (r < 0)
+ return r;
}
link_allocate_scopes(l);
return 0;
}
-static int link_update_dns_server_one(Link *l, const char *name) {
+static int link_update_dns_server_one(Link *l, const char *str) {
+ _cleanup_free_ char *name = NULL;
+ int family, ifindex, r;
union in_addr_union a;
DnsServer *s;
- int family, r;
+ uint16_t port;
assert(l);
- assert(name);
+ assert(str);
- r = in_addr_from_string_auto(name, &family, &a);
+ r = in_addr_port_ifindex_name_from_string_auto(str, &family, &a, &port, &ifindex, &name);
if (r < 0)
return r;
- s = dns_server_find(l->dns_servers, family, &a, 0);
+ if (ifindex != 0 && ifindex != l->ifindex)
+ return -EINVAL;
+
+ /* By default, the port number is determined with the transaction feature level.
+ * See dns_transaction_port() and dns_server_port(). */
+ if (IN_SET(port, 53, 853))
+ port = 0;
+
+ s = dns_server_find(l->dns_servers, family, &a, port, 0, name);
if (s) {
dns_server_move_back_and_unmark(s);
return 0;
}
- return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0);
+ return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name);
}
static int link_update_dns_servers(Link *l) {
return r;
}
+static int link_update_default_route(Link *l) {
+ int r;
+
+ assert(l);
+
+ r = sd_network_link_get_dns_default_route(l->ifindex);
+ if (r == -ENODATA) {
+ r = 0;
+ goto clear;
+ }
+ if (r < 0)
+ goto clear;
+
+ l->default_route = r > 0;
+ return 0;
+
+clear:
+ l->default_route = -1;
+ return r;
+}
+
static int link_update_llmnr_support(Link *l) {
_cleanup_free_ char *b = NULL;
int r;
#if ! ENABLE_DNS_OVER_TLS
if (mode != DNS_OVER_TLS_NO)
- log_warning("DNS-over-TLS option for the link cannot be set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support.");
+ log_warning("DNS-over-TLS option for the link cannot be enabled or set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support.");
return;
#endif
if (!ns)
return -ENOMEM;
- r = set_put_strdupv(ns, ntas);
+ r = set_put_strdupv(&ns, ntas);
if (r < 0)
return r;
r = link_is_managed(l);
if (r < 0) {
- log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to determine whether the interface is managed: %m");
return;
}
if (r == 0) {
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);
+ log_link_warning_errno(l, r, "Failed to read DNS servers for the interface, ignoring: %m");
r = link_update_llmnr_support(l);
if (r < 0)
- log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read LLMNR support for the interface, ignoring: %m");
r = link_update_mdns_support(l);
if (r < 0)
- log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read mDNS support for the interface, ignoring: %m");
r = link_update_dns_over_tls_mode(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNS-over-TLS mode for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNS-over-TLS mode for the interface, ignoring: %m");
r = link_update_dnssec_mode(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNSSEC mode for the interface, ignoring: %m");
r = link_update_dnssec_negative_trust_anchors(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNSSEC negative trust anchors for the interface, ignoring: %m");
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);
+ log_link_warning_errno(l, r, "Failed to read search domains for the interface, ignoring: %m");
+
+ r = link_update_default_route(l);
+ if (r < 0)
+ log_link_warning_errno(l, r, "Failed to read default route setting for the interface, proceeding anyway: %m");
}
int link_update(Link *l) {
assert(l);
link_read_settings(l);
- link_load_user(l);
+ r = link_load_user(l);
+ if (r < 0)
+ return r;
if (l->llmnr_support != RESOLVE_SUPPORT_NO) {
r = manager_llmnr_start(l->manager);
return false;
(void) sd_network_link_get_operational_state(l->ifindex, &state);
- if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
+ if (state && !STR_IN_SET(state, "unknown", "degraded", "degraded-carrier", "routable"))
return false;
LIST_FOREACH(addresses, a, l->addresses)
return s;
if (s)
- log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
+ log_debug("Switching to DNS server %s for interface %s.", strna(dns_server_string_full(s)), l->ifname);
dns_server_unref(l->current_dns_server);
l->current_dns_server = dns_server_ref(s);
if (l->llmnr_support != RESOLVE_SUPPORT_YES ||
l->mdns_support != RESOLVE_SUPPORT_NO ||
- l->dnssec_mode != _DNSSEC_MODE_INVALID)
+ l->dnssec_mode != _DNSSEC_MODE_INVALID ||
+ l->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
return true;
if (l->dns_servers ||
if (!set_isempty(l->dnssec_negative_trust_anchors))
return true;
+ if (l->default_route >= 0)
+ return true;
+
return false;
}
if (r < 0)
goto fail;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
(void) fchmod(fileno(f), 0644);
fputs("# This is private data. Do not parse.\n", f);
if (v)
fprintf(f, "DNSSEC=%s\n", v);
+ if (l->default_route >= 0)
+ fprintf(f, "DEFAULT_ROUTE=%s\n", yes_no(l->default_route));
+
if (l->dns_servers) {
DnsServer *server;
if (server != l->dns_servers)
fputc(' ', f);
- v = dns_server_string(server);
+ v = dns_server_string_full(server);
if (!v) {
r = -ENOMEM;
goto fail;
*dnssec = NULL,
*servers = NULL,
*domains = NULL,
- *ntas = NULL;
+ *ntas = NULL,
+ *default_route = NULL;
ResolveSupport s;
const char *p;
"DNSSEC", &dnssec,
"SERVERS", &servers,
"DOMAINS", &domains,
- "NTAS", &ntas);
+ "NTAS", &ntas,
+ "DEFAULT_ROUTE", &default_route);
if (r == -ENOENT)
return 0;
if (r < 0)
if (s >= 0)
l->mdns_support = s;
+ r = parse_boolean(default_route);
+ if (r >= 0)
+ l->default_route = r;
+
/* If we can't recognize the DNSSEC setting, then set it to invalid, so that the daemon default is used. */
l->dnssec_mode = dnssec_mode_from_string(dnssec);