/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include <net/if.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "dns-domain.h"
#include "escape.h"
+#include "format-util.h"
#include "gcrypt-util.h"
#include "in-addr-util.h"
#include "main-func.h"
STATUS_ALL,
STATUS_DNS,
STATUS_DOMAIN,
+ STATUS_DEFAULT_ROUTE,
STATUS_LLMNR,
STATUS_MDNS,
STATUS_PRIVATE,
STATUS_NTA,
} StatusMode;
-static int parse_ifindex_and_warn(const char *s) {
- int ifi;
-
- assert(s);
-
- if (parse_ifindex(s, &ifi) < 0) {
- ifi = if_nametoindex(s);
- if (ifi <= 0)
- return log_error_errno(errno, "Unknown interface '%s': %m", s);
- }
-
- return ifi;
-}
-
int ifname_mangle(const char *s) {
_cleanup_free_ char *iface = NULL;
const char *dot;
- int ifi;
+ int ifi, r;
assert(s);
if (!iface)
return log_oom();
- if (parse_ifindex(iface, &ifi) < 0) {
- ifi = if_nametoindex(iface);
- if (ifi <= 0) {
- if (errno == ENODEV && arg_ifindex_permissive) {
- log_debug("Interface '%s' not found, but -f specified, ignoring.", iface);
- return 0; /* done */
- }
-
- return log_error_errno(errno, "Unknown interface '%s': %m", iface);
+ r = parse_ifindex_or_ifname(iface, &ifi);
+ if (r < 0) {
+ if (r == -ENODEV && arg_ifindex_permissive) {
+ log_debug("Interface '%s' not found, but -f specified, ignoring.", iface);
+ return 0; /* done */
}
- }
- if (arg_ifindex > 0 && arg_ifindex != ifi) {
- log_error("Specified multiple different interfaces. Refusing.");
- return -EINVAL;
+ return log_error_errno(r, "Unknown interface '%s': %m", iface);
}
+ if (arg_ifindex > 0 && arg_ifindex != ifi)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing.");
+
arg_ifindex = ifi;
free_and_replace(arg_ifname, iface);
}
static void print_ifindex_comment(int printed_so_far, int ifindex) {
- char ifname[IF_NAMESIZE];
+ char ifname[IF_NAMESIZE + 1];
if (ifindex <= 0)
return;
- if (!if_indextoname(ifindex, ifname))
+ if (!format_ifname(ifindex, ifname))
log_warning_errno(errno, "Failed to resolve interface name for index %i, ignoring: %m", ifindex);
else
printf("%*s%s-- link: %s%s",
char **domains;
char **ntas;
bool dnssec_supported;
+ bool default_route;
};
static void link_info_clear(struct link_info *p) {
{ "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) },
{ "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) },
{ "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
+ { "DefaultRoute", "b", NULL, offsetof(struct link_info, default_route) },
{ "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
{ "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
{ "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) },
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(link_info_clear) struct link_info link_info = {};
_cleanup_free_ char *ifi = NULL, *p = NULL;
- char ifname[IF_NAMESIZE] = "";
+ char ifname[IF_NAMESIZE + 1] = "";
char **i;
int r;
assert(ifindex > 0);
if (!name) {
- if (!if_indextoname(ifindex, ifname))
+ if (!format_ifname(ifindex, ifname))
return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex);
name = ifname;
if (mode == STATUS_NTA)
return status_print_strv_ifindex(ifindex, name, link_info.ntas);
+ if (mode == STATUS_DEFAULT_ROUTE) {
+ printf("%sLink %i (%s)%s: %s\n",
+ ansi_highlight(), ifindex, name, ansi_normal(),
+ yes_no(link_info.default_route));
+
+ return 0;
+ }
+
if (mode == STATUS_LLMNR) {
printf("%sLink %i (%s)%s: %s\n",
ansi_highlight(), ifindex, name, ansi_normal(),
link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
- printf(" LLMNR setting: %s\n"
+ printf("DefaultRoute setting: %s\n"
+ " LLMNR setting: %s\n"
"MulticastDNS setting: %s\n"
" DNSOverTLS setting: %s\n"
" DNSSEC setting: %s\n"
" DNSSEC supported: %s\n",
+ yes_no(link_info.default_route),
strna(link_info.llmnr),
strna(link_info.mdns),
strna(link_info.dns_over_tls),
STRV_FOREACH(ifname, argv + 1) {
int ifindex;
- ifindex = parse_ifindex_and_warn(*ifname);
- if (ifindex < 0)
+ q = parse_ifindex_or_ifname(*ifname, &ifindex);
+ if (q < 0) {
+ log_error_errno(q, "Unknown interface '%s', ignoring: %m", *ifname);
continue;
+ }
q = status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line);
if (q < 0)
}
static int log_interface_is_managed(int r, int ifindex) {
- char ifname[IFNAMSIZ];
+ char ifname[IF_NAMESIZE + 1];
return log_error_errno(r,
"The specified interface %s is managed by systemd-networkd. Operation refused.\n"
"Please configure DNS settings for systemd-networkd managed interfaces directly in their .network files.",
- strna(if_indextoname(ifindex, ifname)));
+ strna(format_ifname(ifindex, ifname)));
}
static int verb_dns(int argc, char **argv, void *userdata) {
return 0;
}
+static int verb_default_route(int argc, char **argv, void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus = userdata;
+ int r, b;
+
+ assert(bus);
+
+ if (argc >= 2) {
+ r = ifname_mangle(argv[1]);
+ if (r < 0)
+ return r;
+ }
+
+ if (arg_ifindex <= 0)
+ return status_all(bus, STATUS_DEFAULT_ROUTE);
+
+ if (argc < 3)
+ return status_ifindex(bus, arg_ifindex, NULL, STATUS_DEFAULT_ROUTE, NULL);
+
+ b = parse_boolean(argv[2]);
+ if (b < 0)
+ return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.resolve1",
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ "SetLinkDefaultRoute",
+ &error,
+ NULL,
+ "ib", arg_ifindex, b);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
+ return log_interface_is_managed(r, arg_ifindex);
+
+ if (arg_ifindex_permissive &&
+ sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
+ return 0;
+
+ return log_error_errno(r, "Failed to set default route configuration: %s", bus_error_message(&error, r));
+ }
+
+ return 0;
+}
+
static int verb_llmnr(int argc, char **argv, void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
" reset-server-features Forget learnt DNS server feature levels\n"
" dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
" domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
+ " default-route [LINK [BOOL]] Get/set per-interface default route flag\n"
" llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
" mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
" dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
{ "reset-server-features", VERB_ANY, 1, 0, reset_server_features },
{ "dns", VERB_ANY, VERB_ANY, 0, verb_dns },
{ "domain", VERB_ANY, VERB_ANY, 0, verb_domain },
+ { "default-route", VERB_ANY, 3, 0, verb_default_route },
{ "llmnr", VERB_ANY, 3, 0, verb_llmnr },
{ "mdns", VERB_ANY, 3, 0, verb_mdns },
- { "dnsovertls", VERB_ANY, 3, 0, verb_dns_over_tls },
+ { "dnsovertls", VERB_ANY, 3, 0, verb_dns_over_tls },
{ "dnssec", VERB_ANY, 3, 0, verb_dnssec },
{ "nta", VERB_ANY, VERB_ANY, 0, verb_nta },
{ "revert", VERB_ANY, 2, 0, verb_revert_link },
int r;
setlocale(LC_ALL, "");
+ log_show_color(true);
log_parse_environment();
log_open();