resolved: expose a new bus property that informs about the /etc/resolv.conf mode

It can be one of "foreign", "missing", "stub", "static", "uplink",
depending on how /etc/resolv.conf is set up:

foreign → someone/something else manages /etc/resolv.conf,
    systemd-resolved is just the consumer

missing → /etc/resolv.conf is missing altogether

stub/static/uplink → the file is managed by resolved, with the
    well-known modes

Fixes: #17159
This commit is contained in:
Lennart Poettering 2020-09-29 17:25:15 +02:00
parent 60b254ca1a
commit 4261ab654c
4 changed files with 96 additions and 3 deletions

View File

@ -147,6 +147,8 @@ node /org/freedesktop/resolve1 {
readonly as DNSSECNegativeTrustAnchors = ['...', ...]; readonly as DNSSECNegativeTrustAnchors = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("false") @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DNSStubListener = '...'; readonly s DNSStubListener = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s ResolvConfMode = '...';
}; };
interface org.freedesktop.DBus.Peer { ... }; interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... }; interface org.freedesktop.DBus.Introspectable { ... };
@ -272,6 +274,8 @@ node /org/freedesktop/resolve1 {
<variablelist class="dbus-property" generated="True" extra-ref="DNSStubListener"/> <variablelist class="dbus-property" generated="True" extra-ref="DNSStubListener"/>
<variablelist class="dbus-property" generated="True" extra-ref="ResolvConfMode"/>
<!--End of Autogenerated section--> <!--End of Autogenerated section-->
<refsect2> <refsect2>
@ -555,9 +559,12 @@ node /org/freedesktop/resolve1 {
DNSSEC is supported by DNS servers until it verifies that this is not the case. Thus, the reported DNSSEC is supported by DNS servers until it verifies that this is not the case. Thus, the reported
value may initially be true, until the first transactions are executed.</para> value may initially be true, until the first transactions are executed.</para>
<para>The <varname>LogLevel</varname> property shows the (maximum) log level of the manager, with the <para>The <varname>ResolvConfMode</varname> property exposes how <filename>/etc/resolv.conf</filename>
same values as the <option>--log-level=</option> option described in is managed on the host. Currently, the values <literal>uplink</literal>, <literal>stub</literal>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> <literal>static</literal> (these three correspond to the three different files
<filename>systemd-resolved.service</filename> provides), <literal>foreign</literal> (the file is
managed by admin or another service, <filename>systemd-resolved.service</filename> just consumes it),
<literal>missing</literal> (<filename>/etc/resolv.conf</filename> is missing).</para>
</refsect2> </refsect2>
</refsect1> </refsect1>

View File

@ -15,6 +15,7 @@
#include "resolved-dnssd-bus.h" #include "resolved-dnssd-bus.h"
#include "resolved-dnssd.h" #include "resolved-dnssd.h"
#include "resolved-link-bus.h" #include "resolved-link-bus.h"
#include "resolved-resolv-conf.h"
#include "socket-netlink.h" #include "socket-netlink.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "strv.h" #include "strv.h"
@ -1620,6 +1621,28 @@ static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager,
static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string); static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dns_over_tls_mode, "s", Manager, manager_get_dns_over_tls_mode, dns_over_tls_mode_to_string); static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dns_over_tls_mode, "s", Manager, manager_get_dns_over_tls_mode, dns_over_tls_mode_to_string);
static int bus_property_get_resolv_conf_mode(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
int r;
assert(reply);
r = resolv_conf_mode();
if (r < 0) {
log_warning_errno(r, "Failed to test /etc/resolv.conf mode, ignoring: %m");
return sd_bus_message_append(reply, "s", NULL);
}
return sd_bus_message_append(reply, "s", resolv_conf_mode_to_string(r));
}
static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) { static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata; Manager *m = userdata;
DnsScope *s; DnsScope *s;
@ -2000,6 +2023,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0), SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0), SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0), SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
SD_BUS_PROPERTY("ResolvConfMode", "s", bus_property_get_resolv_conf_mode, 0, 0),
SD_BUS_METHOD_WITH_ARGS("ResolveHostname", SD_BUS_METHOD_WITH_ARGS("ResolveHostname",
SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags), SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags),

View File

@ -15,6 +15,7 @@
#include "resolved-dns-server.h" #include "resolved-dns-server.h"
#include "resolved-resolv-conf.h" #include "resolved-resolv-conf.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "tmpfile-util-label.h" #include "tmpfile-util-label.h"
@ -371,3 +372,49 @@ int manager_write_resolv_conf(Manager *m) {
return r; return r;
} }
int resolv_conf_mode(void) {
static const char * const table[_RESOLV_CONF_MODE_MAX] = {
[RESOLV_CONF_UPLINK] = PRIVATE_UPLINK_RESOLV_CONF,
[RESOLV_CONF_STUB] = PRIVATE_STUB_RESOLV_CONF,
[RESOLV_CONF_STATIC] = PRIVATE_STATIC_RESOLV_CONF,
};
struct stat system_st;
if (stat("/etc/resolv.conf", &system_st) < 0) {
if (errno == ENOENT)
return RESOLV_CONF_MISSING;
return -errno;
}
for (ResolvConfMode m = 0; m < _RESOLV_CONF_MODE_MAX; m++) {
struct stat our_st;
if (!table[m])
continue;
if (stat(table[m], &our_st) < 0) {
if (errno != ENOENT)
log_debug_errno(errno, "Failed to stat() %s, ignoring: %m", table[m]);
continue;
}
if (system_st.st_dev == our_st.st_dev &&
system_st.st_ino == our_st.st_ino)
return m;
}
return RESOLV_CONF_FOREIGN;
}
static const char* const resolv_conf_mode_table[_RESOLV_CONF_MODE_MAX] = {
[RESOLV_CONF_UPLINK] = "uplink",
[RESOLV_CONF_STUB] = "stub",
[RESOLV_CONF_STATIC] = "static",
[RESOLV_CONF_MISSING] = "missing",
[RESOLV_CONF_FOREIGN] = "foreign",
};
DEFINE_STRING_TABLE_LOOKUP(resolv_conf_mode, ResolvConfMode);

View File

@ -6,3 +6,18 @@
int manager_check_resolv_conf(const Manager *m); int manager_check_resolv_conf(const Manager *m);
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);
typedef enum ResolvConfMode {
RESOLV_CONF_UPLINK,
RESOLV_CONF_STUB,
RESOLV_CONF_STATIC,
RESOLV_CONF_FOREIGN,
RESOLV_CONF_MISSING,
_RESOLV_CONF_MODE_MAX,
_RESOLV_CONF_MODE_INVALID = -1,
} ResolvConfMode;
int resolv_conf_mode(void);
const char* resolv_conf_mode_to_string(ResolvConfMode m) _const_;
ResolvConfMode resolv_conf_mode_from_string(const char *s) _pure_;