resolved: create private stub resolve file for /etc/resolv.conf integration (#7014)

This creates a second private resolve.conf file which lists the stub resolver
and the resolved acquired search domains.

This runtime file should be used as a symlink target for /etc/resolv.conf such
that non-nss based applications can resolve search domains.

Fixes: #7009
This commit is contained in:
Dimitri John Ledkov 2017-10-24 09:28:41 -04:00 committed by Lennart Poettering
parent ceeb433c39
commit e6b2d948f8
6 changed files with 73 additions and 20 deletions

8
NEWS
View File

@ -6,6 +6,14 @@ CHANGES WITH 236 in spe:
has been extended to also set the dummy module option numdummies=0, has been extended to also set the dummy module option numdummies=0,
resolving issues with the kernel creating dummy0. resolving issues with the kernel creating dummy0.
* systemd-resolved now maintains a new dynamic
/run/systemd/resolve/stub-resolv.conf compatibility file. It is now
recommended to maintain /etc/resolv.conf as a symlink to this new
dynamic file. It points at the systemd-resolved stub DNS 127.0.0.53
resolver and it includes dynamically acquired search domains. This
achieves a more correct DNS resolution by software that bypasses
local DNS APIs (e.g. NSS).
CHANGES WITH 235: CHANGES WITH 235:
* A new modprobe.d drop-in is now shipped by default that sets the * A new modprobe.d drop-in is now shipped by default that sets the

View File

@ -94,7 +94,8 @@
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details
about systemd's own configuration files for DNS servers. To improve compatibility, about systemd's own configuration files for DNS servers. To improve compatibility,
<filename>/etc/resolv.conf</filename> is read in order to discover configured system DNS servers, but only if it is <filename>/etc/resolv.conf</filename> is read in order to discover configured system DNS servers, but only if it is
not a symlink to <filename>/run/systemd/resolve/resolv.conf</filename> (see below).</para> not a symlink to <filename>/run/systemd/resolve/stub-resolv.conf</filename> or
<filename>/run/systemd/resolve/resolv.conf</filename> (see below).</para>
<para><command>systemd-resolved</command> synthesizes DNS resource records (RRs) for the following cases:</para> <para><command>systemd-resolved</command> synthesizes DNS resource records (RRs) for the following cases:</para>
@ -164,15 +165,26 @@
<refsect1> <refsect1>
<title><filename>/etc/resolv.conf</filename></title> <title><filename>/etc/resolv.conf</filename></title>
<para>Three modes of handling <filename>/etc/resolv.conf</filename> (see <para>Four modes of handling <filename>/etc/resolv.conf</filename> (see
<citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) are <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) are
supported:</para> supported:</para>
<itemizedlist> <itemizedlist>
<listitem><para><command>systemd-resolved</command> maintains the
<filename>/run/systemd/resolve/stub-resolv.conf</filename> file for compatibility with traditional Linux
programs. This file may be symlinked from <filename>/etc/resolv.conf</filename>. This file lists the 127.0.0.53
DNS stub (see above) as the only DNS server. It also contains a list of search domains that are in use by
systemd-resolved. The list of search domains is always kept up-to-date. Note that
<filename>/run/systemd/resolve/stub-resolv.conf</filename> should not be used directly by applications, but only
through a symlink from <filename>/etc/resolv.conf</filename>. This file may be symlinked from
<filename>/etc/resolv.conf</filename> in order to connect all local clients that bypass local DNS APIs to
<command>systemd-resolved</command> with correct search domains settings. This mode of operation is
recommended.</para></listitem>
<listitem><para>A static file <filename>/usr/lib/systemd/resolv.conf</filename> is provided that lists <listitem><para>A static file <filename>/usr/lib/systemd/resolv.conf</filename> is provided that lists
the 127.0.0.53 DNS stub (see above) as only DNS server. This file may be symlinked from the 127.0.0.53 DNS stub (see above) as only DNS server. This file may be symlinked from
<filename>/etc/resolv.conf</filename> in order to connect all local clients that bypass local DNS APIs to <filename>/etc/resolv.conf</filename> in order to connect all local clients that bypass local DNS APIs to
<command>systemd-resolved</command>. This mode of operation is recommended.</para></listitem> <command>systemd-resolved</command>. This file does not contain any search domains.</para></listitem>
<listitem><para><command>systemd-resolved</command> maintains the <listitem><para><command>systemd-resolved</command> maintains the
<filename>/run/systemd/resolve/resolv.conf</filename> file for compatibility with traditional Linux <filename>/run/systemd/resolve/resolv.conf</filename> file for compatibility with traditional Linux

View File

@ -61,7 +61,13 @@ int manager_read_resolv_conf(Manager *m) {
return 0; return 0;
/* Is it symlinked to our own file? */ /* Is it symlinked to our own file? */
if (stat(PRIVATE_RESOLV_CONF, &own) >= 0 && if (stat(PRIVATE_UPLINK_RESOLV_CONF, &own) >= 0 &&
st.st_dev == own.st_dev &&
st.st_ino == own.st_ino)
return 0;
/* Is it symlinked to our own stub file? */
if (stat(PRIVATE_STUB_RESOLV_CONF, &own) >= 0 &&
st.st_dev == own.st_dev && st.st_dev == own.st_dev &&
st.st_ino == own.st_ino) st.st_ino == own.st_ino)
return 0; return 0;
@ -206,7 +212,7 @@ static void write_resolv_conf_search(
fputs_unlocked("\n", f); fputs_unlocked("\n", f);
} }
static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
Iterator i; Iterator i;
fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n" fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
@ -234,11 +240,25 @@ static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *doma
return fflush_and_check(f); return fflush_and_check(f);
} }
static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
"# 127.0.0.53 is the systemd-resolved stub resolver.\n"
"# run \"systemd-resolve --status\" to see details about the actual nameservers.\n"
"nameserver 127.0.0.53\n\n", f);
if (!ordered_set_isempty(domains))
write_resolv_conf_search(domains, f);
return fflush_and_check(f);
}
int manager_write_resolv_conf(Manager *m) { int manager_write_resolv_conf(Manager *m) {
_cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL; _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
_cleanup_free_ char *temp_path = NULL; _cleanup_free_ char *temp_path_uplink = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *temp_path_stub = NULL;
_cleanup_fclose_ FILE *f_uplink = NULL;
_cleanup_fclose_ FILE *f_stub = NULL;
int r; int r;
assert(m); assert(m);
@ -255,28 +275,44 @@ int manager_write_resolv_conf(Manager *m) {
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to compile list of search domains: %m"); return log_warning_errno(r, "Failed to compile list of search domains: %m");
r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path); r = fopen_temporary_label(PRIVATE_UPLINK_RESOLV_CONF, PRIVATE_UPLINK_RESOLV_CONF, &f_uplink, &temp_path_uplink);
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to open private resolv.conf file for writing: %m"); return log_warning_errno(r, "Failed to open private resolv.conf file for writing: %m");
r = fopen_temporary_label(PRIVATE_STUB_RESOLV_CONF, PRIVATE_STUB_RESOLV_CONF, &f_stub, &temp_path_stub);
if (r < 0)
return log_warning_errno(r, "Failed to open private stub-resolv.conf file for writing: %m");
(void) fchmod(fileno(f_uplink), 0644);
(void) fchmod(fileno(f_stub), 0644);
(void) fchmod(fileno(f), 0644); r = write_uplink_resolv_conf_contents(f_uplink, dns, domains);
r = write_resolv_conf_contents(f, dns, domains);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to write private resolv.conf contents: %m"); log_error_errno(r, "Failed to write private resolv.conf contents: %m");
goto fail; goto fail;
} }
if (rename(temp_path, PRIVATE_RESOLV_CONF) < 0) { if (rename(temp_path_uplink, PRIVATE_UPLINK_RESOLV_CONF) < 0) {
r = log_error_errno(errno, "Failed to move private resolv.conf file into place: %m"); r = log_error_errno(errno, "Failed to move private resolv.conf file into place: %m");
goto fail; goto fail;
} }
r = write_stub_resolv_conf_contents(f_stub, dns, domains);
if (r < 0) {
log_error_errno(r, "Failed to write private stub-resolv.conf contents: %m");
goto fail;
}
if (rename(temp_path_stub, PRIVATE_STUB_RESOLV_CONF) < 0) {
r = log_error_errno(errno, "Failed to move private stub-resolv.conf file into place: %m");
goto fail;
}
return 0; return 0;
fail: fail:
(void) unlink(PRIVATE_RESOLV_CONF); (void) unlink(PRIVATE_UPLINK_RESOLV_CONF);
(void) unlink(temp_path); (void) unlink(temp_path_uplink);
(void) unlink(PRIVATE_STUB_RESOLV_CONF);
(void) unlink(temp_path_stub);
return r; return r;
} }

View File

@ -21,7 +21,8 @@
#include "resolved-manager.h" #include "resolved-manager.h"
#define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf" #define PRIVATE_UPLINK_RESOLV_CONF "/run/systemd/resolve/resolv.conf"
#define PRIVATE_STUB_RESOLV_CONF "/run/systemd/resolve/stub-resolv.conf"
int manager_read_resolv_conf(Manager *m); int manager_read_resolv_conf(Manager *m);
int manager_write_resolv_conf(Manager *m); int manager_write_resolv_conf(Manager *m);

View File

@ -117,10 +117,6 @@ int main(int argc, char *argv[]) {
sd_event_get_exit_code(m->event, &r); sd_event_get_exit_code(m->event, &r);
finish: finish:
/* systemd-nspawn checks for private resolv.conf to decide whether
or not to mount it into the container. So just delete it. */
(void) unlink(PRIVATE_RESOLV_CONF);
sd_notify(false, sd_notify(false,
"STOPPING=1\n" "STOPPING=1\n"
"STATUS=Shutting down..."); "STATUS=Shutting down...");

View File

@ -14,7 +14,7 @@ m4_ifdef(`HAVE_SMACK_RUN_LABEL',
t /etc/mtab - - - - security.SMACK64=_ t /etc/mtab - - - - security.SMACK64=_
)m4_dnl )m4_dnl
m4_ifdef(`ENABLE_RESOLVE', m4_ifdef(`ENABLE_RESOLVE',
L! /etc/resolv.conf - - - - ../usr/lib/systemd/resolv.conf L! /etc/resolv.conf - - - - ../run/systemd/resolve/stub-resolv.conf
)m4_dnl )m4_dnl
C /etc/nsswitch.conf - - - - C /etc/nsswitch.conf - - - -
m4_ifdef(`HAVE_PAM', m4_ifdef(`HAVE_PAM',