diff options
author | Lennart Poettering <lennart@poettering.net> | 2023-01-05 15:35:20 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-01-05 18:52:15 +0100 |
commit | 116687f26778c5d8f1fceb9b0ebba363a10597bc (patch) | |
tree | 3514cb8fb28d72896aa6b5434486e4a39b3c23de | |
parent | vconsole: permit configuration of vconsole settings via credentials (diff) | |
download | systemd-116687f26778c5d8f1fceb9b0ebba363a10597bc.tar.xz systemd-116687f26778c5d8f1fceb9b0ebba363a10597bc.zip |
resolved: read DNS conf also from creds and kernel cmdline
Note that this drops ProtectProc=invisible from
systemd-resolved.service.
This is done because othewise access to the booted "kernel" command line is not
necessarily available. That's because in containers we want to read
/proc/1/cmdline for that.
Fixes: #24103
-rw-r--r-- | man/kernel-command-line.xml | 9 | ||||
-rw-r--r-- | man/systemd-resolved.service.xml | 43 | ||||
-rw-r--r-- | man/systemd.system-credentials.xml | 9 | ||||
-rw-r--r-- | src/resolve/resolved-conf.c | 104 | ||||
-rw-r--r-- | units/systemd-resolved.service.in | 3 |
5 files changed, 164 insertions, 4 deletions
diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 545dc40798..0528c4b672 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -479,6 +479,15 @@ </varlistentry> <varlistentry> + <term><varname>nameserver=</varname></term> + <term><varname>domain=</varname></term> + + <listitem><para>Configures DNS server information and search domains, see + <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> + for details.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>resume=</varname></term> <term><varname>resumeflags=</varname></term> diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index c006c03b53..7003c36db7 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -400,6 +400,49 @@ search foobar.com barbar.com </refsect1> <refsect1> + <title>Credentials</title> + + <para><command>systemd-resolved</command> supports the service credentials logic as implemented by + <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for + details). The following credentials are used when passed in:</para> + + <variablelist> + <varlistentry> + <term><varname>network.dns</varname></term> + <term><varname>network.search_domains</varname></term> + + <listitem><para>May contain a space separated list of DNS server IP addresses and DNS search + domains. This information is only used when no explicit configuration via + <filename>/etc/systemd/resolved.conf</filename>, <filename>/etc/resolv.conf</filename> or the kernel + command line has been provided.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Kernel Command Line</title> + + <para><command>systemd-resolved</command> also honours two kernel command line options:</para> + + <variablelist class='kernel-commandline-options'> + <varlistentry> + <term><varname>nameserver=</varname></term> + <term><varname>domain=</varname></term> + + <listitem><para>Takes the IP address of a DNS server (in case of <varname>nameserver=</varname>), and + a DNS search domain (in case of <varname>domain=</varname>). May be used multiple times, to define + multiple DNS servers/search domains. If either of these options are specified + <filename>/etc/resolv.conf</filename> will not be read and the <varname>DNS=</varname> and + <varname>Domains=</varname> settings of + <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> + will be ignored. These two kernel command line options hence override system + configuration.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index 3eadf9b985..9e49e3feae 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -116,6 +116,15 @@ </varlistentry> <varlistentry> + <term><varname>network.dns</varname></term> + <term><varname>network.search_domains</varname></term> + <listitem> + <para>DNS server information and search domains. Read by + <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>passwd.hashed-password.root</varname></term> <term><varname>passwd.plaintext-password.root</varname></term> <listitem> diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 2be5986f9b..d6929984e9 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -3,15 +3,17 @@ #include "alloc-util.h" #include "conf-parser.h" #include "constants.h" +#include "creds-util.h" +#include "dns-domain.h" #include "extract-word.h" #include "hexdecoct.h" #include "parse-util.h" +#include "proc-cmdline.h" #include "resolved-conf.h" -#include "resolved-dnssd.h" -#include "resolved-manager.h" #include "resolved-dns-search-domain.h" #include "resolved-dns-stub.h" -#include "dns-domain.h" +#include "resolved-dnssd.h" +#include "resolved-manager.h" #include "socket-netlink.h" #include "specifier.h" #include "string-table.h" @@ -463,6 +465,99 @@ int config_parse_dns_stub_listener_extra( return 0; } +static void read_credentials(Manager *m) { + _cleanup_free_ char *dns = NULL, *domains = NULL; + int r; + + assert(m); + + /* Hmm, if we aren't supposed to read /etc/resolv.conf because the DNS settings were already + * configured explicitly in our config file, we don't want to honour credentials either */ + if (!m->read_resolv_conf) + return; + + r = read_credential_strings_many( + "network.dns", &dns, + "network.search_domains", &domains); + if (r < 0 && !IN_SET(r, -ENXIO, -ENOENT)) + log_warning_errno(r, "Failed to read credentials, ignoring: %m"); + + if (dns) { + r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_SYSTEM, dns); + if (r < 0) + log_warning_errno(r, "Failed to parse credential provided DNS server string '%s', ignoring.", dns); + + m->read_resolv_conf = false; + } + + if (domains) { + r = manager_parse_search_domains_and_warn(m, domains); + if (r < 0) + log_warning_errno(r, "Failed to parse credential provided search domain string '%s', ignoring.", domains); + + m->read_resolv_conf = false; + } +} + +struct ProcCmdlineInfo { + Manager *manager; + + /* If there's a setting configured via /proc/cmdline we want to reset the configured lists, but only + * once, so that multiple nameserver= or domain= settings can be specified on the kernel command line + * and will be combined. These booleans will be set once we erase the list once. */ + bool dns_server_unlinked; + bool search_domain_unlinked; +}; + +static int proc_cmdline_callback(const char *key, const char *value, void *data) { + struct ProcCmdlineInfo *info = ASSERT_PTR(data); + int r; + + assert(info->manager); + + /* The kernel command line option names are chosen to be compatible with what various tools already + * interpret, for example dracut and SUSE Linux. */ + + if (proc_cmdline_key_streq(key, "nameserver")) { + if (!info->dns_server_unlinked) { + /* The kernel command line overrides any prior configuration */ + dns_server_unlink_all(manager_get_first_dns_server(info->manager, DNS_SERVER_SYSTEM)); + info->dns_server_unlinked = true; + } + + r = manager_parse_dns_server_string_and_warn(info->manager, DNS_SERVER_SYSTEM, value); + if (r < 0) + log_warning_errno(r, "Failed to parse DNS server string '%s', ignoring.", value); + + info->manager->read_resolv_conf = false; + + } else if (proc_cmdline_key_streq(key, "domain")) { + + if (!info->search_domain_unlinked) { + dns_search_domain_unlink_all(info->manager->search_domains); + info->search_domain_unlinked = true; + } + + r = manager_parse_search_domains_and_warn(info->manager, value); + if (r < 0) + log_warning_errno(r, "Failed to parse credential provided search domain string '%s', ignoring.", value); + + info->manager->read_resolv_conf = false; + } + + return 0; +} + +static void read_proc_cmdline(Manager *m) { + int r; + + assert(m); + + r = proc_cmdline_parse(proc_cmdline_callback, &(struct ProcCmdlineInfo) { .manager = m }, 0); + if (r < 0) + log_warning_errno(r, "Failed to read kernel command line, ignoring: %m"); +} + int manager_parse_config_file(Manager *m) { int r; @@ -479,6 +574,9 @@ int manager_parse_config_file(Manager *m) { if (r < 0) return r; + read_credentials(m); /* credentials are only used when nothing is explicitly configured … */ + read_proc_cmdline(m); /* … but kernel command line overrides local configuration. */ + if (m->need_builtin_fallbacks) { r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_FALLBACK, DNS_SERVERS); if (r < 0) diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in index 621fe34224..b4227ffd42 100644 --- a/units/systemd-resolved.service.in +++ b/units/systemd-resolved.service.in @@ -30,7 +30,6 @@ MemoryDenyWriteExecute=yes NoNewPrivileges=yes PrivateDevices=yes PrivateTmp=yes -ProtectProc=invisible ProtectClock=yes ProtectControlGroups=yes ProtectHome=yes @@ -51,6 +50,8 @@ SystemCallErrorNumber=EPERM SystemCallFilter=@system-service Type=notify User=systemd-resolve +LoadCredential=network.dns +LoadCredential=network.search_domains {{SERVICE_WATCHDOG}} [Install] |