resolve: extend systemd-resolve so that it can push per-interface DNS configuration into systemd-resolved (#7576)
This is useful to debug things, but also to hook up external post-up scripts with resolved. Eventually this code might be useful to implement a resolvconf(8)-compatible interface for compatibility purposes. Since the semantics don't map entirely cleanly as first step we add a native interface for pushing DNS configuration into resolved, that exposes the correct semantics, before adding any compatibility interface. See: #7202
This commit is contained in:
parent
fbd0b64f44
commit
14965b94f2
|
@ -321,6 +321,48 @@
|
||||||
<listitem><para>Shows the global and per-link DNS settings in currently in effect.</para></listitem>
|
<listitem><para>Shows the global and per-link DNS settings in currently in effect.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--set-dns=SERVER</option></term>
|
||||||
|
<term><option>--set-domain=DOMAIN</option></term>
|
||||||
|
<term><option>--set-llmnr=MODE</option></term>
|
||||||
|
<term><option>--set-mdns=MODE</option></term>
|
||||||
|
<term><option>--set-dnssec=MODE</option></term>
|
||||||
|
<term><option>--set-nta=DOMAIN</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Set per-interface DNS configuration. These switches may be used to configure various DNS
|
||||||
|
settings for network interfaces that aren't managed by
|
||||||
|
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. (These
|
||||||
|
commands will fail when used on interfaces that are managed by <command>systemd-networkd</command>, please
|
||||||
|
configure their DNS settings directly inside the <filename>.network</filename> files instead.) These switches
|
||||||
|
may be used to inform <command>systemd-resolved</command> about per-interface DNS configuration determined
|
||||||
|
through external means. Multiple of these switches may be passed on a single invocation of
|
||||||
|
<command>systemd-resolve</command> in order to set multiple configuration options at once. If any of these
|
||||||
|
switches is used, it must be combined with <option>--interface=</option> to indicate the network interface the
|
||||||
|
new DNS configuration belongs to. The <option>--set-dns=</option> option expects an IPv4 or IPv6 address
|
||||||
|
specification of a DNS server to use, and may be used multiple times to define multiple servers for the same
|
||||||
|
interface. The <option>--set-domain=</option> option expects a valid DNS domain, possibly prefixed with
|
||||||
|
<literal>~</literal>, and configures a per-interface search or route-only domain. It may be used multiple times
|
||||||
|
to configure multiple such domains. The <option>--set-llmnr=</option>, <option>--set-mdns=</option> and
|
||||||
|
<option>--set-dnssec=</option> options may be used to configure the per-interface LLMNR, MulticastDNS and
|
||||||
|
DNSSEC settings. Finally, <option>--set-nta=</option> may be used to configure additional per-interface DNSSEC
|
||||||
|
NTA domains and may also be used multiple times. For details about these settings, their possible values and
|
||||||
|
their effect, see the corresponding options in
|
||||||
|
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--revert</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Revert the per-interface DNS configuration. This option must be combined with
|
||||||
|
<option>--interface=</option> to indicate the network interface the DNS configuration shall be reverted on. If
|
||||||
|
the DNS configuration is reverted all per-interface DNS setting are reset to their defaults, undoing all
|
||||||
|
effects of <option>--set-dns=</option>, <option>--set-domain=</option>, <option>--set-llmnr=</option>,
|
||||||
|
<option>--set-mdns=</option>, <option>--set-dnssec=</option>, <option>--set-nta=</option>. Note that when a
|
||||||
|
network interface disappears all configuration is lost automatically, an explicit reverting is not necessary in
|
||||||
|
that case.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<xi:include href="standard-options.xml" xpointer="help" />
|
<xi:include href="standard-options.xml" xpointer="help" />
|
||||||
<xi:include href="standard-options.xml" xpointer="version" />
|
<xi:include href="standard-options.xml" xpointer="version" />
|
||||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||||
|
@ -403,8 +445,9 @@ _443._tcp.fedoraproject.org IN TLSA 0 0 1 19400be5b7a31fb733917700789d2f0a2471c0
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
<para>
|
<para>
|
||||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>systemd.dnssd</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>systemd.dnssd</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||||
|
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
|
@ -26,8 +26,10 @@
|
||||||
|
|
||||||
#include "af-list.h"
|
#include "af-list.h"
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "bus-common-errors.h"
|
||||||
#include "bus-error.h"
|
#include "bus-error.h"
|
||||||
#include "bus-util.h"
|
#include "bus-util.h"
|
||||||
|
#include "dns-domain.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "gcrypt-util.h"
|
#include "gcrypt-util.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
|
@ -75,8 +77,18 @@ static enum {
|
||||||
MODE_FLUSH_CACHES,
|
MODE_FLUSH_CACHES,
|
||||||
MODE_RESET_SERVER_FEATURES,
|
MODE_RESET_SERVER_FEATURES,
|
||||||
MODE_STATUS,
|
MODE_STATUS,
|
||||||
|
MODE_SET_LINK,
|
||||||
|
MODE_REVERT_LINK,
|
||||||
} arg_mode = MODE_RESOLVE_HOST;
|
} arg_mode = MODE_RESOLVE_HOST;
|
||||||
|
|
||||||
|
static struct in_addr_data *arg_set_dns = NULL;
|
||||||
|
static size_t arg_n_set_dns = 0;
|
||||||
|
static char **arg_set_domain = NULL;
|
||||||
|
static char *arg_set_llmnr = NULL;
|
||||||
|
static char *arg_set_mdns = NULL;
|
||||||
|
static char *arg_set_dnssec = NULL;
|
||||||
|
static char **arg_set_nta = NULL;
|
||||||
|
|
||||||
static ServiceFamily service_family_from_string(const char *s) {
|
static ServiceFamily service_family_from_string(const char *s) {
|
||||||
if (s == NULL || streq(s, "tcp"))
|
if (s == NULL || streq(s, "tcp"))
|
||||||
return SERVICE_FAMILY_TCP;
|
return SERVICE_FAMILY_TCP;
|
||||||
|
@ -1545,6 +1557,234 @@ static int status_all(sd_bus *bus) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_link(sd_bus *bus) {
|
||||||
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
int r = 0, q;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
|
||||||
|
if (arg_n_set_dns > 0) {
|
||||||
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
q = sd_bus_message_new_method_call(
|
||||||
|
bus,
|
||||||
|
&req,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkDNS");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append(req, "i", arg_ifindex);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_open_container(req, 'a', "(iay)");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
for (i = 0; i < arg_n_set_dns; i++) {
|
||||||
|
q = sd_bus_message_open_container(req, 'r', "iay");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append(req, "i", arg_set_dns[i].family);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append_array(req, 'y', &arg_set_dns[i].address, FAMILY_ADDRESS_SIZE(arg_set_dns[i].family));
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_close_container(req);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = sd_bus_message_close_container(req);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_call(bus, req, 0, &error, NULL);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set DNS configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strv_isempty(arg_set_domain)) {
|
||||||
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
|
||||||
|
char **p;
|
||||||
|
|
||||||
|
q = sd_bus_message_new_method_call(
|
||||||
|
bus,
|
||||||
|
&req,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkDomains");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append(req, "i", arg_ifindex);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_open_container(req, 'a', "(sb)");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
STRV_FOREACH(p, arg_set_domain) {
|
||||||
|
const char *n;
|
||||||
|
|
||||||
|
n = **p == '~' ? *p + 1 : *p;
|
||||||
|
q = sd_bus_message_append(req, "(sb)", n, **p == '~');
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = sd_bus_message_close_container(req);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_call(bus, req, 0, &error, NULL);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set domain configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_set_llmnr) {
|
||||||
|
q = sd_bus_call_method(bus,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkLLMNR",
|
||||||
|
&error,
|
||||||
|
NULL,
|
||||||
|
"is", arg_ifindex, arg_set_llmnr);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set LLMNR configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_set_mdns) {
|
||||||
|
q = sd_bus_call_method(bus,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkMulticastDNS",
|
||||||
|
&error,
|
||||||
|
NULL,
|
||||||
|
"is", arg_ifindex, arg_set_mdns);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_set_dnssec) {
|
||||||
|
q = sd_bus_call_method(bus,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkDNSSEC",
|
||||||
|
&error,
|
||||||
|
NULL,
|
||||||
|
"is", arg_ifindex, arg_set_dnssec);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set DNSSEC configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strv_isempty(arg_set_nta)) {
|
||||||
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
|
||||||
|
|
||||||
|
q = sd_bus_message_new_method_call(
|
||||||
|
bus,
|
||||||
|
&req,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"SetLinkDNSSECNegativeTrustAnchors");
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append(req, "i", arg_ifindex);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_message_append_strv(req, arg_set_nta);
|
||||||
|
if (q < 0)
|
||||||
|
return bus_log_create_error(q);
|
||||||
|
|
||||||
|
q = sd_bus_call(bus, req, 0, &error, NULL);
|
||||||
|
if (q < 0) {
|
||||||
|
if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
|
||||||
|
goto is_managed;
|
||||||
|
|
||||||
|
log_error_errno(q, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error, q));
|
||||||
|
if (r == 0)
|
||||||
|
r = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
is_managed:
|
||||||
|
{
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
|
||||||
|
return log_error_errno(q,
|
||||||
|
"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(arg_ifindex, ifname)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int revert_link(sd_bus *bus) {
|
||||||
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
|
||||||
|
r = sd_bus_call_method(bus,
|
||||||
|
"org.freedesktop.resolve1",
|
||||||
|
"/org/freedesktop/resolve1",
|
||||||
|
"org.freedesktop.resolve1.Manager",
|
||||||
|
"RevertLink",
|
||||||
|
&error,
|
||||||
|
NULL,
|
||||||
|
"i", arg_ifindex);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void help_protocol_types(void) {
|
static void help_protocol_types(void) {
|
||||||
if (arg_legend)
|
if (arg_legend)
|
||||||
puts("Known protocol types:");
|
puts("Known protocol types:");
|
||||||
|
@ -1610,6 +1850,13 @@ static void help(void) {
|
||||||
" --flush-caches Flush all local DNS caches\n"
|
" --flush-caches Flush all local DNS caches\n"
|
||||||
" --reset-server-features\n"
|
" --reset-server-features\n"
|
||||||
" Forget learnt DNS server feature levels\n"
|
" Forget learnt DNS server feature levels\n"
|
||||||
|
" --set-dns=SERVER Set per-interface DNS server address\n"
|
||||||
|
" --set-domain=DOMAIN Set per-interface search domain\n"
|
||||||
|
" --set-llmnr=MODE Set per-interface LLMNR mode\n"
|
||||||
|
" --set-mdns=MODE Set per-interface MulticastDNS mode\n"
|
||||||
|
" --set-dnssec=MODE Set per-interface DNSSEC mode\n"
|
||||||
|
" --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
|
||||||
|
" --revert Revert per-interface configuration\n"
|
||||||
, program_invocation_short_name);
|
, program_invocation_short_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,6 +1878,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_FLUSH_CACHES,
|
ARG_FLUSH_CACHES,
|
||||||
ARG_RESET_SERVER_FEATURES,
|
ARG_RESET_SERVER_FEATURES,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
|
ARG_SET_DNS,
|
||||||
|
ARG_SET_DOMAIN,
|
||||||
|
ARG_SET_LLMNR,
|
||||||
|
ARG_SET_MDNS,
|
||||||
|
ARG_SET_DNSSEC,
|
||||||
|
ARG_SET_NTA,
|
||||||
|
ARG_REVERT_LINK,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -1655,6 +1909,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
|
{ "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
|
||||||
{ "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
|
{ "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
|
{ "set-dns", required_argument, NULL, ARG_SET_DNS },
|
||||||
|
{ "set-domain", required_argument, NULL, ARG_SET_DOMAIN },
|
||||||
|
{ "set-llmnr", required_argument, NULL, ARG_SET_LLMNR },
|
||||||
|
{ "set-mdns", required_argument, NULL, ARG_SET_MDNS },
|
||||||
|
{ "set-dnssec", required_argument, NULL, ARG_SET_DNSSEC },
|
||||||
|
{ "set-nta", required_argument, NULL, ARG_SET_NTA },
|
||||||
|
{ "revert", no_argument, NULL, ARG_REVERT_LINK },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1850,6 +2111,84 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_no_pager = true;
|
arg_no_pager = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_SET_DNS: {
|
||||||
|
struct in_addr_data data, *n;
|
||||||
|
|
||||||
|
r = in_addr_from_string_auto(optarg, &data.family, &data.address);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse DNS server address: %s", optarg);
|
||||||
|
|
||||||
|
n = realloc(arg_set_dns, sizeof(struct in_addr_data) * (arg_n_set_dns + 1));
|
||||||
|
if (!n)
|
||||||
|
return log_oom();
|
||||||
|
arg_set_dns = n;
|
||||||
|
|
||||||
|
arg_set_dns[arg_n_set_dns++] = data;
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ARG_SET_DOMAIN: {
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
p = optarg[0] == '~' ? optarg + 1 : optarg;
|
||||||
|
|
||||||
|
r = dns_name_is_valid(p);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to validate specified domain %s: %m", p);
|
||||||
|
if (r == 0)
|
||||||
|
return log_error_errno(r, "Domain not valid: %s", p);
|
||||||
|
|
||||||
|
r = strv_extend(&arg_set_domain, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ARG_SET_LLMNR:
|
||||||
|
r = free_and_strdup(&arg_set_llmnr, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_SET_MDNS:
|
||||||
|
r = free_and_strdup(&arg_set_mdns, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_SET_DNSSEC:
|
||||||
|
r = free_and_strdup(&arg_set_dnssec, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_SET_NTA:
|
||||||
|
r = dns_name_is_valid(optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to validate specified domain %s: %m", optarg);
|
||||||
|
if (r == 0)
|
||||||
|
return log_error_errno(r, "Domain not valid: %s", optarg);
|
||||||
|
|
||||||
|
r = strv_extend(&arg_set_nta, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
arg_mode = MODE_SET_LINK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_REVERT_LINK:
|
||||||
|
arg_mode = MODE_REVERT_LINK;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -1873,6 +2212,19 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
if (arg_class != 0 && arg_type == 0)
|
if (arg_class != 0 && arg_type == 0)
|
||||||
arg_type = DNS_TYPE_A;
|
arg_type = DNS_TYPE_A;
|
||||||
|
|
||||||
|
if (IN_SET(arg_mode, MODE_SET_LINK, MODE_REVERT_LINK)) {
|
||||||
|
|
||||||
|
if (arg_ifindex <= 0) {
|
||||||
|
log_error("--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnssec=, --set-nta= and --revert require --interface=.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_ifindex == LOOPBACK_IFINDEX) {
|
||||||
|
log_error("Interface can't be the loopback interface (lo). Sorry.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1 /* work to do */;
|
return 1 /* work to do */;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2064,10 +2416,38 @@ int main(int argc, char **argv) {
|
||||||
r = status_all(bus);
|
r = status_all(bus);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case MODE_SET_LINK:
|
||||||
|
if (argc > optind) {
|
||||||
|
log_error("Too many arguments.");
|
||||||
|
r = -EINVAL;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_link(bus);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_REVERT_LINK:
|
||||||
|
if (argc > optind) {
|
||||||
|
log_error("Too many arguments.");
|
||||||
|
r = -EINVAL;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = revert_link(bus);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
pager_close();
|
pager_close();
|
||||||
|
|
||||||
|
free(arg_set_dns);
|
||||||
|
strv_free(arg_set_domain);
|
||||||
|
free(arg_set_llmnr);
|
||||||
|
free(arg_set_mdns);
|
||||||
|
free(arg_set_dnssec);
|
||||||
|
strv_free(arg_set_nta);
|
||||||
|
|
||||||
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue