mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 08:55:40 +03:00
Compare commits
27 Commits
1399e3d385
...
9edf3b7374
Author | SHA1 | Date | |
---|---|---|---|
|
9edf3b7374 | ||
|
f7078de515 | ||
|
6d6048b4cb | ||
|
10a48938ef | ||
|
b58b13f1c6 | ||
|
c8f59296bf | ||
|
d585085f57 | ||
|
ff4b6a1915 | ||
|
d9f68f48f7 | ||
|
0310b2a60b | ||
|
115fac3c29 | ||
|
9d8f5e22f8 | ||
|
6fb0c52295 | ||
|
edd10ab29c | ||
|
988053eac3 | ||
|
a586f57eb2 | ||
|
c18ac81f17 | ||
|
c4363051e4 | ||
|
f515ea1cd4 | ||
|
e4b4d9cc7a | ||
|
11de19f3da | ||
|
e98e3f856d | ||
|
dcbfc7872e | ||
|
95b1dd00b6 | ||
|
fe09c8398e | ||
|
da1b3c55ff | ||
|
568bf0b4e8 |
8
TODO
8
TODO
@ -129,6 +129,11 @@ Deprecations and removals:
|
||||
|
||||
Features:
|
||||
|
||||
* $LISTEN_PID, $MAINPID and $SYSTEMD_EXECPID env vars that the service manager
|
||||
sets should be augmented with $LISTEN_PIDFDID, $MAINPIDFDID and
|
||||
$SYSTEMD_EXECPIDFD (and similar for other env vars we might send). Also,
|
||||
MAINPID= in sd_notify() should be augmented with MAINPIDFDID=, and so on.
|
||||
|
||||
* port copy.c over to use LabelOps for all labelling.
|
||||
|
||||
* port remaining getmntent() users over to libmount. There are subtle
|
||||
@ -157,9 +162,6 @@ Features:
|
||||
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
|
||||
calls.
|
||||
|
||||
* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
|
||||
i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑🔧 or so.
|
||||
|
||||
* introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
|
||||
policy bits into one structure, i.e. public key info, pcr masks, pcrlock
|
||||
stuff, pin and so on. Then pass that around in tpm2_seal() and tpm2_unseal().
|
||||
|
@ -115,6 +115,9 @@ node /org/freedesktop/resolve1 {
|
||||
ResetStatistics();
|
||||
FlushCaches();
|
||||
ResetServerFeatures();
|
||||
GetDelegate(in s id,
|
||||
out o path);
|
||||
ListDelegates(out a(so) delegates);
|
||||
properties:
|
||||
readonly s LLMNRHostname = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
@ -202,6 +205,10 @@ node /org/freedesktop/resolve1 {
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ResetServerFeatures()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="GetDelegate()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListDelegates()"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="LLMNRHostname"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="LLMNR"/>
|
||||
@ -423,13 +430,13 @@ node /org/freedesktop/resolve1 {
|
||||
<para>The <function>RevertLink()</function> method may be used to revert all per-link settings
|
||||
described above to the defaults.</para>
|
||||
|
||||
<para>The <function>FlushCaches()</function> flushes all resource record caches maintained by the
|
||||
<para>The <function>FlushCaches()</function> method flushes all resource record caches maintained by the
|
||||
resolver, and ensures that any subsequent lookups re-request their responses from their sources.</para>
|
||||
|
||||
<para>The <function>ResetServerFeatures()</function> flushes any feature information learned about
|
||||
remote DNS servers. This ensures that subsequent lookups will be initially attempted at the highest DNS
|
||||
protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to recognize the
|
||||
supported feature level again.</para>
|
||||
<para>The <function>ResetServerFeatures()</function> method flushes any feature information learned
|
||||
about remote DNS servers. This ensures that subsequent lookups will be initially attempted at the
|
||||
highest DNS protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to
|
||||
recognize the supported feature level again.</para>
|
||||
|
||||
<para>The <function>RegisterService()</function> method may be used to register a DNS-SD service on the
|
||||
host. This functionality is closely related to the functionality provided by
|
||||
@ -447,6 +454,12 @@ node /org/freedesktop/resolve1 {
|
||||
<function>RegisterService()</function> and deletes a DNS-SD service previously created via IPC
|
||||
again.</para>
|
||||
|
||||
<para>The <function>GetDelegate()</function> method returns the D-Bus object path for the specified DNS
|
||||
delegate ID.</para>
|
||||
|
||||
<para>The <function>ListDelegates()</function> method returns a list of the IDs and D-Bus object paths
|
||||
of the currently configured DNS delegates.</para>
|
||||
|
||||
<refsect3>
|
||||
<title>The Flags Parameter</title>
|
||||
|
||||
@ -935,4 +948,14 @@ $ gdbus introspect --system \
|
||||
</refsect1>
|
||||
|
||||
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
|
||||
|
||||
<refsect1>
|
||||
<title>History</title>
|
||||
<refsect2>
|
||||
<title>The Manager Object</title>
|
||||
|
||||
<para><function>GetDelegate()</function> and <function>ListDelegates()</function> were added in version 257.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
52
man/run0.xml
52
man/run0.xml
@ -192,6 +192,35 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--pty</option></term>
|
||||
<term><option>--pipe</option></term>
|
||||
|
||||
<listitem><para>Request allocation of a pseudo TTY for the <command>run0</command> session (in case
|
||||
of <option>--pty</option>), or request passing the caller's STDIO file descriptors directly through
|
||||
(in case of <option>--pipe</option>). If neither switch is specified, or if both switches are
|
||||
specified, the mode will be picked automatically: if standard input, standard output and standard
|
||||
error output are all connected to a TTY then a pseudo TTY is allocated, otherwise the relevant file
|
||||
descriptors are passed through directly.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--shell-prompt-prefix=<replaceable>STRING</replaceable></option></term>
|
||||
|
||||
<listitem><para>Set a shell prompt prefix string. This ultimately controls the
|
||||
<varname>$SHELL_PROMPT_PREFIX</varname> environment variable for the invoked program, which is
|
||||
typically imported into the shell prompt. By default – if emojis are supported – a superhero emoji is
|
||||
shown (🦸). This default may also be changed (or turned off) by passing the
|
||||
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable to <varname>run0</varname>,
|
||||
see below. Set to an empty string to disable shell prompt prefixing.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
@ -256,7 +285,30 @@
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SHELL_PROMPT_PREFIX</varname></term>
|
||||
<listitem><para>By default set to the superhero emoji (if supported), but may be overriden with the
|
||||
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable (see below), or the
|
||||
<option>--shell-prompt-prefix=</option> switch (see above).</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>The following variables may be passed to <command>run0</command>:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname></term>
|
||||
<listitem><para>If set, overrides the default shell prompt prefix that <command>run0</command> sets
|
||||
for the invoked shell (the superhero emoji). Set to an empty string to disable shell prompt
|
||||
prefixing.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -54,12 +54,24 @@
|
||||
|
||||
<listitem><para>Takes a boolean argument. Defaults to <literal>yes</literal>. If
|
||||
<literal>no</literal>, disables the generator entirely. <varname>rd.systemd.verity=</varname> is
|
||||
honored only by the initrd while <varname>systemd.verity=</varname> is honored by both the host
|
||||
system and the initrd.</para>
|
||||
honored only in the initrd while <varname>systemd.verity=</varname> is honored by both the main
|
||||
system and in the initrd.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v233"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>veritytab=</varname></term>
|
||||
<term><varname>rd.veritytab=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. Defaults to <literal>yes</literal>. If
|
||||
<literal>no</literal>, causes the generator to ignore any devices configured in
|
||||
<filename>/etc/veritytab</filename>. <varname>rd.veritytab=</varname> is honored only in the initrd
|
||||
while <varname>veritytab=</varname> is honored by both the main system and in the initrd.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>roothash=</varname></term>
|
||||
|
||||
@ -104,7 +116,7 @@
|
||||
<option>hash=<replaceable>HASH</replaceable></option>, <option>fec-device=<replaceable>PATH</replaceable></option>,
|
||||
<option>fec-offset=<replaceable>BYTES</replaceable></option>, <option>fec-roots=<replaceable>NUM</replaceable></option> and
|
||||
<option>root-hash-signature=<replaceable>PATH</replaceable>|base64:<replaceable>HEX</replaceable></option>. See
|
||||
<citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more
|
||||
<citerefentry project='man-pages'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more
|
||||
details.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
|
||||
@ -129,7 +141,7 @@
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
@ -97,7 +97,7 @@
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -319,7 +319,7 @@ data /etc/data /etc/hash a5ee4b42f70ae1f46a08a7c92c2e0a20672ad2f514792730f5d49d7
|
||||
<member><citerefentry><refentrytitle>systemd-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -80,6 +80,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
|
||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_SUPERHERO] = "S",
|
||||
},
|
||||
|
||||
/* UTF-8 */
|
||||
@ -149,6 +150,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
|
||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
|
||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
|
||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
|
||||
[SPECIAL_GLYPH_SUPERHERO] = u8"🦸",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -55,6 +55,7 @@ typedef enum SpecialGlyph {
|
||||
SPECIAL_GLYPH_YELLOW_CIRCLE,
|
||||
SPECIAL_GLYPH_BLUE_CIRCLE,
|
||||
SPECIAL_GLYPH_GREEN_CIRCLE,
|
||||
SPECIAL_GLYPH_SUPERHERO,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
@ -4061,7 +4061,7 @@ int exec_invoke(
|
||||
int r, ngids = 0;
|
||||
_cleanup_free_ gid_t *supplementary_gids = NULL;
|
||||
const char *username = NULL, *groupname = NULL;
|
||||
_cleanup_free_ char *home_buffer = NULL, *memory_pressure_path = NULL;
|
||||
_cleanup_free_ char *home_buffer = NULL, *memory_pressure_path = NULL, *own_user = NULL;
|
||||
const char *home = NULL, *shell = NULL;
|
||||
char **final_argv = NULL;
|
||||
dev_t journal_stream_dev = 0;
|
||||
@ -4298,8 +4298,23 @@ int exec_invoke(
|
||||
username = runtime->dynamic_creds->user->name;
|
||||
|
||||
} else {
|
||||
if (context->user) {
|
||||
r = get_fixed_user(context->user, &username, &uid, &gid, &home, &shell);
|
||||
const char *u;
|
||||
|
||||
if (context->user)
|
||||
u = context->user;
|
||||
else if (context->pam_name) {
|
||||
/* If PAM is enabled but no user name is explicitly selected, then use our own one. */
|
||||
own_user = getusername_malloc();
|
||||
if (!own_user) {
|
||||
*exit_status = EXIT_USER;
|
||||
return log_exec_error_errno(context, params, r, "Failed to determine my own user ID: %m");
|
||||
}
|
||||
u = own_user;
|
||||
} else
|
||||
u = NULL;
|
||||
|
||||
if (u) {
|
||||
r = get_fixed_user(u, &username, &uid, &gid, &home, &shell);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_USER;
|
||||
return log_exec_error_errno(context, params, r, "Failed to determine user credentials: %m");
|
||||
|
@ -85,6 +85,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_STUB_LOOP, ELOOP),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DNSSD_SERVICE, ENOENT),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNSSD_SERVICE_EXISTS, EEXIST),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DELEGATE, ENXIO),
|
||||
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNS_FORMERR, EBADMSG),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNS_SERVFAIL, EHOSTDOWN),
|
||||
|
@ -85,6 +85,7 @@
|
||||
#define BUS_ERROR_STUB_LOOP "org.freedesktop.resolve1.StubLoop"
|
||||
#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService"
|
||||
#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists"
|
||||
#define BUS_ERROR_NO_SUCH_DELEGATE "org.freedesktop.resolve1.NoSuchDelegate"
|
||||
|
||||
#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError."
|
||||
#define BUS_ERROR_DNS_FORMERR _BUS_ERROR_DNS "FORMERR"
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "operation.h"
|
||||
#include "process-util.h"
|
||||
|
||||
static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_error *error) {
|
||||
static int read_operation_errno(const siginfo_t *si, Operation *o) {
|
||||
int r;
|
||||
|
||||
assert(si);
|
||||
@ -27,15 +27,6 @@ static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_err
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message when reading operation's errno");
|
||||
}
|
||||
|
||||
if (o->done)
|
||||
/* A completion routine is set for this operation, call it. */
|
||||
return o->done(o, r, error);
|
||||
|
||||
/* The default operation when done is to simply return an error on failure or an empty success
|
||||
* message on success. */
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Operation failed: %m");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -51,10 +42,18 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
|
||||
|
||||
o->pid = 0;
|
||||
|
||||
r = read_operation_errno(si, o);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Operation failed: %m");
|
||||
|
||||
/* If a completion routine (o->done) is set for this operation, call it. It sends a response, but can return an error in which case it expect us to reply.
|
||||
* Otherwise, the default action is to simply return an error on failure or an empty success message on success. */
|
||||
|
||||
if (o->message) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
if (o->done)
|
||||
r = o->done(o, r, &error);
|
||||
|
||||
r = operation_done_internal(si, o, &error);
|
||||
if (r < 0) {
|
||||
if (!sd_bus_error_is_set(&error))
|
||||
sd_bus_error_set_errno(&error, r);
|
||||
@ -62,16 +61,20 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
|
||||
r = sd_bus_reply_method_error(o->message, &error);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to reply to dbus message: %m");
|
||||
} else {
|
||||
} else if (!o->done) {
|
||||
/* when o->done set it's responsible for sending reply in a happy-path case */
|
||||
r = sd_bus_reply_method_return(o->message, NULL);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to reply to dbus message: %m");
|
||||
}
|
||||
} else if (o->link) {
|
||||
r = operation_done_internal(si, o, /* error = */ NULL);
|
||||
if (o->done)
|
||||
r = o->done(o, r, /* error = */ NULL);
|
||||
|
||||
if (r < 0)
|
||||
(void) sd_varlink_error_errno(o->link, r);
|
||||
else
|
||||
else if (!o->done)
|
||||
/* when o->done set it's responsible for sending reply in a happy-path case */
|
||||
(void) sd_varlink_reply(o->link, NULL);
|
||||
} else
|
||||
assert_not_reached();
|
||||
|
@ -290,7 +290,7 @@ static int handle_arg_console(const char *arg) {
|
||||
else if (streq(arg, "passive"))
|
||||
arg_console_mode = CONSOLE_PASSIVE;
|
||||
else if (streq(arg, "pipe")) {
|
||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
||||
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
|
||||
"Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
|
||||
"Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
|
||||
@ -298,7 +298,7 @@ static int handle_arg_console(const char *arg) {
|
||||
|
||||
arg_console_mode = CONSOLE_PIPE;
|
||||
} else if (streq(arg, "autopipe")) {
|
||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
||||
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||
arg_console_mode = CONSOLE_INTERACTIVE;
|
||||
else
|
||||
arg_console_mode = CONSOLE_PIPE;
|
||||
@ -5981,7 +5981,7 @@ static int run(int argc, char *argv[]) {
|
||||
umask(0022);
|
||||
|
||||
if (arg_console_mode < 0)
|
||||
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) ?
|
||||
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) ?
|
||||
CONSOLE_INTERACTIVE : CONSOLE_READ_ONLY;
|
||||
|
||||
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
|
||||
|
@ -16,6 +16,8 @@ systemd_resolved_sources = files(
|
||||
'resolved-bus.c',
|
||||
'resolved-conf.c',
|
||||
'resolved-dns-cache.c',
|
||||
'resolved-dns-delegate.c',
|
||||
'resolved-dns-delegate-bus.c',
|
||||
'resolved-dns-query.c',
|
||||
'resolved-dns-scope.c',
|
||||
'resolved-dns-search-domain.c',
|
||||
@ -100,6 +102,12 @@ systemd_resolved_sources += custom_target(
|
||||
output : 'resolved-dnssd-gperf.c',
|
||||
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
|
||||
|
||||
systemd_resolved_sources += custom_target(
|
||||
'resolved_dns_delegate_gperf.c',
|
||||
input : 'resolved-dns-delegate-gperf.gperf',
|
||||
output : 'resolved-dns-delegate-gperf.c',
|
||||
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
|
||||
|
||||
systemd_resolved_dependencies = [threads, libm] + [lib_openssl_or_gcrypt]
|
||||
if conf.get('ENABLE_DNS_OVER_TLS') == 1
|
||||
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
|
||||
|
@ -1354,11 +1354,36 @@ static int reset_server_features(int argc, char **argv, void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum DnsServerPropertyFlags {
|
||||
DNS_SERVER_WITH_IFINDEX = 1 << 0, /* prefixed with a field for an ifindex */
|
||||
DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME = 1 << 1, /* suffix with port nr and server name */
|
||||
DNS_SERVER_ONLY_GLOBAL = 1 << 2, /* filter entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
|
||||
_DNS_SERVER_PROPERTY_FLAGS_MAX = DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME|DNS_SERVER_ONLY_GLOBAL,
|
||||
} DnsServerPropertyFlags;
|
||||
|
||||
static const char *dns_server_property_signature(DnsServerPropertyFlags flags) {
|
||||
switch (flags & (DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME)) {
|
||||
|
||||
case 0:
|
||||
return "iay";
|
||||
|
||||
case DNS_SERVER_WITH_IFINDEX:
|
||||
return "iiay";
|
||||
|
||||
case DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME:
|
||||
return "iayqs";
|
||||
|
||||
case DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME:
|
||||
return "iiayqs";
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static int read_dns_server_one(
|
||||
sd_bus_message *m,
|
||||
bool with_ifindex, /* read "ifindex" reply that also carries an interface index */
|
||||
bool extended, /* read "extended" reply, i.e. with port number and server name */
|
||||
bool only_global, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
|
||||
DnsServerPropertyFlags flags,
|
||||
char **ret) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
@ -1375,12 +1400,11 @@ static int read_dns_server_one(
|
||||
r = sd_bus_message_enter_container(
|
||||
m,
|
||||
'r',
|
||||
with_ifindex ? (extended ? "iiayqs" : "iiay") :
|
||||
(extended ? "iayqs" : "iay"));
|
||||
dns_server_property_signature(flags));
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (with_ifindex) {
|
||||
if (FLAGS_SET(flags, DNS_SERVER_WITH_IFINDEX)) {
|
||||
r = sd_bus_message_read(m, "i", &ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1390,12 +1414,8 @@ static int read_dns_server_one(
|
||||
if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
|
||||
return k;
|
||||
|
||||
if (extended) {
|
||||
r = sd_bus_message_read(m, "q", &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (FLAGS_SET(flags, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME)) {
|
||||
r = sd_bus_message_read(m, "qs", &port, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1410,7 +1430,7 @@ static int read_dns_server_one(
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (only_global && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) {
|
||||
if (FLAGS_SET(flags, DNS_SERVER_ONLY_GLOBAL) && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) {
|
||||
/* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
|
||||
*ret = NULL;
|
||||
return 1;
|
||||
@ -1424,7 +1444,14 @@ static int read_dns_server_one(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
|
||||
static int map_dns_servers_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
DnsServerPropertyFlags flags,
|
||||
sd_bus_error *error,
|
||||
void *userdata) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
@ -1432,14 +1459,16 @@ static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
|
||||
const char *sig = strjoina("(", dns_server_property_signature(flags), ")");
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_dns_server_one(m, /* with_ifindex= */ false, extended, /* only_global= */ false, &pretty);
|
||||
r = read_dns_server_one(m, flags, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -1461,25 +1490,25 @@ static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus
|
||||
}
|
||||
|
||||
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_link_dns_servers_internal(bus, member, m, error, userdata, false);
|
||||
return map_dns_servers_internal(bus, member, m, /* flags= */ 0, error, userdata);
|
||||
}
|
||||
|
||||
static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_link_dns_servers_internal(bus, member, m, error, userdata, true);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
assert(m);
|
||||
assert(userdata);
|
||||
|
||||
return read_dns_server_one(m, /* with_ifindex= */ false, /* extended= */ false, /* only_global= */ false, userdata);
|
||||
return read_dns_server_one(m, /* flags= */ 0, userdata);
|
||||
}
|
||||
|
||||
static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
assert(m);
|
||||
assert(userdata);
|
||||
|
||||
return read_dns_server_one(m, /* with_ifindex= */ false, /* extended= */ true, /* only_global= */ false, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, userdata);
|
||||
}
|
||||
|
||||
static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
|
||||
@ -1511,11 +1540,17 @@ static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(str);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
static int map_domains_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
bool with_ifindex,
|
||||
sd_bus_error *error,
|
||||
void *userdata) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
@ -1523,14 +1558,14 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m,
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "(sb)");
|
||||
r = sd_bus_message_enter_container(m, 'a', with_ifindex ? "(isb)" : "(sb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_domain_one(m, false, &pretty);
|
||||
r = read_domain_one(m, with_ifindex, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -1551,12 +1586,18 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
|
||||
static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
|
||||
}
|
||||
|
||||
static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) {
|
||||
const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */
|
||||
int pos1, pos2;
|
||||
|
||||
if (ifname)
|
||||
printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal());
|
||||
else if (delegate_id)
|
||||
printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1, delegate_id, &pos2, ansi_normal());
|
||||
else
|
||||
printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
|
||||
|
||||
@ -1580,6 +1621,14 @@ static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
|
||||
return status_print_strv_full(ifindex, ifname, NULL, p);
|
||||
}
|
||||
|
||||
static int status_print_strv_delegate(const char *delegate_id, char **p) {
|
||||
return status_print_strv_full(0, NULL, delegate_id, p);
|
||||
}
|
||||
|
||||
static int status_print_strv_global(char **p) {
|
||||
return status_print_strv_ifindex(0, NULL, p);
|
||||
}
|
||||
@ -1899,101 +1948,24 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_global_dns_servers_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
sd_bus_error *error,
|
||||
void *userdata,
|
||||
bool extended) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_dns_server_one(m, /* with_ifindex= */ true, extended, /* only_global= */ true, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (isempty(pretty))
|
||||
continue;
|
||||
|
||||
r = strv_consume(l, TAKE_PTR(pretty));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_global_dns_servers_internal(bus, member, m, error, userdata, /* extended= */ false);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL, error, userdata);
|
||||
}
|
||||
|
||||
static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_global_dns_servers_internal(bus, member, m, error, userdata, /* extended= */ true);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, /* with_ifindex= */ true, /* extended= */ false, /* only_global= */ true, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL, userdata);
|
||||
}
|
||||
|
||||
static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, /* with_ifindex= */ true, /* extended= */ true, /* only_global= */ true, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME|DNS_SERVER_ONLY_GLOBAL, userdata);
|
||||
}
|
||||
|
||||
static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "(isb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_domain_one(m, true, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (isempty(pretty))
|
||||
continue;
|
||||
|
||||
r = strv_consume(l, TAKE_PTR(pretty));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
strv_sort(*l);
|
||||
|
||||
return 0;
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ true, error, userdata);
|
||||
}
|
||||
|
||||
static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
@ -2132,18 +2104,13 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_all(sd_bus *bus, StatusMode mode) {
|
||||
static int status_links(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
bool empty_line = false;
|
||||
int ret = 0, r;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = status_global(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_open(&rtnl);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to netlink: %m");
|
||||
@ -2195,11 +2162,206 @@ static int status_all(sd_bus *bus, StatusMode mode) {
|
||||
typesafe_qsort(infos, n_infos, interface_info_compare);
|
||||
|
||||
FOREACH_ARRAY(info, infos, n_infos)
|
||||
RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, &empty_line));
|
||||
RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, empty_line));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct DelegateInfo {
|
||||
char *current_dns;
|
||||
char **dns;
|
||||
char **domains;
|
||||
bool default_route;
|
||||
} DelegateInfo;
|
||||
|
||||
static void delegate_info_done(DelegateInfo *p) {
|
||||
assert(p);
|
||||
|
||||
free(p->current_dns);
|
||||
strv_free(p->dns);
|
||||
strv_free(p->domains);
|
||||
}
|
||||
|
||||
static int map_delegate_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_delegate_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, userdata);
|
||||
}
|
||||
|
||||
static int map_delegate_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
|
||||
}
|
||||
|
||||
static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, bool *empty_line) {
|
||||
|
||||
static const struct bus_properties_map property_map[] = {
|
||||
{ "DNS", "a(iiayqs)", map_delegate_dns_servers, offsetof(DelegateInfo, dns) },
|
||||
{ "CurrentDNSServer", "(iiayqs)", map_delegate_current_dns_server, offsetof(DelegateInfo, current_dns) },
|
||||
{ "Domains", "a(sb)", map_delegate_domains, offsetof(DelegateInfo, domains) },
|
||||
{ "DefaultRoute", "b", NULL, offsetof(DelegateInfo, default_route) },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(delegate_info_done) DelegateInfo delegate_info = {};
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(id);
|
||||
|
||||
r = sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id, &p);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
log_info("→ %s", p);
|
||||
|
||||
r = bus_map_all_properties(
|
||||
bus,
|
||||
"org.freedesktop.resolve1",
|
||||
p,
|
||||
property_map,
|
||||
BUS_MAP_BOOLEAN_AS_BOOL,
|
||||
&error,
|
||||
&m,
|
||||
&delegate_info);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get delegate data for %s: %s", id, bus_error_message(&error, r));
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case STATUS_DNS:
|
||||
return status_print_strv_delegate(id, delegate_info.dns);
|
||||
|
||||
case STATUS_DOMAIN:
|
||||
return status_print_strv_delegate(id, delegate_info.domains);
|
||||
|
||||
case STATUS_DEFAULT_ROUTE:
|
||||
printf("%sDelegate %s%s: %s\n",
|
||||
ansi_highlight(), id, ansi_normal(),
|
||||
yes_no(delegate_info.default_route));
|
||||
|
||||
return 0;
|
||||
|
||||
case STATUS_ALL:
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (empty_line && *empty_line)
|
||||
fputc('\n', stdout);
|
||||
|
||||
printf("%sDelegate %s%s\n",
|
||||
ansi_highlight(), id, ansi_normal());
|
||||
|
||||
_cleanup_(table_unrefp) Table *table = table_new_vertical();
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
if (delegate_info.current_dns) {
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "Current DNS Server",
|
||||
TABLE_STRING, delegate_info.current_dns);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = dump_list(table, "DNS Servers", delegate_info.dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dump_list(table, "DNS Domain", delegate_info.domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "Default Route",
|
||||
TABLE_BOOLEAN, delegate_info.default_route);
|
||||
|
||||
r = table_print(table, NULL);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
if (empty_line)
|
||||
*empty_line = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_delegates(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r, ret = 0;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = bus_call_method(bus, bus_resolve_mgr, "ListDelegates", &error, &reply, NULL);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
|
||||
log_debug("Delegates not supported, skipping.");
|
||||
return 0;
|
||||
}
|
||||
return log_error_errno(r, "Failed to list delegates: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(so)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
for (;;) {
|
||||
const char *id;
|
||||
|
||||
r = sd_bus_message_read(reply, "(so)", &id, NULL);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (strv_extend(&l, id) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
strv_sort(l);
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
RET_GATHER(ret, status_delegate_one(bus, *i, mode, empty_line));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int status_all(sd_bus *bus, StatusMode mode) {
|
||||
bool empty_line = false;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = status_global(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = status_links(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = status_delegates(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_status(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
|
@ -14,10 +14,11 @@
|
||||
#include "path-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-def.h"
|
||||
#include "resolved-dns-delegate-bus.h"
|
||||
#include "resolved-dns-stream.h"
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-dnssd-bus.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-dnssd-bus.h"
|
||||
#include "resolved-link-bus.h"
|
||||
#include "resolved-resolv-conf.h"
|
||||
#include "socket-netlink.h"
|
||||
@ -2079,6 +2080,64 @@ static int bus_method_unregister_service(sd_bus_message *message, void *userdata
|
||||
return call_dnssd_method(m, message, bus_dnssd_method_unregister, error);
|
||||
}
|
||||
|
||||
static int bus_method_get_delegate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
const char *id;
|
||||
r = sd_bus_message_read(message, "s", &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
DnsDelegate *d = hashmap_get(m->delegates, id);
|
||||
if (!d)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DELEGATE, "Delegate '%s' not known", id);
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_reply_method_return(message, "o", p);
|
||||
}
|
||||
|
||||
static int bus_method_list_delegates(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(so)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(so)", d->id, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable resolve_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
@ -2217,6 +2276,16 @@ static const sd_bus_vtable resolve_vtable[] = {
|
||||
SD_BUS_NO_RESULT,
|
||||
bus_method_reset_server_features,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("GetDelegate",
|
||||
SD_BUS_ARGS("s", id),
|
||||
SD_BUS_RESULT("o", path),
|
||||
bus_method_get_delegate,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("ListDelegates",
|
||||
SD_BUS_NO_ARGS,
|
||||
SD_BUS_RESULT("a(so)", delegates),
|
||||
bus_method_list_delegates,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
@ -2226,7 +2295,8 @@ const BusObjectImplementation manager_object = {
|
||||
"org.freedesktop.resolve1.Manager",
|
||||
.vtables = BUS_VTABLES(resolve_vtable),
|
||||
.children = BUS_IMPLEMENTATIONS(&link_object,
|
||||
&dnssd_object),
|
||||
&dnssd_object,
|
||||
&dns_delegate_object),
|
||||
};
|
||||
|
||||
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
|
||||
|
@ -55,7 +55,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE);
|
||||
return dns_server_new(m, /* ret= */ NULL, type, /* link= */ NULL, /* delegate= */ NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE);
|
||||
}
|
||||
|
||||
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
|
||||
@ -100,7 +100,7 @@ static int manager_add_search_domain_by_string(Manager *m, const char *domain) {
|
||||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
|
||||
r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, domain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
153
src/resolve/resolved-dns-delegate-bus.c
Normal file
153
src/resolve/resolved-dns-delegate-bus.c
Normal file
@ -0,0 +1,153 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "bus-get-properties.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-dns-delegate-bus.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "strv.h"
|
||||
|
||||
static int property_get_dns(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(iiayqs)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH(servers, s, d->dns_servers) {
|
||||
r = bus_dns_server_append(reply, s, /* with_ifindex= */ true, /* extended= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int property_get_current_dns_server(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
|
||||
assert(reply);
|
||||
|
||||
return bus_dns_server_append(reply, d->current_dns_server, /* with_ifindex= */ true, /* extended= */ true);
|
||||
}
|
||||
|
||||
static int property_get_domains(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *delegate = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(sb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH(domains, d, delegate->search_domains) {
|
||||
r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int dns_delegate_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
assert(bus);
|
||||
assert(path);
|
||||
assert(interface);
|
||||
assert(found);
|
||||
|
||||
_cleanup_free_ char *e = NULL;
|
||||
if (sd_bus_path_decode(path, "/org/freedesktop/resolve1/dns_delegate", &e) <= 0)
|
||||
return 0;
|
||||
|
||||
DnsDelegate *d = hashmap_get(m->delegates, e);
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
*found = d;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* dns_delegate_bus_path(const DnsDelegate *d) {
|
||||
char *p;
|
||||
|
||||
assert(d);
|
||||
|
||||
if (sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", d->id, &p) < 0)
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int dns_delegate_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(path);
|
||||
assert(nodes);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume(&l, TAKE_PTR(p));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*nodes = TAKE_PTR(l);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable dns_delegate_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
|
||||
SD_BUS_PROPERTY("DNS", "a(iiayqs)", property_get_dns, 0, 0),
|
||||
SD_BUS_PROPERTY("CurrentDNSServer", "(iiayqs)", property_get_current_dns_server, 0, 0),
|
||||
SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
|
||||
SD_BUS_PROPERTY("DefaultRoute", "b", bus_property_get_tristate, offsetof(DnsDelegate, default_route), 0),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
const BusObjectImplementation dns_delegate_object = {
|
||||
"/org/freedesktop/resolve1/dns_delegate",
|
||||
"org.freedesktop.resolve1.DnsDelegate",
|
||||
.fallback_vtables = BUS_FALLBACK_VTABLES({dns_delegate_vtable, dns_delegate_object_find}),
|
||||
.node_enumerator = dns_delegate_node_enumerator,
|
||||
};
|
12
src/resolve/resolved-dns-delegate-bus.h
Normal file
12
src/resolve/resolved-dns-delegate-bus.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-object.h"
|
||||
#include "bus-util.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
|
||||
extern const BusObjectImplementation dns_delegate_object;
|
||||
|
||||
char* dns_delegate_bus_path(const DnsDelegate *d);
|
20
src/resolve/resolved-dns-delegate-gperf.gperf
Normal file
20
src/resolve/resolved-dns-delegate-gperf.gperf
Normal file
@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
%{
|
||||
#include <stddef.h>
|
||||
#include "conf-parser.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
%null_strings
|
||||
%language=ANSI-C
|
||||
%define slot-name section_and_lvalue
|
||||
%define hash-function-name resolved_dns_delegate_gperf_hash
|
||||
%define lookup-function-name resolved_dns_delegate_gperf_lookup
|
||||
%readonly-tables
|
||||
%omit-struct-type
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Delegate.DNS, config_parse_delegate_dns_servers, 0, 0
|
||||
Delegate.Domains, config_parse_delegate_domains, 0, 0
|
||||
Delegate.DefaultRoute, config_parse_tristate, 0, offsetof(DnsDelegate, default_route),
|
356
src/resolve/resolved-dns-delegate.c
Normal file
356
src/resolve/resolved-dns-delegate.c
Normal file
@ -0,0 +1,356 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "conf-files.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "path-util.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "socket-netlink.h"
|
||||
|
||||
#define DNS_DELEGATES_MAX 4096U
|
||||
#define DNS_DELEGATE_SEARCH_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/dns-delegate"))
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
dns_delegate_hash_ops,
|
||||
char,
|
||||
string_hash_func,
|
||||
string_compare_func,
|
||||
DnsDelegate,
|
||||
dns_delegate_free);
|
||||
|
||||
int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(id);
|
||||
|
||||
if (hashmap_size(m->delegates) >= DNS_DELEGATES_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
_cleanup_free_ char *id_copy = strdup(id);
|
||||
if (!id_copy)
|
||||
return -ENOMEM;
|
||||
|
||||
_cleanup_(dns_delegate_freep) DnsDelegate *d = new(DnsDelegate, 1);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
*d = (DnsDelegate) {
|
||||
.id = TAKE_PTR(id_copy),
|
||||
.default_route = -1,
|
||||
};
|
||||
|
||||
r = dns_scope_new(
|
||||
m,
|
||||
&d->scope,
|
||||
DNS_SCOPE_DELEGATE,
|
||||
/* link= */ NULL,
|
||||
d,
|
||||
DNS_PROTOCOL_DNS,
|
||||
AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_ensure_put(&m->delegates, &dns_delegate_hash_ops, d->id, d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
d->manager = m;
|
||||
|
||||
log_debug("New delegate '%s'.", id);
|
||||
|
||||
if (ret)
|
||||
*ret = d;
|
||||
|
||||
TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DnsDelegate *dns_delegate_free(DnsDelegate *d) {
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
Manager *m = d->manager;
|
||||
|
||||
log_debug("Removing delegate '%s'.", d->id);
|
||||
|
||||
dns_server_unlink_all(d->dns_servers);
|
||||
dns_search_domain_unlink_all(d->search_domains);
|
||||
|
||||
dns_scope_free(d->scope);
|
||||
|
||||
if (m)
|
||||
hashmap_remove(m->delegates, d->id);
|
||||
|
||||
free(d->id);
|
||||
|
||||
return mfree(d);
|
||||
}
|
||||
|
||||
DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s) {
|
||||
assert(d);
|
||||
|
||||
if (d->current_dns_server == s)
|
||||
return s;
|
||||
|
||||
if (s)
|
||||
log_debug("Switching delegate '%s' to DNS server %s.", d->id, strna(dns_server_string_full(s)));
|
||||
|
||||
dns_server_unref(d->current_dns_server);
|
||||
d->current_dns_server = dns_server_ref(s);
|
||||
|
||||
/* Skip flushing the cache if server stale feature is enabled. */
|
||||
if (d->manager->stale_retention_usec == 0)
|
||||
dns_cache_flush(&d->scope->cache);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
DnsServer *dns_delegate_get_dns_server(DnsDelegate *d) {
|
||||
assert(d);
|
||||
|
||||
if (!d->current_dns_server)
|
||||
dns_delegate_set_dns_server(d, d->dns_servers);
|
||||
|
||||
return d->current_dns_server;
|
||||
}
|
||||
|
||||
void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current) {
|
||||
assert(d);
|
||||
|
||||
/* If the current server of the transaction is specified, and we already are at a different one,
|
||||
* don't do anything */
|
||||
if (if_current && d->current_dns_server != if_current)
|
||||
return;
|
||||
|
||||
/* If currently have no DNS server, then don't do anything, we'll pick it lazily the next time a DNS
|
||||
* server is needed. */
|
||||
if (!d->current_dns_server)
|
||||
return;
|
||||
|
||||
/* Change to the next one, but make sure to follow the linked list only if this server is actually
|
||||
* still linked. */
|
||||
if (d->current_dns_server->linked && d->current_dns_server->servers_next) {
|
||||
dns_delegate_set_dns_server(d, d->current_dns_server->servers_next);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pick the first one again, after we reached the end */
|
||||
dns_delegate_set_dns_server(d, d->dns_servers);
|
||||
}
|
||||
|
||||
static int dns_delegate_load(Manager *m, const char *path) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
|
||||
|
||||
const char *e = endswith(fn, ".dns-delegate");
|
||||
if (!e)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name does not end in .dns-delegate, refusing: %s", fn);
|
||||
|
||||
_cleanup_free_ char *id = strndup(fn, e - fn);
|
||||
if (!string_is_safe(id))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name contains weird characters, refusing: %s", fn);
|
||||
|
||||
_cleanup_free_ char *dropin_dirname = strjoin(id, ".dns-delegate.d");
|
||||
if (!dropin_dirname)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_(dns_delegate_freep) DnsDelegate *d = NULL;
|
||||
r = dns_delegate_new(m, id, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate delegate '%s': %m", id);
|
||||
|
||||
r = config_parse_many(
|
||||
STRV_MAKE_CONST(path),
|
||||
DNS_DELEGATE_SEARCH_DIRS,
|
||||
dropin_dirname,
|
||||
/* root= */ NULL,
|
||||
"Delegate\0",
|
||||
config_item_perf_lookup,
|
||||
resolved_dns_delegate_gperf_lookup,
|
||||
/* flags= */ 0,
|
||||
d,
|
||||
/* ret_stats_by_path= */ NULL,
|
||||
/* ret_drop_in_files= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_info("Successfully loaded delegate '%s'.", d->id);
|
||||
|
||||
TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_load_delegates(Manager *m) {
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = conf_files_list_strv(&files, ".dns-delegate", /* root= */ NULL, /* flags= */ 0, DNS_DELEGATE_SEARCH_DIRS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate .dns-delegate files: %m");
|
||||
|
||||
STRV_FOREACH(f, files)
|
||||
(void) dns_delegate_load(m, *f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_delegate_dns_servers(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
/* Empty assignment means clear the list */
|
||||
if (isempty(rvalue)) {
|
||||
dns_server_unlink_all(d->dns_servers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, add to the list */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse DNS server string '%s', ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
_cleanup_free_ char *server_name = NULL;
|
||||
union in_addr_union address;
|
||||
int family, ifindex = 0;
|
||||
uint16_t port;
|
||||
r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse DNS server string '%s', ignoring.", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Silently filter out 0.0.0.0, 127.0.0.53, 127.0.0.54 (our own stub DNS listener) */
|
||||
if (!dns_server_address_valid(family, &address))
|
||||
continue;
|
||||
|
||||
/* By default, the port number is determined with the transaction feature level.
|
||||
* See dns_transaction_port() and dns_server_port(). */
|
||||
if (IN_SET(port, 53, 853))
|
||||
port = 0;
|
||||
|
||||
/* Filter out duplicates */
|
||||
DnsServer *s = dns_server_find(d->dns_servers, family, &address, port, ifindex, server_name);
|
||||
if (s) {
|
||||
/* Drop the marker. This is used to find the servers that ceased to exist, see
|
||||
* manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
|
||||
dns_server_move_back_and_unmark(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = dns_server_new(
|
||||
d->manager,
|
||||
/* ret= */ NULL,
|
||||
DNS_SERVER_DELEGATE,
|
||||
/* link= */ NULL,
|
||||
d,
|
||||
family,
|
||||
&address,
|
||||
port,
|
||||
ifindex,
|
||||
server_name,
|
||||
RESOLVE_CONFIG_SOURCE_FILE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add DNS server: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_delegate_domains(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
/* Empty assignment means clear the list */
|
||||
if (isempty(rvalue)) {
|
||||
dns_search_domain_unlink_all(d->search_domains);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, add to the list */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse search domains string '%s', ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
const char *name = word;
|
||||
|
||||
bool route_only = name[0] == '~';
|
||||
if (route_only)
|
||||
name++;
|
||||
|
||||
if (dns_name_is_root(name) || streq(name, "*")) {
|
||||
route_only = true;
|
||||
name = ".";
|
||||
}
|
||||
|
||||
DnsSearchDomain *domain;
|
||||
r = dns_search_domain_find(d->search_domains, name, &domain);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find search domain: %m");
|
||||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(domain);
|
||||
else {
|
||||
r = dns_search_domain_new(d->manager, &domain, DNS_SEARCH_DOMAIN_DELEGATE, /* link= */ NULL, d, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
domain->route_only = route_only;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
48
src/resolve/resolved-dns-delegate.h
Normal file
48
src/resolve/resolved-dns-delegate.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
|
||||
#include "resolved-dns-scope.h"
|
||||
#include "resolved-dns-search-domain.h"
|
||||
#include "resolved-dns-server.h"
|
||||
|
||||
#define DELEGATE_SEARCH_DOMAINS_MAX 256
|
||||
#define DELEGATE_DNS_SERVERS_MAX 256
|
||||
|
||||
/* A DnsDelegate object is used to manage additional, explicitly configured unicast DNS lookup scopes,
|
||||
* independent from any network link and from the global scope. */
|
||||
|
||||
struct DnsDelegate {
|
||||
Manager *manager;
|
||||
char *id;
|
||||
|
||||
LIST_HEAD(DnsServer, dns_servers);
|
||||
unsigned n_dns_servers;
|
||||
DnsServer *current_dns_server;
|
||||
|
||||
LIST_HEAD(DnsSearchDomain, search_domains);
|
||||
unsigned n_search_domains;
|
||||
|
||||
int default_route;
|
||||
|
||||
DnsScope *scope;
|
||||
|
||||
LIST_FIELDS(DnsDelegate, delegates);
|
||||
};
|
||||
|
||||
int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret);
|
||||
DnsDelegate *dns_delegate_free(DnsDelegate *d);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsDelegate*, dns_delegate_free);
|
||||
|
||||
DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s);
|
||||
DnsServer *dns_delegate_get_dns_server(DnsDelegate *d);
|
||||
void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current);
|
||||
|
||||
int manager_load_delegates(Manager *m);
|
||||
|
||||
const struct ConfigPerfItem* resolved_dns_delegate_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_delegate_dns_servers);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_delegate_domains);
|
@ -11,12 +11,14 @@
|
||||
#include "missing_network.h"
|
||||
#include "random-util.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-scope.h"
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-dns-zone.h"
|
||||
#include "resolved-llmnr.h"
|
||||
#include "resolved-mdns.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
|
||||
#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
|
||||
@ -26,11 +28,24 @@
|
||||
#define MULTICAST_RESEND_TIMEOUT_MIN_USEC (100 * USEC_PER_MSEC)
|
||||
#define MULTICAST_RESEND_TIMEOUT_MAX_USEC (1 * USEC_PER_SEC)
|
||||
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
|
||||
int dns_scope_new(
|
||||
Manager *m,
|
||||
DnsScope **ret,
|
||||
DnsScopeOrigin origin,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
DnsProtocol protocol,
|
||||
int family) {
|
||||
|
||||
DnsScope *s;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
assert(origin >= 0);
|
||||
assert(origin < _DNS_SCOPE_ORIGIN_MAX);
|
||||
|
||||
assert(!!link == (origin == DNS_SCOPE_LINK));
|
||||
assert(!!delegate == (origin == DNS_SCOPE_DELEGATE));
|
||||
|
||||
s = new(DnsScope, 1);
|
||||
if (!s)
|
||||
@ -38,7 +53,9 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
||||
|
||||
*s = (DnsScope) {
|
||||
.manager = m,
|
||||
.link = l,
|
||||
.link = link,
|
||||
.delegate = delegate,
|
||||
.origin = origin,
|
||||
.protocol = protocol,
|
||||
.family = family,
|
||||
.resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC,
|
||||
@ -54,9 +71,9 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
||||
* not update it from the on, even if the setting
|
||||
* changes. */
|
||||
|
||||
if (l) {
|
||||
s->dnssec_mode = link_get_dnssec_mode(l);
|
||||
s->dns_over_tls_mode = link_get_dns_over_tls_mode(l);
|
||||
if (link) {
|
||||
s->dnssec_mode = link_get_dnssec_mode(link);
|
||||
s->dns_over_tls_mode = link_get_dns_over_tls_mode(link);
|
||||
} else {
|
||||
s->dnssec_mode = manager_get_dnssec_mode(m);
|
||||
s->dns_over_tls_mode = manager_get_dns_over_tls_mode(m);
|
||||
@ -72,7 +89,12 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
||||
dns_scope_llmnr_membership(s, true);
|
||||
dns_scope_mdns_membership(s, true);
|
||||
|
||||
log_debug("New scope on link %s, protocol %s, family %s", l ? l->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
|
||||
log_debug("New scope on link %s, protocol %s, family %s, origin %s, delegate %s",
|
||||
link ? link->ifname : "*",
|
||||
dns_protocol_to_string(protocol),
|
||||
family == AF_UNSPEC ? "*" : af_to_name(family),
|
||||
dns_scope_origin_to_string(origin),
|
||||
s->delegate ? s->delegate->id : "n/a");
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
@ -100,7 +122,12 @@ DnsScope* dns_scope_free(DnsScope *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->ifname : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
|
||||
log_debug("Removing scope on link %s, protocol %s, family %s, origin %s, delegate %s",
|
||||
s->link ? s->link->ifname : "*",
|
||||
dns_protocol_to_string(s->protocol),
|
||||
s->family == AF_UNSPEC ? "*" : af_to_name(s->family),
|
||||
dns_scope_origin_to_string(s->origin),
|
||||
s->delegate ? s->delegate->id : "n/a");
|
||||
|
||||
dns_scope_llmnr_membership(s, false);
|
||||
dns_scope_mdns_membership(s, false);
|
||||
@ -133,6 +160,8 @@ DnsServer *dns_scope_get_dns_server(DnsScope *s) {
|
||||
|
||||
if (s->link)
|
||||
return link_get_dns_server(s->link);
|
||||
else if (s->delegate)
|
||||
return dns_delegate_get_dns_server(s->delegate);
|
||||
else
|
||||
return manager_get_dns_server(s->manager);
|
||||
}
|
||||
@ -145,6 +174,8 @@ unsigned dns_scope_get_n_dns_servers(DnsScope *s) {
|
||||
|
||||
if (s->link)
|
||||
return s->link->n_dns_servers;
|
||||
else if (s->delegate)
|
||||
return s->delegate->n_dns_servers;
|
||||
else
|
||||
return s->manager->n_dns_servers;
|
||||
}
|
||||
@ -160,6 +191,8 @@ void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) {
|
||||
|
||||
if (s->link)
|
||||
link_next_dns_server(s->link, if_current);
|
||||
else if (s->delegate)
|
||||
dns_delegate_next_dns_server(s->delegate, if_current);
|
||||
else
|
||||
manager_next_dns_server(s->manager, if_current);
|
||||
}
|
||||
@ -267,6 +300,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) {
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
assert(s->link);
|
||||
r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, LLMNR_PORT, NULL, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -298,6 +332,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) {
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
assert(s->link);
|
||||
r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, p->destination_port ?: MDNS_PORT, NULL, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1374,6 +1409,14 @@ void dns_scope_dump(DnsScope *s, FILE *f) {
|
||||
fputs(af_to_name(s->family), f);
|
||||
}
|
||||
|
||||
fputs(" origin=", f);
|
||||
fputs(dns_scope_origin_to_string(s->origin), f);
|
||||
|
||||
if (s->delegate) {
|
||||
fputs(" id=", f);
|
||||
fputs(s->delegate->id, f);
|
||||
}
|
||||
|
||||
fputs("]\n", f);
|
||||
|
||||
if (!dns_zone_is_empty(&s->zone)) {
|
||||
@ -1395,6 +1438,8 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
|
||||
|
||||
if (s->link)
|
||||
return s->link->search_domains;
|
||||
if (s->delegate)
|
||||
return s->delegate->search_domains;
|
||||
|
||||
return s->manager->search_domains;
|
||||
}
|
||||
@ -1680,6 +1725,8 @@ static bool dns_scope_has_route_only_domains(DnsScope *scope) {
|
||||
|
||||
if (scope->link)
|
||||
first = scope->link->search_domains;
|
||||
else if (scope->delegate)
|
||||
first = scope->delegate->search_domains;
|
||||
else
|
||||
first = scope->manager->search_domains;
|
||||
|
||||
@ -1705,18 +1752,27 @@ bool dns_scope_is_default_route(DnsScope *scope) {
|
||||
if (scope->protocol != DNS_PROTOCOL_DNS)
|
||||
return false;
|
||||
|
||||
/* The global DNS scope is always suitable as default route */
|
||||
if (!scope->link)
|
||||
if (scope->link) {
|
||||
|
||||
/* Honour whatever is explicitly configured. This is really the best approach, and trumps any
|
||||
* automatic logic. */
|
||||
if (scope->link->default_route >= 0)
|
||||
return scope->link->default_route;
|
||||
|
||||
/* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not
|
||||
* volunteer as default route. */
|
||||
return !dns_scope_has_route_only_domains(scope);
|
||||
|
||||
} else if (scope->delegate) {
|
||||
|
||||
if (scope->delegate->default_route >= 0)
|
||||
return scope->delegate->default_route;
|
||||
|
||||
/* Delegates are by default not used as default route */
|
||||
return false;
|
||||
} else
|
||||
/* The global DNS scope is always suitable as default route */
|
||||
return true;
|
||||
|
||||
/* Honour whatever is explicitly configured. This is really the best approach, and trumps any
|
||||
* automatic logic. */
|
||||
if (scope->link->default_route >= 0)
|
||||
return scope->link->default_route;
|
||||
|
||||
/* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not
|
||||
* volunteer as default route. */
|
||||
return !dns_scope_has_route_only_domains(scope);
|
||||
}
|
||||
|
||||
int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) {
|
||||
@ -1800,3 +1856,11 @@ int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protoco
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* const dns_scope_origin_table[_DNS_SCOPE_ORIGIN_MAX] = {
|
||||
[DNS_SCOPE_GLOBAL] = "global",
|
||||
[DNS_SCOPE_LINK] = "link",
|
||||
[DNS_SCOPE_DELEGATE] = "delegate",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(dns_scope_origin, DnsScopeOrigin);
|
||||
|
@ -26,9 +26,19 @@ typedef enum DnsScopeMatch {
|
||||
_DNS_SCOPE_MATCH_INVALID = -EINVAL,
|
||||
} DnsScopeMatch;
|
||||
|
||||
typedef enum DnsScopeOrigin {
|
||||
DNS_SCOPE_GLOBAL,
|
||||
DNS_SCOPE_LINK,
|
||||
DNS_SCOPE_DELEGATE,
|
||||
_DNS_SCOPE_ORIGIN_MAX,
|
||||
_DNS_SCOPE_ORIGIN_INVALID = -EINVAL,
|
||||
} DnsScopeOrigin;
|
||||
|
||||
struct DnsScope {
|
||||
Manager *manager;
|
||||
|
||||
DnsScopeOrigin origin;
|
||||
|
||||
DnsProtocol protocol;
|
||||
int family;
|
||||
|
||||
@ -37,6 +47,7 @@ struct DnsScope {
|
||||
DnsOverTlsMode dns_over_tls_mode;
|
||||
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
DnsCache cache;
|
||||
DnsZone zone;
|
||||
@ -69,7 +80,7 @@ struct DnsScope {
|
||||
bool announced;
|
||||
};
|
||||
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, DnsScopeOrigin origin, Link *link, DnsDelegate *delegate, DnsProtocol protocol, int family);
|
||||
DnsScope* dns_scope_free(DnsScope *s);
|
||||
|
||||
void dns_scope_packet_received(DnsScope *s, usec_t rtt);
|
||||
@ -119,3 +130,6 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret);
|
||||
|
||||
int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol);
|
||||
int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol);
|
||||
|
||||
const char* dns_scope_origin_to_string(DnsScopeOrigin origin) _const_;
|
||||
DnsScopeOrigin dns_scope_origin_from_string(const char *s) _pure_;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-search-domain.h"
|
||||
#include "resolved-link.h"
|
||||
#include "resolved-manager.h"
|
||||
@ -10,7 +11,8 @@ int dns_search_domain_new(
|
||||
Manager *m,
|
||||
DnsSearchDomain **ret,
|
||||
DnsSearchDomainType type,
|
||||
Link *l,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
const char *name) {
|
||||
|
||||
_cleanup_free_ char *normalized = NULL;
|
||||
@ -18,15 +20,19 @@ int dns_search_domain_new(
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
|
||||
assert((type == DNS_SEARCH_DOMAIN_LINK) == !!link);
|
||||
assert((type == DNS_SEARCH_DOMAIN_DELEGATE) == !!delegate);
|
||||
assert(name);
|
||||
|
||||
r = dns_name_normalize(name, 0, &normalized);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (l) {
|
||||
if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
|
||||
if (link) {
|
||||
if (link->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
|
||||
return -E2BIG;
|
||||
} else if (delegate) {
|
||||
if (delegate->n_search_domains >= DELEGATE_SEARCH_DOMAINS_MAX)
|
||||
return -E2BIG;
|
||||
} else {
|
||||
if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX)
|
||||
@ -47,9 +53,9 @@ int dns_search_domain_new(
|
||||
switch (type) {
|
||||
|
||||
case DNS_SEARCH_DOMAIN_LINK:
|
||||
d->link = l;
|
||||
LIST_APPEND(domains, l->search_domains, d);
|
||||
l->n_search_domains++;
|
||||
d->link = link;
|
||||
LIST_APPEND(domains, link->search_domains, d);
|
||||
link->n_search_domains++;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_SYSTEM:
|
||||
@ -57,6 +63,12 @@ int dns_search_domain_new(
|
||||
m->n_search_domains++;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
d->delegate = delegate;
|
||||
LIST_APPEND(domains, delegate->search_domains, d);
|
||||
delegate->n_search_domains++;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -99,6 +111,13 @@ void dns_search_domain_unlink(DnsSearchDomain *d) {
|
||||
LIST_REMOVE(domains, d->manager->search_domains, d);
|
||||
d->manager->n_search_domains--;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
assert(d->delegate);
|
||||
assert(d->delegate->n_search_domains > 0);
|
||||
LIST_REMOVE(domains, d->delegate->search_domains, d);
|
||||
d->delegate->n_search_domains--;
|
||||
break;
|
||||
}
|
||||
|
||||
d->linked = false;
|
||||
@ -134,6 +153,13 @@ void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) {
|
||||
LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d);
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
assert(d->delegate);
|
||||
tail = LIST_FIND_TAIL(domains, d);
|
||||
LIST_REMOVE(domains, d->delegate->search_domains, d);
|
||||
LIST_INSERT_AFTER(domains, d->delegate->search_domains, tail, d);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
@ -7,10 +7,12 @@
|
||||
typedef struct DnsSearchDomain DnsSearchDomain;
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
|
||||
typedef enum DnsSearchDomainType {
|
||||
DNS_SEARCH_DOMAIN_SYSTEM,
|
||||
DNS_SEARCH_DOMAIN_LINK,
|
||||
DNS_SEARCH_DOMAIN_DELEGATE,
|
||||
} DnsSearchDomainType;
|
||||
|
||||
struct DnsSearchDomain {
|
||||
@ -20,6 +22,7 @@ struct DnsSearchDomain {
|
||||
|
||||
DnsSearchDomainType type;
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
char *name;
|
||||
|
||||
@ -35,6 +38,7 @@ int dns_search_domain_new(
|
||||
DnsSearchDomain **ret,
|
||||
DnsSearchDomainType type,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
const char *name);
|
||||
|
||||
DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-server.h"
|
||||
#include "resolved-dns-stub.h"
|
||||
#include "resolved-manager.h"
|
||||
@ -23,7 +24,8 @@ int dns_server_new(
|
||||
Manager *m,
|
||||
DnsServer **ret,
|
||||
DnsServerType type,
|
||||
Link *l,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
uint16_t port,
|
||||
@ -35,14 +37,18 @@ int dns_server_new(
|
||||
DnsServer *s;
|
||||
|
||||
assert(m);
|
||||
assert((type == DNS_SERVER_LINK) == !!l);
|
||||
assert((type == DNS_SERVER_LINK) == !!link);
|
||||
assert((type == DNS_SERVER_DELEGATE) == !!delegate);
|
||||
assert(in_addr);
|
||||
|
||||
if (!IN_SET(family, AF_INET, AF_INET6))
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (l) {
|
||||
if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX)
|
||||
if (link) {
|
||||
if (link->n_dns_servers >= LINK_DNS_SERVERS_MAX)
|
||||
return -E2BIG;
|
||||
} else if (delegate) {
|
||||
if (delegate->n_dns_servers >= DELEGATE_DNS_SERVERS_MAX)
|
||||
return -E2BIG;
|
||||
} else {
|
||||
if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX)
|
||||
@ -76,9 +82,9 @@ int dns_server_new(
|
||||
switch (type) {
|
||||
|
||||
case DNS_SERVER_LINK:
|
||||
s->link = l;
|
||||
LIST_APPEND(servers, l->dns_servers, s);
|
||||
l->n_dns_servers++;
|
||||
s->link = link;
|
||||
LIST_APPEND(servers, link->dns_servers, s);
|
||||
link->n_dns_servers++;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_SYSTEM:
|
||||
@ -91,16 +97,20 @@ int dns_server_new(
|
||||
m->n_dns_servers++;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
s->delegate = delegate;
|
||||
LIST_APPEND(servers, delegate->dns_servers, s);
|
||||
delegate->n_dns_servers++;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
s->linked = true;
|
||||
|
||||
/* A new DNS server that isn't fallback is added and the one
|
||||
* we used so far was a fallback one? Then let's try to pick
|
||||
* the new one */
|
||||
if (type != DNS_SERVER_FALLBACK && dns_server_is_fallback(m->current_dns_server))
|
||||
/* A new non-fallback DNS server is added and the one we used so far was a fallback one? Then
|
||||
* let's try to pick the new one */
|
||||
if (type == DNS_SERVER_SYSTEM && dns_server_is_fallback(m->current_dns_server))
|
||||
manager_set_dns_server(m, NULL);
|
||||
|
||||
if (ret)
|
||||
@ -157,6 +167,14 @@ void dns_server_unlink(DnsServer *s) {
|
||||
LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
|
||||
s->manager->n_dns_servers--;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
assert(s->delegate);
|
||||
assert(s->delegate->n_dns_servers > 0);
|
||||
LIST_REMOVE(servers, s->delegate->dns_servers, s);
|
||||
s->delegate->n_dns_servers--;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -169,6 +187,9 @@ void dns_server_unlink(DnsServer *s) {
|
||||
if (s->manager->current_dns_server == s)
|
||||
manager_set_dns_server(s->manager, NULL);
|
||||
|
||||
if (s->delegate && s->delegate->current_dns_server == s)
|
||||
dns_delegate_set_dns_server(s->delegate, NULL);
|
||||
|
||||
/* No need to keep a default stream around anymore */
|
||||
dns_server_unref_stream(s);
|
||||
|
||||
@ -188,8 +209,8 @@ void dns_server_move_back_and_unmark(DnsServer *s) {
|
||||
if (!s->linked || !s->servers_next)
|
||||
return;
|
||||
|
||||
/* Move us to the end of the list, so that the order is
|
||||
* strictly kept, if we are not at the end anyway. */
|
||||
/* Move us to the end of the list, so that the order is strictly kept, if we are not at the end
|
||||
* anyway. */
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
@ -212,6 +233,13 @@ void dns_server_move_back_and_unmark(DnsServer *s) {
|
||||
LIST_INSERT_AFTER(servers, s->manager->fallback_dns_servers, tail, s);
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
assert(s->delegate);
|
||||
tail = LIST_FIND_TAIL(servers, s);
|
||||
LIST_REMOVE(servers, s->delegate->dns_servers, s);
|
||||
LIST_INSERT_AFTER(servers, s->delegate->dns_servers, tail, s);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -879,8 +907,23 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
DnsServer *manager_get_dns_server(Manager *m) {
|
||||
static bool manager_search_default_rote_dns_server(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
if (l->dns_servers && l->default_route)
|
||||
return true;
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
if (d->dns_servers && d->default_route)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DnsServer *manager_get_dns_server(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
/* Try to read updates resolv.conf */
|
||||
@ -899,22 +942,10 @@ DnsServer *manager_get_dns_server(Manager *m) {
|
||||
manager_set_dns_server(m, NULL);
|
||||
}
|
||||
|
||||
if (!m->current_dns_server) {
|
||||
bool found = false;
|
||||
|
||||
/* No DNS servers configured, let's see if there are
|
||||
* any on any links. If not, we use the fallback
|
||||
* servers */
|
||||
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
if (l->dns_servers && l->default_route) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
manager_set_dns_server(m, m->fallback_dns_servers);
|
||||
}
|
||||
/* If no DNS servers are configured, let's see if there are any on any links. If not, we use the
|
||||
* fallback servers */
|
||||
if (!m->current_dns_server && !manager_search_default_rote_dns_server(m))
|
||||
manager_set_dns_server(m, m->fallback_dns_servers);
|
||||
|
||||
return m->current_dns_server;
|
||||
}
|
||||
@ -970,11 +1001,15 @@ void dns_server_flush_cache(DnsServer *s) {
|
||||
|
||||
/* Flush the cache of the scope this server belongs to */
|
||||
|
||||
current = s->link ? s->link->current_dns_server : s->manager->current_dns_server;
|
||||
current = s->link ? s->link->current_dns_server :
|
||||
s->delegate ? s->delegate->current_dns_server :
|
||||
s->manager->current_dns_server;
|
||||
if (current != s)
|
||||
return;
|
||||
|
||||
scope = s->link ? s->link->unicast_scope : s->manager->unicast_scope;
|
||||
scope = s->link ? s->link->unicast_scope :
|
||||
s->delegate ? s->delegate->scope :
|
||||
s->manager->unicast_scope;
|
||||
if (!scope)
|
||||
return;
|
||||
|
||||
@ -1079,10 +1114,14 @@ void dns_server_unref_stream(DnsServer *s) {
|
||||
|
||||
DnsScope *dns_server_scope(DnsServer *s) {
|
||||
assert(s);
|
||||
assert(s->linked);
|
||||
assert((s->type == DNS_SERVER_LINK) == !!s->link);
|
||||
assert((s->type == DNS_SERVER_DELEGATE) == !!s->delegate);
|
||||
|
||||
if (s->link)
|
||||
return s->link->unicast_scope;
|
||||
if (s->delegate)
|
||||
return s->delegate->scope;
|
||||
|
||||
return s->manager->unicast_scope;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct DnsScope DnsScope;
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
typedef struct DnsServer DnsServer;
|
||||
typedef struct DnsStream DnsStream;
|
||||
typedef struct DnsPacket DnsPacket;
|
||||
@ -21,6 +22,7 @@ typedef enum DnsServerType {
|
||||
DNS_SERVER_SYSTEM,
|
||||
DNS_SERVER_FALLBACK,
|
||||
DNS_SERVER_LINK,
|
||||
DNS_SERVER_DELEGATE,
|
||||
_DNS_SERVER_TYPE_MAX,
|
||||
_DNS_SERVER_TYPE_INVALID = -EINVAL,
|
||||
} DnsServerType;
|
||||
@ -58,6 +60,7 @@ struct DnsServer {
|
||||
|
||||
DnsServerType type;
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
@ -113,6 +116,7 @@ int dns_server_new(
|
||||
DnsServer **ret,
|
||||
DnsServerType type,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
int family,
|
||||
const union in_addr_union *address,
|
||||
uint16_t port,
|
||||
|
@ -274,7 +274,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
||||
if (s)
|
||||
dns_server_move_back_and_unmark(s);
|
||||
else {
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS);
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS);
|
||||
if (r < 0) {
|
||||
dns_server_unlink_all(l->dns_servers);
|
||||
goto finalize;
|
||||
@ -282,7 +282,6 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
changed = dns_server_unlink_marked(l->dns_servers) || changed;
|
||||
@ -402,7 +401,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
|
||||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name);
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
|
||||
|
@ -133,7 +133,7 @@ void link_allocate_scopes(Link *l) {
|
||||
if (!l->unicast_scope) {
|
||||
dns_server_reset_features_all(l->dns_servers);
|
||||
|
||||
r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
r = dns_scope_new(l->manager, &l->unicast_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate DNS scope, ignoring: %m");
|
||||
}
|
||||
@ -143,7 +143,7 @@ void link_allocate_scopes(Link *l) {
|
||||
if (link_relevant(l, AF_INET, true) &&
|
||||
link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->llmnr_ipv4_scope) {
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv4 scope, ignoring: %m");
|
||||
}
|
||||
@ -153,7 +153,7 @@ void link_allocate_scopes(Link *l) {
|
||||
if (link_relevant(l, AF_INET6, true) &&
|
||||
link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->llmnr_ipv6_scope) {
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET6);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv6 scope, ignoring: %m");
|
||||
}
|
||||
@ -163,7 +163,7 @@ void link_allocate_scopes(Link *l) {
|
||||
if (link_relevant(l, AF_INET, true) &&
|
||||
link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->mdns_ipv4_scope) {
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m");
|
||||
}
|
||||
@ -173,7 +173,7 @@ void link_allocate_scopes(Link *l) {
|
||||
if (link_relevant(l, AF_INET6, true) &&
|
||||
link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->mdns_ipv6_scope) {
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET6);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m");
|
||||
}
|
||||
@ -273,7 +273,7 @@ static int link_update_dns_server_one(Link *l, const char *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD);
|
||||
return dns_server_new(l->manager, /* ret= */ NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD);
|
||||
}
|
||||
|
||||
static int link_update_dns_servers(Link *l) {
|
||||
@ -493,7 +493,7 @@ static int link_update_search_domain_one(Link *l, const char *name, bool route_o
|
||||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "random-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-conf.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-stub.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-etc-hosts.h"
|
||||
@ -522,6 +523,10 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(servers, server, l->dns_servers)
|
||||
dns_server_dump(server, f);
|
||||
DnsDelegate *delegate;
|
||||
HASHMAP_FOREACH(delegate, m->delegates)
|
||||
LIST_FOREACH(servers, server, delegate->dns_servers)
|
||||
dns_server_dump(server, f);
|
||||
|
||||
return memstream_dump(LOG_INFO, &ms);
|
||||
}
|
||||
@ -599,6 +604,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
|
||||
m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners);
|
||||
dnssd_service_clear_on_reload(m->dnssd_services);
|
||||
m->unicast_scope = dns_scope_free(m->unicast_scope);
|
||||
m->delegates = hashmap_free(m->delegates);
|
||||
|
||||
dns_trust_anchor_flush(&m->trust_anchor);
|
||||
|
||||
@ -616,9 +622,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to load DNS-SD configuration files: %m");
|
||||
|
||||
manager_load_delegates(m);
|
||||
|
||||
/* The default scope configuration is influenced by the manager's configuration (modes, etc.), so
|
||||
* recreate it on reload. */
|
||||
r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -699,7 +707,9 @@ int manager_new(Manager **ret) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to load DNS-SD configuration files: %m");
|
||||
|
||||
r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
manager_load_delegates(m);
|
||||
|
||||
r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -768,7 +778,6 @@ int manager_start(Manager *m) {
|
||||
|
||||
Manager *manager_free(Manager *m) {
|
||||
Link *l;
|
||||
DnssdService *s;
|
||||
|
||||
if (!m)
|
||||
return NULL;
|
||||
@ -780,12 +789,13 @@ Manager *manager_free(Manager *m) {
|
||||
while ((l = hashmap_first(m->links)))
|
||||
link_free(l);
|
||||
|
||||
m->delegates = hashmap_free(m->delegates);
|
||||
|
||||
while (m->dns_queries)
|
||||
dns_query_free(m->dns_queries);
|
||||
|
||||
m->stub_queries_by_packet = hashmap_free(m->stub_queries_by_packet);
|
||||
|
||||
dns_scope_free(m->unicast_scope);
|
||||
m->unicast_scope = dns_scope_free(m->unicast_scope);
|
||||
|
||||
/* At this point only orphaned streams should remain. All others should have been freed already by their
|
||||
* owners */
|
||||
@ -833,6 +843,7 @@ Manager *manager_free(Manager *m) {
|
||||
free(m->llmnr_hostname);
|
||||
free(m->mdns_hostname);
|
||||
|
||||
DnssdService *s;
|
||||
while ((s = hashmap_first(m->dnssd_services)))
|
||||
dnssd_service_free(s);
|
||||
hashmap_free(m->dnssd_services);
|
||||
@ -1560,7 +1571,7 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
||||
}
|
||||
|
||||
/* Then, add the per-link servers */
|
||||
HASHMAP_FOREACH(l, m->links) {
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(servers, s, l->dns_servers) {
|
||||
r = ordered_set_put(*dns, s);
|
||||
if (r == -EEXIST)
|
||||
@ -1568,7 +1579,17 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Third, add the delegate servers and domains */
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
LIST_FOREACH(servers, s, d->dns_servers) {
|
||||
r = ordered_set_put(*dns, s);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If we found nothing, add the fallback servers */
|
||||
if (ordered_set_isempty(*dns)) {
|
||||
@ -1590,7 +1611,6 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
||||
* > 0 or true: return only domains which are for routing only
|
||||
*/
|
||||
int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) {
|
||||
Link *l;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -1613,8 +1633,23 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_
|
||||
return r;
|
||||
}
|
||||
|
||||
HASHMAP_FOREACH(l, m->links) {
|
||||
DnsDelegate *delegate;
|
||||
HASHMAP_FOREACH(delegate, m->delegates)
|
||||
LIST_FOREACH(domains, d, delegate->search_domains) {
|
||||
|
||||
if (filter_route >= 0 &&
|
||||
d->route_only != !!filter_route)
|
||||
continue;
|
||||
|
||||
r = ordered_set_put(*domains, d->name);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(domains, d, l->search_domains) {
|
||||
|
||||
if (filter_route >= 0 &&
|
||||
@ -1627,7 +1662,6 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1710,14 +1744,18 @@ void manager_flush_caches(Manager *m, int log_level) {
|
||||
}
|
||||
|
||||
void manager_reset_server_features(Manager *m) {
|
||||
Link *l;
|
||||
|
||||
dns_server_reset_features_all(m->dns_servers);
|
||||
dns_server_reset_features_all(m->fallback_dns_servers);
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
dns_server_reset_features_all(l->dns_servers);
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
dns_server_reset_features_all(d->dns_servers);
|
||||
|
||||
log_info("Resetting learnt feature levels on all servers.");
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,8 @@ struct Manager {
|
||||
LIST_HEAD(DnsScope, dns_scopes);
|
||||
DnsScope *unicast_scope;
|
||||
|
||||
Hashmap *delegates; /* id string → DnsDelegate objects */
|
||||
|
||||
/* LLMNR */
|
||||
int llmnr_ipv4_udp_fd;
|
||||
int llmnr_ipv6_udp_fd;
|
||||
|
@ -781,7 +781,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
||||
}
|
||||
|
||||
if (cfg->has_scope) {
|
||||
ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link, env->protocol, env->family));
|
||||
ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link ? DNS_SCOPE_LINK : DNS_SCOPE_GLOBAL, env->link, /* delegate= */ NULL, env->protocol, env->family));
|
||||
ASSERT_NOT_NULL(env->scope);
|
||||
|
||||
env->server_addr.in.s_addr = htobe32(0x7f000001);
|
||||
@ -789,7 +789,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
||||
env->server_port = 53;
|
||||
|
||||
ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type,
|
||||
env->link, env->family, &env->server_addr, env->server_port,
|
||||
env->link, /* delegate= */ NULL, env->family, &env->server_addr, env->server_port,
|
||||
env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS));
|
||||
|
||||
ASSERT_NOT_NULL(env->server);
|
||||
@ -803,7 +803,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
||||
|
||||
for (size_t i = 0 ; i < env->n_search_domains; i++) {
|
||||
DnsSearchDomainType type = (env->link == NULL) ? DNS_SEARCH_DOMAIN_SYSTEM : DNS_SEARCH_DOMAIN_LINK;
|
||||
ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, SEARCH_DOMAINS[i]));
|
||||
ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, /* delegate= */ NULL, SEARCH_DOMAINS[i]));
|
||||
ASSERT_NOT_NULL(env->search_domains[i]);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ TEST(dns_search_domain_new_system) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd = NULL;
|
||||
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
ASSERT_TRUE(sd->linked);
|
||||
@ -41,12 +41,12 @@ TEST(dns_search_domain_new_system_limit) {
|
||||
DnsSearchDomain *sd = NULL;
|
||||
|
||||
for (size_t i = 0; i < MANAGER_SEARCH_DOMAINS_MAX; i++) {
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
ASSERT_EQ(manager.n_search_domains, i + 1);
|
||||
}
|
||||
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"), E2BIG);
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"), E2BIG);
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
dns_search_domain_unlink_all(manager.search_domains);
|
||||
@ -60,7 +60,7 @@ TEST(dns_search_domain_new_link) {
|
||||
ASSERT_OK(link_new(&manager, &link, 1));
|
||||
ASSERT_NOT_NULL(link);
|
||||
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local."));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local."));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
ASSERT_TRUE(sd->linked);
|
||||
@ -76,12 +76,12 @@ TEST(dns_search_domain_new_link_limit) {
|
||||
ASSERT_NOT_NULL(link);
|
||||
|
||||
for (size_t i = 0; i < LINK_SEARCH_DOMAINS_MAX; i++) {
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
ASSERT_EQ(link->n_search_domains, i + 1);
|
||||
}
|
||||
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local"), E2BIG);
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"), E2BIG);
|
||||
ASSERT_NOT_NULL(sd);
|
||||
}
|
||||
|
||||
@ -94,13 +94,13 @@ TEST(dns_search_domain_unlink_system) {
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd3 = NULL;
|
||||
DnsSearchDomain *sd2 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(sd2->linked);
|
||||
@ -123,13 +123,13 @@ TEST(dns_search_domain_unlink_link) {
|
||||
ASSERT_OK(link_new(&manager, &link, 1));
|
||||
ASSERT_NOT_NULL(link);
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(sd2->linked);
|
||||
@ -151,13 +151,13 @@ TEST(dns_search_domain_mark_all) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_FALSE(sd1->marked);
|
||||
@ -179,13 +179,13 @@ TEST(dns_search_domain_move_back_and_unmark) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_move_back_and_unmark(sd1);
|
||||
@ -211,13 +211,13 @@ TEST(dns_search_domain_unlink_marked) {
|
||||
DnsSearchDomain *sd1 = NULL, *sd2 = NULL;
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_unlink_marked(sd1);
|
||||
@ -245,13 +245,13 @@ TEST(dns_search_domain_unlink_all) {
|
||||
Manager manager = {};
|
||||
DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_unlink_all(sd1);
|
||||
@ -267,13 +267,13 @@ TEST(dns_search_domain_find) {
|
||||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL, *ret = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(dns_search_domain_find(sd1, "local", &ret));
|
||||
|
@ -26,7 +26,7 @@ TEST(dns_zone_put_simple) {
|
||||
DnsZoneItem *item = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
ASSERT_OK(dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET));
|
||||
ASSERT_OK(dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET));
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -50,7 +50,7 @@ TEST(dns_zone_put_any_class_is_invalid) {
|
||||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -68,7 +68,7 @@ TEST(dns_zone_put_any_type_is_invalid) {
|
||||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -90,7 +90,7 @@ TEST(dns_zone_remove_rr_match) {
|
||||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -115,7 +115,7 @@ TEST(dns_zone_remove_rr_match_one) {
|
||||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -148,7 +148,7 @@ TEST(dns_zone_remove_rr_different_payload) {
|
||||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -178,7 +178,7 @@ TEST(dns_zone_remove_rrs_by_key) {
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr1 = NULL, *rr2 = NULL, *rr3 = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
@ -248,7 +248,7 @@ TEST(dns_zone_lookup_match_a) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
@ -270,7 +270,7 @@ TEST(dns_zone_lookup_match_cname) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
@ -293,7 +293,7 @@ TEST(dns_zone_lookup_match_any) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
@ -324,7 +324,7 @@ TEST(dns_zone_lookup_match_any_apex) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
@ -349,7 +349,7 @@ TEST(dns_zone_lookup_match_nothing) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
@ -370,7 +370,7 @@ TEST(dns_zone_lookup_match_nothing_with_soa) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -182,7 +182,7 @@ static void link_alloc_env_setup(LinkAllocEnv *env, int family, DnsServerType se
|
||||
link = env->link;
|
||||
|
||||
ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type,
|
||||
link, family, &env->server_addr, env->server_port,
|
||||
link, /* delegate= */ NULL, family, &env->server_addr, env->server_port,
|
||||
env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS));
|
||||
|
||||
ASSERT_NOT_NULL(env->server);
|
||||
|
431
src/run/run.c
431
src/run/run.c
@ -22,6 +22,7 @@
|
||||
#include "chase.h"
|
||||
#include "env-util.h"
|
||||
#include "escape.h"
|
||||
#include "event-util.h"
|
||||
#include "exec-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fd-util.h"
|
||||
@ -85,6 +86,7 @@ static char *arg_exec_path = NULL;
|
||||
static bool arg_ignore_failure = false;
|
||||
static char *arg_background = NULL;
|
||||
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
||||
static char *arg_shell_prompt_prefix = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
||||
@ -96,6 +98,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep);
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
@ -171,6 +174,10 @@ static int help_sudo_mode(void) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
/* NB: Let's not go overboard with short options: we try to keep a modicum of compatibility with
|
||||
* sudo's short switches, hence please do not introduce new short switches unless they have a roughly
|
||||
* equivalent purpose on sudo. Use long options for everything private to run0. */
|
||||
|
||||
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
||||
"\n%sElevate privileges interactively.%s\n\n"
|
||||
" -h --help Show this help\n"
|
||||
@ -188,6 +195,9 @@ static int help_sudo_mode(void) {
|
||||
" -D --chdir=PATH Set working directory\n"
|
||||
" --setenv=NAME[=VALUE] Set environment variable\n"
|
||||
" --background=COLOR Set ANSI color for background\n"
|
||||
" --pty Request allocation of a pseudo TTY for stdio\n"
|
||||
" --pipe Request direct pipe for stdio\n"
|
||||
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@ -674,7 +684,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
|
||||
* to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
|
||||
* pipeline, but we are neatly interactive with tty-level isolation otherwise. */
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
|
||||
ARG_STDIO_PTY :
|
||||
ARG_STDIO_DIRECT;
|
||||
|
||||
@ -770,27 +780,33 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
ARG_NICE,
|
||||
ARG_SETENV,
|
||||
ARG_BACKGROUND,
|
||||
ARG_PTY,
|
||||
ARG_PIPE,
|
||||
ARG_SHELL_PROMPT_PREFIX,
|
||||
};
|
||||
|
||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||
* though (but limit the extension to long options). */
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
||||
{ "machine", required_argument, NULL, ARG_MACHINE },
|
||||
{ "unit", required_argument, NULL, ARG_UNIT },
|
||||
{ "property", required_argument, NULL, ARG_PROPERTY },
|
||||
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
||||
{ "slice", required_argument, NULL, ARG_SLICE },
|
||||
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
||||
{ "user", required_argument, NULL, 'u' },
|
||||
{ "group", required_argument, NULL, 'g' },
|
||||
{ "nice", required_argument, NULL, ARG_NICE },
|
||||
{ "chdir", required_argument, NULL, 'D' },
|
||||
{ "setenv", required_argument, NULL, ARG_SETENV },
|
||||
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
||||
{ "machine", required_argument, NULL, ARG_MACHINE },
|
||||
{ "unit", required_argument, NULL, ARG_UNIT },
|
||||
{ "property", required_argument, NULL, ARG_PROPERTY },
|
||||
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
||||
{ "slice", required_argument, NULL, ARG_SLICE },
|
||||
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
||||
{ "user", required_argument, NULL, 'u' },
|
||||
{ "group", required_argument, NULL, 'g' },
|
||||
{ "nice", required_argument, NULL, ARG_NICE },
|
||||
{ "chdir", required_argument, NULL, 'D' },
|
||||
{ "setenv", required_argument, NULL, ARG_SETENV },
|
||||
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
||||
{ "pty", no_argument, NULL, ARG_PTY },
|
||||
{ "pipe", no_argument, NULL, ARG_PIPE },
|
||||
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -883,6 +899,26 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_PTY:
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
|
||||
arg_stdio = ARG_STDIO_AUTO;
|
||||
else
|
||||
arg_stdio = ARG_STDIO_PTY;
|
||||
break;
|
||||
|
||||
case ARG_PIPE:
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
|
||||
arg_stdio = ARG_STDIO_AUTO;
|
||||
else
|
||||
arg_stdio = ARG_STDIO_DIRECT;
|
||||
break;
|
||||
|
||||
case ARG_SHELL_PROMPT_PREFIX:
|
||||
r = free_and_strdup_warn(&arg_shell_prompt_prefix, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -913,7 +949,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
arg_wait = true;
|
||||
arg_aggressive_gc = true;
|
||||
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||
|
||||
arg_expand_environment = false;
|
||||
arg_send_sighup = true;
|
||||
|
||||
@ -993,6 +1031,25 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
|
||||
}
|
||||
|
||||
if (!arg_shell_prompt_prefix) {
|
||||
const char *e = secure_getenv("SYSTEMD_RUN_SHELL_PROMPT_PREFIX");
|
||||
if (e) {
|
||||
arg_shell_prompt_prefix = strdup(e);
|
||||
if (!arg_shell_prompt_prefix)
|
||||
return log_oom();
|
||||
} else if (emoji_enabled()) {
|
||||
arg_shell_prompt_prefix = strjoin(special_glyph(SPECIAL_GLYPH_SUPERHERO), " ");
|
||||
if (!arg_shell_prompt_prefix)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isempty(arg_shell_prompt_prefix)) {
|
||||
r = strv_env_assign(&arg_environment, "SHELL_PROMPT_PREFIX", arg_shell_prompt_prefix);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1181,7 +1238,7 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
send_term = isatty_safe(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO);
|
||||
send_term = isatty_safe(STDIN_FILENO) || isatty_safe(STDOUT_FILENO) || isatty_safe(STDERR_FILENO);
|
||||
}
|
||||
|
||||
if (send_term) {
|
||||
@ -1345,78 +1402,75 @@ static int transient_timer_set_properties(sd_bus_message *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
|
||||
unsigned soft_reboots_count = 0;
|
||||
const char *unique, *id;
|
||||
char *p;
|
||||
static int make_unit_name(UnitType t, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(t >= 0);
|
||||
assert(t < _UNIT_TYPE_MAX);
|
||||
assert(ret);
|
||||
|
||||
r = sd_bus_get_unique_name(bus, &unique);
|
||||
/* Preferably use our PID + pidfd ID as identifier, if available. It's a boot time unique identifier
|
||||
* managed by the kernel. Unfortunately only new kernels support this, hence we keep some fallback
|
||||
* logic in place. */
|
||||
|
||||
_cleanup_(pidref_done) PidRef self = PIDREF_NULL;
|
||||
r = pidref_set_self(&self);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get reference to my own process: %m");
|
||||
|
||||
r = pidref_acquire_pidfd_id(&self);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to acquire pidfd ID of myself, defaulting to randomized unit name: %m");
|
||||
|
||||
/* We couldn't get the pidfd id. In that case, just pick a random uuid as name */
|
||||
sd_id128_t rnd;
|
||||
|
||||
/* We couldn't get the unique name, which is a pretty
|
||||
* common case if we are connected to systemd
|
||||
* directly. In that case, just pick a random uuid as
|
||||
* name */
|
||||
|
||||
r = sd_id128_randomize(&rnd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate random run unit name: %m");
|
||||
|
||||
if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
|
||||
return log_oom();
|
||||
r = asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t));
|
||||
} else
|
||||
r = asprintf(ret, "run-p" PID_FMT "-i%" PRIu64 ".%s", self.pid, self.fd_id, unit_type_to_string(t));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We managed to get the unique name, then let's use that to name our transient units. */
|
||||
static int connect_bus(sd_bus **ret) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
||||
id = startswith(unique, ":1."); /* let' strip the usual prefix */
|
||||
if (!id)
|
||||
id = startswith(unique, ":"); /* the spec only requires things to start with a colon, hence
|
||||
* let's add a generic fallback for that. */
|
||||
if (!id)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unique name %s has unexpected format.",
|
||||
unique);
|
||||
assert(ret);
|
||||
|
||||
/* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap
|
||||
* and start over since the D-Bus broker is restarted. If there's a failed unit left behind that
|
||||
* hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
r = bus_get_property_trivial(
|
||||
bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count);
|
||||
if (r < 0)
|
||||
log_debug_errno(r,
|
||||
"Failed to get SoftRebootsCount property, ignoring: %s",
|
||||
bus_error_message(&error, r));
|
||||
}
|
||||
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
||||
* limited direct connection */
|
||||
if (arg_wait ||
|
||||
arg_stdio != ARG_STDIO_NONE ||
|
||||
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
||||
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||
else
|
||||
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||
if (r < 0)
|
||||
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
||||
|
||||
if (soft_reboots_count > 0) {
|
||||
if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0)
|
||||
return log_oom();
|
||||
} else {
|
||||
p = strjoin("run-u", id, ".", unit_type_to_string(t));
|
||||
if (!p)
|
||||
return log_oom();
|
||||
}
|
||||
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
||||
|
||||
*ret = p;
|
||||
*ret = TAKE_PTR(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct RunContext {
|
||||
sd_bus *bus;
|
||||
sd_event *event;
|
||||
PTYForward *forward;
|
||||
sd_bus_slot *match;
|
||||
char *service;
|
||||
char *bus_path;
|
||||
|
||||
/* Bus objects */
|
||||
sd_bus *bus;
|
||||
sd_bus_slot *match_properties_changed;
|
||||
sd_bus_slot *match_disconnected;
|
||||
sd_event_source *retry_timer;
|
||||
|
||||
/* Current state of the unit */
|
||||
char *active_state;
|
||||
@ -1437,16 +1491,72 @@ typedef struct RunContext {
|
||||
uint32_t exit_status;
|
||||
} RunContext;
|
||||
|
||||
static void run_context_free(RunContext *c) {
|
||||
static int run_context_update(RunContext *c);
|
||||
static int run_context_attach_bus(RunContext *c, sd_bus *bus);
|
||||
static void run_context_detach_bus(RunContext *c);
|
||||
static int run_context_reconnect(RunContext *c);
|
||||
|
||||
static void run_context_done(RunContext *c) {
|
||||
assert(c);
|
||||
|
||||
run_context_detach_bus(c);
|
||||
|
||||
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
||||
c->forward = pty_forward_free(c->forward);
|
||||
c->match = sd_bus_slot_unref(c->match);
|
||||
c->bus = sd_bus_unref(c->bus);
|
||||
c->event = sd_event_unref(c->event);
|
||||
|
||||
free(c->active_state);
|
||||
free(c->result);
|
||||
free(c->bus_path);
|
||||
free(c->service);
|
||||
}
|
||||
|
||||
static int on_retry_timer(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
RunContext *c = ASSERT_PTR(userdata);
|
||||
|
||||
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
||||
|
||||
return run_context_reconnect(c);
|
||||
}
|
||||
|
||||
static int run_context_reconnect(RunContext *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
run_context_detach_bus(c);
|
||||
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||
r = connect_bus(&bus);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to reconnect, retrying in 2s: %m");
|
||||
|
||||
r = event_reset_time_relative(
|
||||
c->event,
|
||||
&c->retry_timer,
|
||||
CLOCK_MONOTONIC,
|
||||
2 * USEC_PER_SEC, /* accuracy= */ 0,
|
||||
on_retry_timer, c,
|
||||
SD_EVENT_PRIORITY_NORMAL,
|
||||
"retry-timeout",
|
||||
/* force_reset= */ false);
|
||||
if (r < 0) {
|
||||
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return log_error_errno(r, "Failed to install retry timer: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = run_context_attach_bus(c, bus);
|
||||
if (r < 0) {
|
||||
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return r;
|
||||
}
|
||||
|
||||
log_info("Reconnected to bus.");
|
||||
|
||||
return run_context_update(c);
|
||||
}
|
||||
|
||||
static void run_context_check_done(RunContext *c) {
|
||||
@ -1454,16 +1564,13 @@ static void run_context_check_done(RunContext *c) {
|
||||
|
||||
assert(c);
|
||||
|
||||
if (c->match)
|
||||
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
|
||||
else
|
||||
done = true;
|
||||
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
|
||||
|
||||
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
|
||||
done = pty_forward_drain(c->forward);
|
||||
|
||||
if (done)
|
||||
sd_event_exit(c->event, EXIT_SUCCESS);
|
||||
(void) sd_event_exit(c->event, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
@ -1480,7 +1587,7 @@ static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_er
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_context_update(RunContext *c, const char *path) {
|
||||
static int run_context_update(RunContext *c) {
|
||||
|
||||
static const struct bus_properties_map map[] = {
|
||||
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
||||
@ -1503,16 +1610,35 @@ static int run_context_update(RunContext *c, const char *path) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r;
|
||||
|
||||
r = bus_map_all_properties(c->bus,
|
||||
"org.freedesktop.systemd1",
|
||||
path,
|
||||
map,
|
||||
BUS_MAP_STRDUP,
|
||||
&error,
|
||||
NULL,
|
||||
c);
|
||||
assert(c);
|
||||
assert(c->bus);
|
||||
|
||||
r = bus_map_all_properties(
|
||||
c->bus,
|
||||
"org.freedesktop.systemd1",
|
||||
c->bus_path,
|
||||
map,
|
||||
BUS_MAP_STRDUP,
|
||||
&error,
|
||||
NULL,
|
||||
c);
|
||||
if (r < 0) {
|
||||
sd_event_exit(c->event, EXIT_FAILURE);
|
||||
/* If this is a connection error, then try to reconnect. This might be because the service
|
||||
* manager is being restarted. Handle this gracefully. */
|
||||
if (sd_bus_error_has_names(
|
||||
&error,
|
||||
SD_BUS_ERROR_NO_REPLY,
|
||||
SD_BUS_ERROR_DISCONNECTED,
|
||||
SD_BUS_ERROR_TIMED_OUT,
|
||||
SD_BUS_ERROR_SERVICE_UNKNOWN,
|
||||
SD_BUS_ERROR_NAME_HAS_NO_OWNER)) {
|
||||
|
||||
log_info("Bus call failed due to connection problems. Trying to reconnect...");
|
||||
/* Not propagating error, because we handled it already, by reconnecting. */
|
||||
return run_context_reconnect(c);
|
||||
}
|
||||
|
||||
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
@ -1521,11 +1647,67 @@ static int run_context_update(RunContext *c, const char *path) {
|
||||
}
|
||||
|
||||
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
RunContext *c = ASSERT_PTR(userdata);
|
||||
return run_context_update(ASSERT_PTR(userdata));
|
||||
}
|
||||
|
||||
assert(m);
|
||||
static int on_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
/* If our connection gets terminated, then try to reconnect. This might be because the service
|
||||
* manager is being restarted. Handle this gracefully. */
|
||||
log_info("Got disconnected from bus connection. Trying to reconnect...");
|
||||
return run_context_reconnect(ASSERT_PTR(userdata));
|
||||
}
|
||||
|
||||
return run_context_update(c, sd_bus_message_get_path(m));
|
||||
static int run_context_attach_bus(RunContext *c, sd_bus *bus) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(bus);
|
||||
|
||||
assert(!c->bus);
|
||||
assert(!c->match_properties_changed);
|
||||
assert(!c->match_disconnected);
|
||||
|
||||
c->bus = sd_bus_ref(bus);
|
||||
|
||||
r = sd_bus_match_signal_async(
|
||||
c->bus,
|
||||
&c->match_properties_changed,
|
||||
"org.freedesktop.systemd1",
|
||||
c->bus_path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
on_properties_changed, NULL, c);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request PropertiesChanged signal match: %m");
|
||||
|
||||
r = sd_bus_match_signal_async(
|
||||
bus,
|
||||
&c->match_disconnected,
|
||||
"org.freedesktop.DBus.Local",
|
||||
/* path= */ NULL,
|
||||
"org.freedesktop.DBus.Local",
|
||||
"Disconnected",
|
||||
on_disconnected, NULL, c);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request Disconnected signal match: %m");
|
||||
|
||||
r = sd_bus_attach_event(c->bus, c->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_context_detach_bus(RunContext *c) {
|
||||
assert(c);
|
||||
|
||||
if (c->bus) {
|
||||
(void) sd_bus_detach_event(c->bus);
|
||||
c->bus = sd_bus_unref(c->bus);
|
||||
}
|
||||
|
||||
c->match_properties_changed = sd_bus_slot_unref(c->match_properties_changed);
|
||||
c->match_disconnected = sd_bus_slot_unref(c->match_disconnected);
|
||||
}
|
||||
|
||||
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
||||
@ -1541,7 +1723,7 @@ static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
||||
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
|
||||
* for the service to end. If the user hits ^C we'll exit too. */
|
||||
} else if (rcode < 0) {
|
||||
sd_event_exit(c->event, EXIT_FAILURE);
|
||||
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
||||
}
|
||||
|
||||
@ -1818,7 +2000,7 @@ static int start_transient_service(sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to mangle unit name: %m");
|
||||
} else {
|
||||
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
||||
r = make_unit_name(UNIT_SERVICE, &service);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1860,7 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
|
||||
}
|
||||
|
||||
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
||||
_cleanup_(run_context_free) RunContext c = {
|
||||
_cleanup_(run_context_done) RunContext c = {
|
||||
.cpu_usage_nsec = NSEC_INFINITY,
|
||||
.memory_peak = UINT64_MAX,
|
||||
.memory_swap_peak = UINT64_MAX,
|
||||
@ -1871,14 +2053,19 @@ static int start_transient_service(sd_bus *bus) {
|
||||
.inactive_exit_usec = USEC_INFINITY,
|
||||
.inactive_enter_usec = USEC_INFINITY,
|
||||
};
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
c.bus = sd_bus_ref(bus);
|
||||
|
||||
r = sd_event_default(&c.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get event loop: %m");
|
||||
|
||||
c.service = strdup(service);
|
||||
if (!c.service)
|
||||
return log_oom();
|
||||
|
||||
c.bus_path = unit_dbus_path_from_name(service);
|
||||
if (!c.bus_path)
|
||||
return log_oom();
|
||||
|
||||
if (master >= 0) {
|
||||
(void) sd_event_set_signal_exit(c.event, true);
|
||||
|
||||
@ -1900,26 +2087,11 @@ static int start_transient_service(sd_bus *bus) {
|
||||
set_window_title(c.forward);
|
||||
}
|
||||
|
||||
path = unit_dbus_path_from_name(service);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_match_signal_async(
|
||||
bus,
|
||||
&c.match,
|
||||
"org.freedesktop.systemd1",
|
||||
path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
on_properties_changed, NULL, &c);
|
||||
r = run_context_attach_bus(&c, bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request properties changed signal match: %m");
|
||||
return r;
|
||||
|
||||
r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||
|
||||
r = run_context_update(&c, path);
|
||||
r = run_context_update(&c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -2033,7 +2205,7 @@ static int start_transient_scope(sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to mangle scope name: %m");
|
||||
} else {
|
||||
r = make_unit_name(bus, UNIT_SCOPE, &scope);
|
||||
r = make_unit_name(UNIT_SCOPE, &scope);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -2332,7 +2504,7 @@ static int start_transient_trigger(sd_bus *bus, const char *suffix) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
||||
r = make_unit_name(UNIT_SERVICE, &service);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -2411,16 +2583,30 @@ static int run(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
if (!arg_description) {
|
||||
char *t;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
if (strv_isempty(arg_cmdline))
|
||||
t = strdup(arg_unit);
|
||||
else
|
||||
else if (startswith(arg_cmdline[0], "-")) {
|
||||
/* Drop the login shell marker from the command line when generating the description,
|
||||
* in order to minimize user confusion. */
|
||||
_cleanup_strv_free_ char **l = strv_copy(arg_cmdline);
|
||||
if (!l)
|
||||
return log_oom();
|
||||
|
||||
r = free_and_strdup_warn(l + 0, l[0] + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = quote_command_line(l, SHELL_ESCAPE_EMPTY);
|
||||
} else
|
||||
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(arg_description, t);
|
||||
arg_description = strjoin("[", program_invocation_short_name, "] ", t);
|
||||
if (!arg_description)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
/* For backward compatibility reasons env var expansion is disabled by default for scopes, and
|
||||
@ -2435,18 +2621,9 @@ static int run(int argc, char* argv[]) {
|
||||
" Use --expand-environment=yes/no to explicitly control it as needed.");
|
||||
}
|
||||
|
||||
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
||||
* limited direct connection */
|
||||
if (arg_wait ||
|
||||
arg_stdio != ARG_STDIO_NONE ||
|
||||
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
||||
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||
else
|
||||
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||
r = connect_bus(&bus);
|
||||
if (r < 0)
|
||||
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
||||
|
||||
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
||||
return r;
|
||||
|
||||
if (arg_scope)
|
||||
return start_transient_scope(bus);
|
||||
|
@ -82,7 +82,7 @@ TEST(keymaps) {
|
||||
|
||||
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
|
||||
TEST(dump_special_glyphs) {
|
||||
assert_cc(SPECIAL_GLYPH_GREEN_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
|
||||
assert_cc(SPECIAL_GLYPH_SUPERHERO + 1 == _SPECIAL_GLYPH_MAX);
|
||||
|
||||
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
|
||||
|
||||
@ -133,6 +133,7 @@ TEST(dump_special_glyphs) {
|
||||
dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
|
||||
dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
|
||||
dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
|
||||
dump_glyph(SPECIAL_GLYPH_SUPERHERO);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
@ -453,7 +453,6 @@ static int add_veritytab_devices(void) {
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL, *name = NULL, *data_device = NULL, *hash_device = NULL,
|
||||
*roothash = NULL, *options = NULL;
|
||||
char *data_uuid, *hash_uuid;
|
||||
|
||||
r = read_stripped_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
@ -472,14 +471,6 @@ static int add_veritytab_devices(void) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data_uuid = startswith(data_device, "UUID=");
|
||||
if (!data_uuid)
|
||||
data_uuid = path_startswith(data_device, "/dev/disk/by-uuid/");
|
||||
|
||||
hash_uuid = startswith(hash_device, "UUID=");
|
||||
if (!hash_uuid)
|
||||
hash_uuid = path_startswith(hash_device, "/dev/disk/by-uuid/");
|
||||
|
||||
r = create_veritytab_device(
|
||||
name,
|
||||
data_device,
|
||||
|
@ -238,10 +238,13 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
||||
run0 ls /
|
||||
assert_eq "$(run0 echo foo)" "foo"
|
||||
# Check if we set some expected environment variables
|
||||
for arg in "" "--user=root" "--user=testuser"; do
|
||||
for arg in "" "--user=root" "--user=0" "--user=testuser"; do
|
||||
assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER"
|
||||
assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")"
|
||||
assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")"
|
||||
|
||||
# Validate that we actually went properly through PAM (XDG_SESSION_TYPE is set by pam_systemd)
|
||||
assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $XDG_SESSION_TYPE')" "unspecified"
|
||||
done
|
||||
# Let's chain a couple of run0 calls together, for fun
|
||||
readarray -t cmdline < <(printf "%.0srun0\n" {0..31})
|
||||
@ -258,4 +261,17 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
||||
assert_eq "$(run0 -D / pwd)" "/"
|
||||
assert_eq "$(run0 --user=testuser pwd)" "/home/testuser"
|
||||
assert_eq "$(run0 -D / --user=testuser pwd)" "/"
|
||||
|
||||
# Verify that all combinations of --pty/--pipe come to the sam results
|
||||
assert_eq "$(run0 echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pty echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pipe echo -n foo)" "foo"
|
||||
assert_eq "$(run0 --pipe --pty echo -n foo)" "foo"
|
||||
|
||||
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
|
||||
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
|
||||
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
|
||||
fi
|
||||
|
||||
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
|
||||
assert_rc "37" systemd-run --unit=disconnecttest --wait --pipe --user -M testuser@.host bash -ec 'systemctl --user daemon-reexec; sleep 3; exit 37'
|
||||
|
@ -39,6 +39,15 @@ assert_eq() {(
|
||||
fi
|
||||
)}
|
||||
|
||||
assert_neq() {(
|
||||
set +ex
|
||||
|
||||
if [[ "${1?}" = "${2?}" ]]; then
|
||||
echo "FAIL: not expected: '$2' actual: '$1'" >&2
|
||||
exit 1
|
||||
fi
|
||||
)}
|
||||
|
||||
assert_le() {(
|
||||
set +ex
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user