summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2023-01-06 14:11:57 +0100
committerGitHub <noreply@github.com>2023-01-06 14:11:57 +0100
commite0ff0ee8f9c1aaa642ca90e74ebda795ea265e8b (patch)
treed9f64360cfd4f24e095b003ad9a95c2db9086dd8
parent2d935bbd22daf851cfb684812bb9056ea3538e5c (diff)
parent17eab9467dab008f4a1b714cbac571a8e2400d6a (diff)
downloadsystemd-e0ff0ee8f9c1aaa642ca90e74ebda795ea265e8b.tar.gz
Merge pull request #25947 from poettering/resolved-dns-creds
resolved: add support for reading DNS config from kernel cmdline + service credentials
-rw-r--r--TODO1
-rw-r--r--man/kernel-command-line.xml9
-rw-r--r--man/systemd-resolved.service.xml43
-rw-r--r--man/systemd.system-credentials.xml9
-rw-r--r--src/resolve/resolved-conf.c104
-rw-r--r--units/systemd-resolved.service.in3
6 files changed, 164 insertions, 5 deletions
diff --git a/TODO b/TODO
index 8d4b46106f..f30750550f 100644
--- a/TODO
+++ b/TODO
@@ -598,7 +598,6 @@ Features:
• resolved: allow defining additional /etc/hosts entries via a credential (it
might make sense to then synthesize a new combined /etc/hosts file in /run
and bind mount it on /etc/hosts for other clients that want to read it.
- Similar, allow picking up DNS server IP addresses from credential.
• repart: allow defining additional partitions via credential
• timesyncd: pick NTP server info from credential
• portabled: read a credential "portable.extra" or so, that takes a list of
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]