1
0
mirror of https://github.com/systemd/systemd synced 2025-11-06 18:34:46 +01:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Frantisek Sumsal
7b3046e693 test: sync journal after the test unit finishes
In these two cases we need to sync the journal _after_ the unit finishes
as well, because we try to match messages from systemd itself, not
(only) from the unit, and the messages about units are dispatched
asynchronously.

That is, in the first case (silent-success.service) we want to make sure
that LogLevelMax= filters out messages _about_ units (from systemd) as
well, including messages like "Deactivated..."  and "Finished...", which
are sent out only when/after the unit is stopped.

In the second case we try to match messages with the "systemd" syslog
tag, but these messages come from systemd (obviously) and are sent out
asynchronously, which means they might not reach the journal before we
call `journalctl --sync` from the test unit itself, like happened here:

[ 1754.150391] TEST-04-JOURNAL.sh[13331]: + systemctl start verbose-success.service
[ 1754.172256] bash[13692]: success
[ 1754.221210] TEST-04-JOURNAL.sh[13694]: ++ journalctl -b -q -u verbose-success.service -t systemd
[ 1754.221493] TEST-04-JOURNAL.sh[13331]: + [[ -n '' ]]
[ 1754.175709] systemd[1]: Starting verbose-success.service - Verbose successful service...
[ 1754.221697] TEST-04-JOURNAL.sh[122]: + echo 'Subtest /usr/lib/systemd/tests/testdata/units/TEST-04-JOURNAL.journal.sh failed'
[ 1754.221697] TEST-04-JOURNAL.sh[122]: Subtest /usr/lib/systemd/tests/testdata/units/TEST-04-JOURNAL.journal.sh failed
[ 1754.221697] TEST-04-JOURNAL.sh[122]: + return 1
[ 1754.205408] systemd[1]: verbose-success.service: Deactivated successfully.
[ 1754.205687] systemd[1]: Finished verbose-success.service - Verbose successful service.

By syncing the journal after the unit is stopped we have much bigger
chance that the systemd messages already reached the journal - the race
is technically still there, but the chance we'd hit it should be pretty
negligible.

Resolves: #39555
2025-11-06 16:30:52 +00:00
Zbigniew Jędrzejewski-Szmek
ca5fa2f5ad
resolvectl: add --json support for status commands (#38960)
Add --json support for all status commands in resolvectl by making use
of the new DumpDNSConfiguration varlink method. E.g,

```
$ resolvectl --json=pretty status eth0
[
        {
                "ifname" : "eth0",
                "ifindex" : 9,
                "defaultRoute" : true,
                "currentServer" : {
                        "addressString" : "10.148.181.1",
                        "address" : [
                                10,
                                148,
                                181,
                                1
                        ],
                        "family" : 2,
                        "port" : 53,
                        "ifindex" : 9,
                        "accessible" : true
                },
                "servers" : [
                        {
                                "addressString" : "10.148.181.1",
                                "address" : [
                                        10,
                                        148,
                                        181,
                                        1
                                ],
                                "family" : 2,
                                "port" : 53,
                                "ifindex" : 9,
                                "accessible" : true
                        }
                ],
                "searchDomains" : [
                        {
                                "name" : "local",
                                "routeOnly" : false,
                                "ifindex" : 9
                        }
                ],
                "dnssec" : "allow-downgrade",
                "dnsOverTLS" : "no",
                "llmnr" : "no",
                "mDNS" : "no",
                "scopes" : [
                        {
                                "protocol" : "dns",
                                "ifindex" : 9,
                                "ifname" : "eth0",
                                "dnssec" : "allow-downgrade",
                                "dnsOverTLS" : "no"
                        }
                ]
        }
]
```

Like the regular status output, fields are omitted all together when
empty, unless explicitly requested via one of the sub-commands dns,
domain, nta, etc.

Closes https://github.com/systemd/systemd/issues/33036.
2025-11-06 15:34:10 +01:00
Zbigniew Jędrzejewski-Szmek
9070bffdc1
Fix systemd-ssh-generator printing a bogus hint (#39578) 2025-11-06 15:30:35 +01:00
Nick Rosbrook
313d216662 test: expand testcases to include resolvectl --json usage 2025-11-06 05:17:59 -05:00
Nick Rosbrook
0536b37629 resolvectl: implement --json flag for resolvectl status
Add --json support for all status commands in resolvectl by making use
of the new DumpDNSConfiguration varlink method. E.g,

$ resolvectl --json=pretty status eth0
[
	{
		"ifname" : "eth0",
		"ifindex" : 9,
		"defaultRoute" : true,
		"currentServer" : {
                        "addressString" : "10.148.181.1",
			"address" : [
				10,
				148,
				181,
				1
			],
			"family" : 2,
			"port" : 53,
			"ifindex" : 9,
			"accessible" : true
		},
		"servers" : [
			{
                                "addressString" : "10.148.181.1",
				"address" : [
					10,
					148,
					181,
					1
				],
				"family" : 2,
				"port" : 53,
				"ifindex" : 9,
				"accessible" : true
			}
		],
		"searchDomains" : [
			{
				"name" : "local",
				"routeOnly" : false,
				"ifindex" : 9
			}
		],
		"dnssec" : "allow-downgrade",
		"dnsOverTLS" : "no",
		"llmnr" : "no",
		"mDNS" : "no",
		"scopes" : [
			{
				"protocol" : "dns",
				"ifindex" : 9,
				"ifname" : "eth0",
				"dnssec" : "allow-downgrade",
				"dnsOverTLS" : "no"
			}
		]
	}
]

Like the regular status output, fields are omitted all together when
empty, unless explicitly requested via one of the sub-commands dns,
domain, nta, etc.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
01278ceba0 resolve: add DumpDNSConfiguration to varlink API
Add io.systemd.Resolve.DumpDNSConfiguration. This provides the same
information as io.systemd.Resolve.Monitor.SubscribeDNSConfiguration,
but just returns the configuration once without the subscription logic.

In order to use the same definitions for DNSConfiguration et al. between
both interfaces, move the definitions to io.systemd.Resolve, and include
them in io.systemd.Resolve.Monitor.

This will be used to implement --json for resolvectl status.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
d49a0bd1da wait-online: ignore unused DNSConfiguration fields when dispatching JSON
The io.systemd.Resolve.Monitor.DNSConfiguration type is being expanded,
but we do not need the extra information for determining online status.

Ignore these fields when dispatching JSON to avoid "Unrecognized object field"
messages adding noise to systemd-networkd-wait-online debug output.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
5e777155d5 wait-online: dispatch DNSConfiguration with SD_JSON_ALLOW_EXTENSIONS
Currently if an unknown field is encountered in the JSON, it is a fatal
error. Dispatch with SD_JSON_ALLOW_EXTENSIONS to avoid this.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
0d9e5b39d3 resolve: add formatted address string to DNSServer
Although the JSON output is mostly intended to be machine readable,
humans also consume the output through logs and scripts.

Add an addressString field to DNSServer to improve human-readability.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
f5d5ef9cb4 resolve: add fallback servers list to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
9f9264e3f6 resolve: add resolv.conf mode to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
ed4d43f88f resolve: add all protocol modes to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:59 -05:00
Nick Rosbrook
306375c368 resolve: add DNS scope info to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:58 -05:00
Nick Rosbrook
a80f9291cc resolve: add negative trust anchors to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:58 -05:00
Nick Rosbrook
34be1fadde resolve: add delegate info to DNSConfiguration
This is one of several commits to expand the DNSConfiguration varlink
type to include the necessary information for resolvectl status output.
2025-11-06 05:17:58 -05:00
Nick Rosbrook
994b350860 resolve: add {global,link}_dns_configuration_json_append() helpers
No functional change, just add these helpers to improve readability in
dns_configuration_json_append(). This is preparation for later commits.
2025-11-06 05:17:58 -05:00
Christoph Anton Mitterer
07f4718242 man: clarify what “failed” means
systemd.service(5)’s documentation of `ExecCondition=` uses “failed” with
respect to the unit active state.
In particular the unit won’t be considered failed when `ExecCondition=`’s
command exits with a status of 1 through 254 (inclusive). It will however, when
it exits with 255 or abnormally (e.g. timeout, killed by a signal, etc.).

The table “Defined $SERVICE_RESULT values” in systemd.exec(5) uses “failed”
however rather with respect to the condition.

Tests seem to have shown that, if the exit status of the `ExecCondition=`
command is one of 1 through 254 (inclusive), `$SERVICE_RESULT` will be
`exec-condition`, if it is 255, `$SERVICE_RESULT` will be `exit-code` (but
`$EXIT_CODE` and `$EXIT_STATUS` will be empty or unset), if it’s killed because
of `SIGKILL`, `$SERVICE_RESULT` will `signal` and if it times out,
`$SERVICE_RESULT` will be `timeout`.

This commit clarifies the table at least for the case of an exit status of 1
through 254 (inclusive).
The others (signal, timeout and 255 are probably also still ambiguous (e.g.
`signal` uses “A service process”, which could be considered as the actual
service process only).

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2025-11-06 10:47:06 +01:00
Managor
b1aa33ff91
systemctl.xml: unify ellipsis (#39586)
The reverts in #39423 brought this back. This PR will unify the page.
2025-11-06 10:34:57 +01:00
Zbigniew Jędrzejewski-Szmek
492ae9ec4e ssh-generator: filter out bogus vsock addresses
When VirtIO VSOCK device is not present, IOCTL_VM_SOCKETS_GET_LOCAL_CID
returns VMADDR_CID_LOCAL/1, and we issue a hint to connect to vsock%1.
This does not work. Filter out VMADDR_CID_LOCAL and VMADDR_CID_HOST,
those are not real addresses that can be used from the outside.
2025-11-06 10:32:12 +01:00
Zbigniew Jędrzejewski-Szmek
3bfdc950f7 basic/vsock: report result of IOCTL_VM_SOCKETS_GET_LOCAL_CID 2025-11-05 18:33:44 +01:00
13 changed files with 611 additions and 84 deletions

View File

@ -377,7 +377,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<varlistentry>
<term>
<command>list-dependencies</command>
<optional><replaceable>UNIT</replaceable>...</optional>
<optional><replaceable>UNIT</replaceable></optional>
</term>
<listitem>

View File

@ -4366,7 +4366,7 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
</row>
<row>
<entry><literal>exec-condition</literal></entry>
<entry>Service did not run because <varname>ExecCondition=</varname> failed.</entry>
<entry>Service did not run because <varname>ExecCondition=</varname> failed (that is its command exited with an exit status of 1 through 254 (inclusive)).</entry>
</row>
<row>
<entry><literal>oom-kill</literal></entry>

View File

@ -1928,9 +1928,19 @@ int vsock_get_local_cid(unsigned *ret) {
return log_debug_errno(errno, "Failed to open %s: %m", "/dev/vsock");
unsigned tmp;
if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ret ?: &tmp) < 0)
if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &tmp) < 0)
return log_debug_errno(errno, "Failed to query local AF_VSOCK CID: %m");
log_debug("Local AF_VSOCK CID: %u", tmp);
/* If ret == NULL, we're just want to check if AF_VSOCK is available, so accept
* any address. Otherwise, filter out special addresses that are cannot be used
* to identify _this_ machine from the outside. */
if (ret && IN_SET(tmp, VMADDR_CID_LOCAL, VMADDR_CID_HOST))
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"IOCTL_VM_SOCKETS_GET_LOCAL_CID returned special value (%u), ignoring.", tmp);
if (ret)
*ret = tmp;
return 0;
}

View File

@ -32,12 +32,13 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dns_server_dispatch_table[] = {
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(DNSServer, addr), SD_JSON_MANDATORY },
{ "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSServer, family), SD_JSON_MANDATORY },
{ "port", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint16, offsetof(DNSServer, port), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSServer, ifindex), SD_JSON_RELAX },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSServer, server_name), 0 },
{ "accessible", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSServer, accessible), SD_JSON_MANDATORY },
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(DNSServer, addr), SD_JSON_MANDATORY },
{ "addressString", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSServer, family), SD_JSON_MANDATORY },
{ "port", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint16, offsetof(DNSServer, port), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSServer, ifindex), SD_JSON_RELAX },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSServer, server_name), 0 },
{ "accessible", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSServer, accessible), SD_JSON_MANDATORY },
{},
};
DNSServer **ret = ASSERT_PTR(userdata);
@ -171,12 +172,23 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
static int dispatch_dns_configuration(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dns_configuration_dispatch_table[] = {
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, ifname), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSConfiguration, ifindex), SD_JSON_RELAX },
{ "defaultRoute", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, default_route), 0 },
{ "currentServer", SD_JSON_VARIANT_OBJECT, dispatch_dns_server, offsetof(DNSConfiguration, current_dns_server), 0 },
{ "servers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, dns_servers), 0 },
{ "searchDomains", SD_JSON_VARIANT_ARRAY, dispatch_search_domain_array, offsetof(DNSConfiguration, search_domains), 0 },
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, ifname), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSConfiguration, ifindex), SD_JSON_RELAX },
{ "defaultRoute", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, default_route), 0 },
{ "currentServer", SD_JSON_VARIANT_OBJECT, dispatch_dns_server, offsetof(DNSConfiguration, current_dns_server), 0 },
{ "servers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, dns_servers), 0 },
{ "searchDomains", SD_JSON_VARIANT_ARRAY, dispatch_search_domain_array, offsetof(DNSConfiguration, search_domains), 0 },
/* The remaining fields are currently unused by wait-online. */
{ "delegate", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "fallbackServers", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "negativeTrustAnchors", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "dnssec", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "dnsOverTLS", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "llmnr", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "mDNS", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "resolvConfMode", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{ "scopes", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
{},
};
@ -198,7 +210,7 @@ static int dispatch_dns_configuration(const char *name, sd_json_variant *variant
}
int dns_configuration_from_json(sd_json_variant *variant, DNSConfiguration **ret) {
return dispatch_dns_configuration(NULL, variant, SD_JSON_LOG, ret);
return dispatch_dns_configuration(NULL, variant, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
}
bool dns_is_accessible(DNSConfiguration *c) {

View File

@ -45,6 +45,7 @@
#include "resolvectl.h"
#include "resolved-def.h"
#include "resolved-util.h"
#include "set.h"
#include "socket-netlink.h"
#include "sort-util.h"
#include "stdio-util.h"
@ -1792,6 +1793,161 @@ static char** global_protocol_status(const GlobalInfo *info) {
return TAKE_PTR(s);
}
static const char* status_mode_to_json_field(StatusMode mode) {
switch (mode) {
case STATUS_ALL:
return NULL;
case STATUS_DNS:
return "servers";
case STATUS_DOMAIN:
return "searchDomains";
case STATUS_DEFAULT_ROUTE:
return "defaultRoute";
case STATUS_LLMNR:
return "llmnr";
case STATUS_MDNS:
return "mDNS";
case STATUS_PRIVATE:
return "dnsOverTLS";
case STATUS_DNSSEC:
return "dnssec";
case STATUS_NTA:
return "negativeTrustAnchors";
default:
assert_not_reached();
}
}
static int status_json_filter_fields(sd_json_variant **configuration, StatusMode mode) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
sd_json_variant *w;
const char *field;
int r;
assert(configuration);
field = status_mode_to_json_field(mode);
if (!field)
/* Nothing to filter for this mode. */
return 0;
JSON_VARIANT_ARRAY_FOREACH(w, *configuration) {
/* Always include identifier fields like ifname or delegate, and include the requested
* field even if it is empty in the configuration. */
r = sd_json_variant_append_arraybo(
&v,
JSON_BUILD_PAIR_VARIANT_NON_NULL("ifname", sd_json_variant_by_key(w, "ifname")),
JSON_BUILD_PAIR_VARIANT_NON_NULL("ifindex", sd_json_variant_by_key(w, "ifindex")),
JSON_BUILD_PAIR_VARIANT_NON_NULL("delegate", sd_json_variant_by_key(w, "delegate")),
SD_JSON_BUILD_PAIR_VARIANT(field, sd_json_variant_by_key(w, field)));
if (r < 0)
return r;
}
JSON_VARIANT_REPLACE(*configuration, TAKE_PTR(v));
return 0;
}
static int status_json_filter_links(sd_json_variant **configuration, char **links) {
_cleanup_set_free_ Set *links_by_index = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
sd_json_variant *w;
int r;
assert(configuration);
if (links)
STRV_FOREACH(ifname, links) {
int ifindex = rtnl_resolve_interface_or_warn(/* rtnl= */ NULL, *ifname);
if (ifindex < 0)
return ifindex;
r = set_ensure_put(&links_by_index, NULL, INT_TO_PTR(ifindex));
if (r < 0)
return r;
}
JSON_VARIANT_ARRAY_FOREACH(w, *configuration) {
int ifindex = sd_json_variant_unsigned(sd_json_variant_by_key(w, "ifindex"));
if (links_by_index) {
if (ifindex <= 0)
/* Possibly invalid, but most likely unset because this is global
* or delegate configuration. */
continue;
if (!set_contains(links_by_index, INT_TO_PTR(ifindex)))
continue;
} else if (ifindex == LOOPBACK_IFINDEX)
/* By default, exclude the loopback interface. */
continue;
r = sd_json_variant_append_array(&v, w);
if (r < 0)
return r;
}
JSON_VARIANT_REPLACE(*configuration, TAKE_PTR(v));
return 0;
}
static int varlink_dump_dns_configuration(sd_json_variant **ret) {
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *reply = NULL;
sd_json_variant *v;
int r;
assert(ret);
r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve");
if (r < 0)
return log_error_errno(r, "Failed to connect to service /run/systemd/resolve/io.systemd.Resolve: %m");
r = varlink_call_and_log(vl, "io.systemd.Resolve.DumpDNSConfiguration", /* parameters= */ NULL, &reply);
if (r < 0)
return r;
v = sd_json_variant_by_key(reply, "configuration");
if (!sd_json_variant_is_array(v))
return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "DumpDNSConfiguration() response missing 'configuration' key.");
TAKE_PTR(reply);
*ret = sd_json_variant_ref(v);
return 0;
}
static int status_json(StatusMode mode, char **links) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
int r;
r = varlink_dump_dns_configuration(&configuration);
if (r < 0)
return r;
r = status_json_filter_links(&configuration, links);
if (r < 0)
return log_error_errno(r, "Failed to filter configuration JSON links: %m");
r = status_json_filter_fields(&configuration, mode);
if (r < 0)
return log_error_errno(r, "Failed to filter configuration JSON fields: %m");
return sd_json_variant_dump(configuration, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL);
}
static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
static const struct bus_properties_map property_map[] = {
{ "ScopesMask", "t", NULL, offsetof(LinkInfo, scopes_mask) },
@ -1828,6 +1984,9 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
name = ifname;
}
if (sd_json_format_enabled(arg_json_format_flags))
return status_json(mode, STRV_MAKE(name));
xsprintf(ifi, "%i", ifindex);
r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
if (r < 0)
@ -2423,6 +2582,9 @@ static int status_all(sd_bus *bus, StatusMode mode) {
assert(bus);
if (sd_json_format_enabled(arg_json_format_flags))
return status_json(mode, /* links= */ NULL);
r = status_global(bus, mode, &empty_line);
if (r < 0)
return r;
@ -2444,6 +2606,9 @@ static int verb_status(int argc, char **argv, void *userdata) {
bool empty_line = false;
int r, ret = 0;
if (sd_json_format_enabled(arg_json_format_flags))
return status_json(STATUS_ALL, argc > 1 ? strv_skip(argv, 1) : NULL);
r = acquire_bus(&bus);
if (r < 0)
return r;

View File

@ -1373,6 +1373,7 @@ int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **r
return sd_json_buildo(
ret,
JSON_BUILD_PAIR_STRING_NON_EMPTY("addressString", dns_server_string(server)),
JSON_BUILD_PAIR_IN_ADDR("address", &server->address, server->family),
SD_JSON_BUILD_PAIR_INTEGER("family", server->family),
SD_JSON_BUILD_PAIR_UNSIGNED("port", dns_server_port(server)),

View File

@ -2043,15 +2043,27 @@ void dns_manager_reset_statistics(Manager *m) {
static int dns_configuration_json_append(
const char *ifname,
int ifindex,
const char *delegate,
int default_route,
DnsServer *current_dns_server,
DnsServer *dns_servers,
DnsServer *fallback_dns_servers,
DnsSearchDomain *search_domains,
Set *negative_trust_anchors,
Set *dns_scopes,
DnssecMode dnssec_mode,
DnsOverTlsMode dns_over_tls_mode,
ResolveSupport llmnr_support,
ResolveSupport mdns_support,
ResolvConfMode resolv_conf_mode,
sd_json_variant **configuration) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *dns_servers_json = NULL,
*fallback_dns_servers_json = NULL,
*search_domains_json = NULL,
*current_dns_server_json = NULL;
*current_dns_server_json = NULL,
*scopes_json = NULL;
DnsScope *scope;
int r;
assert(configuration);
@ -2074,6 +2086,29 @@ static int dns_configuration_json_append(
return r;
}
if (fallback_dns_servers) {
r = sd_json_variant_new_array(&fallback_dns_servers_json, NULL, 0);
if (r < 0)
return r;
}
SET_FOREACH(scope, dns_scopes) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = dns_scope_dump_cache_to_json(scope, &v);
if (r < 0)
return r;
/* The cache is not relevant to the configuration of the scope. */
r = sd_json_variant_filter(&v, STRV_MAKE("cache"));
if (r < 0)
return r;
r = sd_json_variant_append_array(&scopes_json, v);
if (r < 0)
return r;
}
LIST_FOREACH(servers, s, dns_servers) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
@ -2102,46 +2137,183 @@ static int dns_configuration_json_append(
return r;
}
LIST_FOREACH(servers, s, fallback_dns_servers) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
assert(fallback_dns_servers_json);
r = dns_server_dump_configuration_to_json(s, &v);
if (r < 0)
return r;
r = sd_json_variant_append_array(&fallback_dns_servers_json, v);
if (r < 0)
return r;
}
return sd_json_variant_append_arraybo(
configuration,
JSON_BUILD_PAIR_STRING_NON_EMPTY("ifname", ifname),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "defaultRoute", SD_JSON_BUILD_BOOLEAN(default_route > 0)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("delegate", delegate),
JSON_BUILD_PAIR_CONDITION_BOOLEAN(ifindex > 0 || !!delegate,
"defaultRoute",
default_route > 0),
JSON_BUILD_PAIR_VARIANT_NON_NULL("currentServer", current_dns_server_json),
JSON_BUILD_PAIR_VARIANT_NON_NULL("servers", dns_servers_json),
JSON_BUILD_PAIR_VARIANT_NON_NULL("searchDomains", search_domains_json));
JSON_BUILD_PAIR_VARIANT_NON_NULL("fallbackServers", fallback_dns_servers_json),
JSON_BUILD_PAIR_VARIANT_NON_NULL("searchDomains", search_domains_json),
SD_JSON_BUILD_PAIR_CONDITION(!set_isempty(negative_trust_anchors),
"negativeTrustAnchors",
JSON_BUILD_STRING_SET(negative_trust_anchors)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("dnssec", dnssec_mode_to_string(dnssec_mode)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("dnsOverTLS", dns_over_tls_mode_to_string(dns_over_tls_mode)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("llmnr", resolve_support_to_string(llmnr_support)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("mDNS", resolve_support_to_string(mdns_support)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("resolvConfMode", resolv_conf_mode_to_string(resolv_conf_mode)),
JSON_BUILD_PAIR_VARIANT_NON_NULL("scopes", scopes_json));
}
static int global_dns_configuration_json_append(Manager *m, sd_json_variant **configuration) {
_cleanup_set_free_ Set *scopes = NULL;
int r;
assert(m);
assert(configuration);
r = set_ensure_put(&scopes, NULL, m->unicast_scope);
if (r < 0)
return r;
return dns_configuration_json_append(
/* ifname = */ NULL,
/* ifindex = */ 0,
/* delegate = */ NULL,
/* default_route = */ 0,
manager_get_dns_server(m),
m->dns_servers,
m->fallback_dns_servers,
m->search_domains,
m->trust_anchor.negative_by_name,
scopes,
manager_get_dnssec_mode(m),
manager_get_dns_over_tls_mode(m),
m->llmnr_support,
m->mdns_support,
resolv_conf_mode(),
configuration);
}
static int link_dns_configuration_json_append(Link *l, sd_json_variant **configuration) {
_cleanup_set_free_ Set *scopes = NULL;
int r;
assert(l);
assert(configuration);
if (l->unicast_scope) {
r = set_ensure_put(&scopes, NULL, l->unicast_scope);
if (r < 0)
return r;
}
if (l->llmnr_ipv4_scope) {
r = set_ensure_put(&scopes, NULL, l->llmnr_ipv4_scope);
if (r < 0)
return r;
}
if (l->llmnr_ipv6_scope) {
r = set_ensure_put(&scopes, NULL, l->llmnr_ipv6_scope);
if (r < 0)
return r;
}
if (l->mdns_ipv4_scope) {
r = set_ensure_put(&scopes, NULL, l->mdns_ipv4_scope);
if (r < 0)
return r;
}
if (l->mdns_ipv6_scope) {
r = set_ensure_put(&scopes, NULL, l->mdns_ipv6_scope);
if (r < 0)
return r;
}
return dns_configuration_json_append(
l->ifname,
l->ifindex,
/* delegate = */ NULL,
link_get_default_route(l),
link_get_dns_server(l),
l->dns_servers,
/* fallback_dns_servers = */ NULL,
l->search_domains,
l->dnssec_negative_trust_anchors,
scopes,
link_get_dnssec_mode(l),
link_get_dns_over_tls_mode(l),
link_get_llmnr_support(l),
link_get_mdns_support(l),
/* resolv_conf_mode = */ _RESOLV_CONF_MODE_INVALID,
configuration);
}
static int delegate_dns_configuration_json_append(DnsDelegate *d, sd_json_variant **configuration) {
_cleanup_set_free_ Set *scopes = NULL;
int r;
assert(d);
assert(configuration);
r = set_ensure_put(&scopes, NULL, d->scope);
if (r < 0)
return r;
return dns_configuration_json_append(
/* ifname = */ NULL,
/* ifindex = */ 0,
d->id,
d->default_route,
dns_delegate_get_dns_server(d),
d->dns_servers,
/* fallback_dns_servers = */ NULL,
d->search_domains,
/* negative_trust_anchors = */ NULL,
scopes,
/* dnssec_mode = */ _DNSSEC_MODE_INVALID,
/* dns_over_tls_mode = */ _DNS_OVER_TLS_MODE_INVALID,
/* llmnr_support = */ _RESOLVE_SUPPORT_INVALID,
/* mdns_support = */ _RESOLVE_SUPPORT_INVALID,
/* resolv_conf_mode = */ _RESOLV_CONF_MODE_INVALID,
configuration);
}
int manager_dump_dns_configuration_json(Manager *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
Link *l;
DnsDelegate *d;
int r;
assert(m);
assert(ret);
/* Global DNS configuration */
r = dns_configuration_json_append(
/* ifname = */ NULL,
/* ifindex = */ 0,
/* default_route = */ 0,
manager_get_dns_server(m),
m->dns_servers,
m->search_domains,
&configuration);
r = global_dns_configuration_json_append(m, &configuration);
if (r < 0)
return r;
/* Append configuration for each link */
HASHMAP_FOREACH(l, m->links) {
r = dns_configuration_json_append(
l->ifname,
l->ifindex,
link_get_default_route(l),
link_get_dns_server(l),
l->dns_servers,
l->search_domains,
&configuration);
r = link_dns_configuration_json_append(l, &configuration);
if (r < 0)
return r;
}
/* Append configuration for each delegate */
HASHMAP_FOREACH(d, m->delegates) {
r = delegate_dns_configuration_json_append(d, &configuration);
if (r < 0)
return r;
}

View File

@ -1409,6 +1409,29 @@ fail:
return log_debug_errno(r, "Failed to subscribe client to DNS configuration monitor: %m");
}
static int vl_method_dump_dns_configuration(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
Manager *m;
Link *l;
int r;
assert(link);
m = ASSERT_PTR(sd_varlink_server_get_userdata(sd_varlink_get_server(link)));
/* Make sure the accessible flag is not stale. */
dns_server_reset_accessible_all(m->dns_servers);
HASHMAP_FOREACH(l, m->links)
dns_server_reset_accessible_all(l->dns_servers);
r = manager_dump_dns_configuration_json(m, &configuration);
if (r < 0)
return r;
return sd_varlink_reply(link, configuration);
}
static int varlink_monitor_server_init(Manager *m) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *server = NULL;
int r;
@ -1481,14 +1504,15 @@ static int varlink_main_server_init(Manager *m) {
r = sd_varlink_server_bind_method_many(
s,
"io.systemd.Resolve.ResolveHostname", vl_method_resolve_hostname,
"io.systemd.Resolve.ResolveAddress", vl_method_resolve_address,
"io.systemd.Resolve.ResolveService", vl_method_resolve_service,
"io.systemd.Resolve.ResolveRecord", vl_method_resolve_record,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
"io.systemd.service.GetEnvironment", varlink_method_get_environment,
"io.systemd.Resolve.BrowseServices", vl_method_browse_services);
"io.systemd.Resolve.ResolveHostname", vl_method_resolve_hostname,
"io.systemd.Resolve.ResolveAddress", vl_method_resolve_address,
"io.systemd.Resolve.ResolveService", vl_method_resolve_service,
"io.systemd.Resolve.ResolveRecord", vl_method_resolve_record,
"io.systemd.service.Ping", varlink_method_ping,
"io.systemd.service.SetLogLevel", varlink_method_set_log_level,
"io.systemd.service.GetEnvironment", varlink_method_get_environment,
"io.systemd.Resolve.BrowseServices", vl_method_browse_services,
"io.systemd.Resolve.DumpDNSConfiguration", vl_method_dump_dns_configuration);
if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m");

View File

@ -3,8 +3,16 @@
#include "bus-polkit.h"
#include "varlink-io.systemd.Resolve.Monitor.h"
/* We want to reuse the ResourceKey and ResourceRecord structures from the io.systemd.Resolve interface,
* hence import them here. */
/* We want to reuse several structures from the io.systemd.Resolve interface, namely:
*
* - ResourceKey
* - ResourceRecord
* - DNSServer
* - DNSScope
* - SearchDomain
* - DNSConfiguration
*
* Hence, import them here . */
#include "varlink-io.systemd.Resolve.h"
static SD_VARLINK_DEFINE_STRUCT_TYPE(
@ -114,45 +122,6 @@ static SD_VARLINK_DEFINE_METHOD(
ResetStatistics,
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSServer,
SD_VARLINK_FIELD_COMMENT("IPv4 or IPv6 address of the server."),
SD_VARLINK_DEFINE_FIELD(address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Address family of the server, one of AF_INET or AF_INET6."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Port number of the server."),
SD_VARLINK_DEFINE_FIELD(port, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this server is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Server Name Indication (SNI) of the server."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates if the DNS server is accessible or not."),
SD_VARLINK_DEFINE_FIELD(accessible, SD_VARLINK_BOOL, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
SearchDomain,
SD_VARLINK_FIELD_COMMENT("Domain name."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this is a routing-only domain."),
SD_VARLINK_DEFINE_FIELD(routeOnly, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this search domain is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSConfiguration,
SD_VARLINK_FIELD_COMMENT("Interface name, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this link's DNS servers will be used for resolving domain names that do not match any link's configured domains."),
SD_VARLINK_DEFINE_FIELD(defaultRoute, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS server currently selected to use for lookups."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(currentServer, DNSServer, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured DNS servers."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(servers, DNSServer, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured search domains."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(searchDomains, SearchDomain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD_FULL(
SubscribeDNSConfiguration,
SD_VARLINK_REQUIRES_MORE,
@ -184,5 +153,7 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_SearchDomain,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a global or per-link DNS configuration, including configured DNS servers, search domains, and more."),
&vl_type_DNSConfiguration,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a DNS scope specification."),
&vl_type_DNSScope,
SD_VARLINK_SYMBOL_COMMENT("Sends the complete global and per-link DNS configurations when any changes are made to them. The current configurations are given immediately when this method is invoked."),
&vl_method_SubscribeDNSConfiguration);

View File

@ -170,6 +170,80 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD_BY_TYPE(rr, ResourceRecord, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(raw, SD_VARLINK_STRING, 0));
SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSServer,
SD_VARLINK_FIELD_COMMENT("IPv4 or IPv6 address of the server."),
SD_VARLINK_DEFINE_FIELD(address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("IPv4 or IPv6 address of the server, formatted as a human-readable string."),
SD_VARLINK_DEFINE_FIELD(addressString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address family of the server, one of AF_INET or AF_INET6."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Port number of the server."),
SD_VARLINK_DEFINE_FIELD(port, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this server is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Server Name Indication (SNI) of the server."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates if the DNS server is accessible or not."),
SD_VARLINK_DEFINE_FIELD(accessible, SD_VARLINK_BOOL, 0));
SD_VARLINK_DEFINE_STRUCT_TYPE(
SearchDomain,
SD_VARLINK_FIELD_COMMENT("Domain name."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this is a routing-only domain."),
SD_VARLINK_DEFINE_FIELD(routeOnly, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this search domain is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSScope,
SD_VARLINK_FIELD_COMMENT("Protocol associated with this scope."),
SD_VARLINK_DEFINE_FIELD(protocol, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address family associated with this scope."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index associated with this scope."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface name associated with this scope."),
SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSSEC mode associated with this scope."),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode associated with this scope."),
SD_VARLINK_DEFINE_FIELD(dnsOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSConfiguration,
SD_VARLINK_FIELD_COMMENT("Interface name, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Delegate name, if any, associated with this configuration. Empty for global or link configurations."),
SD_VARLINK_DEFINE_FIELD(delegate, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this link's DNS servers will be used for resolving domain names that do not match any link's configured domains."),
SD_VARLINK_DEFINE_FIELD(defaultRoute, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS server currently selected to use for lookups."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(currentServer, DNSServer, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured DNS servers."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(servers, DNSServer, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured fallback DNS servers, set for global configuration only."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(fallbackServers, DNSServer, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured search domains."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(searchDomains, SearchDomain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured DNSSEC negative trust anchors."),
SD_VARLINK_DEFINE_FIELD(negativeTrustAnchors, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSSEC mode."),
SD_VARLINK_DEFINE_FIELD(dnssec, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSOverTLS mode."),
SD_VARLINK_DEFINE_FIELD(dnsOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLMNR support."),
SD_VARLINK_DEFINE_FIELD(llmnr, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("mDNS support."),
SD_VARLINK_DEFINE_FIELD(mDNS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("resolv.conf mode, set for global configuration only."),
SD_VARLINK_DEFINE_FIELD(resolvConfMode, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of current DNS scopes."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(scopes, DNSScope, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
ResolveRecord,
SD_VARLINK_DEFINE_INPUT(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
@ -194,6 +268,11 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
SD_VARLINK_FIELD_COMMENT("An array of service data containing information about discovered services."),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(browserServiceData, ServiceData, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_METHOD(
DumpDNSConfiguration,
SD_VARLINK_FIELD_COMMENT("The current global and per-interface DNS configurations"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(configuration, DNSConfiguration, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_ERROR(NoNameServers);
static SD_VARLINK_DEFINE_ERROR(NoSuchResourceRecord);
static SD_VARLINK_DEFINE_ERROR(QueryTimedOut);
@ -236,6 +315,8 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_ResolveRecord,
SD_VARLINK_SYMBOL_COMMENT("Starts browsing for DNS-SD services of specified type."),
&vl_method_BrowseServices,
SD_VARLINK_SYMBOL_COMMENT("Current global and per-link DNS configurations."),
&vl_method_DumpDNSConfiguration,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."),
&vl_type_ResolvedAddress,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."),
@ -254,6 +335,14 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_BrowseServiceUpdateFlag,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates the service data obtained from browsing."),
&vl_type_ServiceData,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a DNS server address specification."),
&vl_type_DNSServer,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a search domain specification."),
&vl_type_SearchDomain,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a global or per-link DNS configuration, including configured DNS servers, search domains, and more."),
&vl_type_DNSConfiguration,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a DNS scope specification."),
&vl_type_DNSScope,
&vl_error_NoNameServers,
&vl_error_NoSuchResourceRecord,
&vl_error_QueryTimedOut,

View File

@ -5,5 +5,9 @@
extern const sd_varlink_symbol vl_type_ResourceKey;
extern const sd_varlink_symbol vl_type_ResourceRecord;
extern const sd_varlink_symbol vl_type_DNSServer;
extern const sd_varlink_symbol vl_type_DNSScope;
extern const sd_varlink_symbol vl_type_SearchDomain;
extern const sd_varlink_symbol vl_type_DNSConfiguration;
extern const sd_varlink_interface vl_interface_io_systemd_Resolve;

View File

@ -104,10 +104,12 @@ diff /tmp/expected /tmp/output
# test that LogLevelMax can also suppress logging about services, not only by services
systemctl start silent-success
journalctl --sync
[[ -z "$(journalctl -b -q -u silent-success.service)" ]]
# Test syslog identifiers exclusion
systemctl start verbose-success.service
journalctl --sync
[[ -n "$(journalctl -b -q -u verbose-success.service -t systemd)" ]]
[[ -n "$(journalctl -b -q -u verbose-success.service -t bash)" ]]
[[ -n "$(journalctl -b -q -u verbose-success.service -T systemd)" ]]

View File

@ -852,6 +852,18 @@ testcase_09_resolvectl_showcache() {
}
testcase_10_resolvectl_json() {
local status_json
# Cleanup
# shellcheck disable=SC2317
cleanup() {
rm -f /run/systemd/resolved.conf.d/90-fallback.conf
systemctl reload systemd-resolved.service
resolvectl revert dns0
}
trap cleanup RETURN ERR
# Issue: https://github.com/systemd/systemd/issues/29580 (part #1)
dig @127.0.0.54 signed.test
@ -871,6 +883,68 @@ testcase_10_resolvectl_json() {
# so we need to select it only if it's present, otherwise the type == "array" check would fail
echo "$line" | jq -e '[. | .question, (select(has("answer")) | .answer) | type == "array"] | all'
done
# Test some global-only settings.
mkdir -p /run/systemd/resolved.conf.d
{
echo "[Resolve]"
echo "FallbackDNS=10.0.0.1 10.0.0.2"
} >/run/systemd/resolved.conf.d/90-fallback.conf
systemctl reload systemd-resolved
status_json="$(mktemp)"
resolvectl --json=short >"$status_json"
# Delegates field should be empty when no delegates are configured.
(! jq -rce '.[] | select(.delegate != null)' "$status_json")
# Test that some links are present.
jq -rce '.[] | select(.ifname == "dns0")' "$status_json"
# Test some global-specific configuration.
assert_eq \
"$(jq -rc '.[] | select(.ifindex == null and .delegate == null) | [ .fallbackServers[] | .addressString ]' "$status_json")" \
'["10.0.0.1","10.0.0.2"]'
assert_eq \
"$(jq -rc '.[] | select(.ifindex == null and .delegate == null) | .resolvConfMode' "$status_json")" \
'stub'
# Test link status.
resolvectl dns dns0 '1.2.3.4'
resolvectl domain dns0 'foo'
resolvectl default-route dns0 'false'
resolvectl llmnr dns0 'no'
resolvectl mdns dns0 'no'
resolvectl dnsovertls dns0 'opportunistic'
resolvectl dnssec dns0 'yes'
resolvectl nta dns0 'bar'
resolvectl --json=short status dns0 >"$status_json"
assert_eq "$(resolvectl --json=short dns dns0 | jq -rc '.[0].servers | .[0].addressString')" '1.2.3.4'
assert_eq "$(jq -rc '.[0].servers | .[0].addressString' "$status_json")" '1.2.3.4'
assert_eq "$(resolvectl --json=short domain dns0 | jq -rc '.[0].searchDomains| .[0].name')" 'foo'
assert_eq "$(jq -rc '.[0].searchDomains | .[0].name' "$status_json")" 'foo'
assert_eq "$(resolvectl --json=short default-route dns0 | jq -rc '.[0].defaultRoute')" 'false'
assert_eq "$(jq -rc '.[0].defaultRoute' "$status_json")" 'false'
assert_eq "$(resolvectl --json=short llmnr dns0 | jq -rc '.[0].llmnr')" 'no'
assert_eq "$(jq -rc '.[0].llmnr' "$status_json")" 'no'
assert_eq "$(resolvectl --json=short mdns dns0 | jq -rc '.[0].mDNS')" 'no'
assert_eq "$(jq -rc '.[0].mDNS' "$status_json")" 'no'
assert_eq "$(resolvectl --json=short dnsovertls dns0 | jq -rc '.[0].dnsOverTLS')" 'opportunistic'
assert_eq "$(jq -rc '.[0].dnsOverTLS' "$status_json")" 'opportunistic'
assert_eq "$(resolvectl --json=short dnssec dns0 | jq -rc '.[0].dnssec')" 'yes'
assert_eq "$(jq -rc '.[0].dnssec' "$status_json")" 'yes'
assert_eq "$(resolvectl --json=short nta dns0 | jq -rc '.[0].negativeTrustAnchors | .[0]')" 'bar'
assert_eq "$(jq -rc '.[0].negativeTrustAnchors | .[0]' "$status_json")" 'bar'
}
# Test serve stale feature and NFTSet= if nftables is installed
@ -1414,6 +1488,9 @@ EOF
systemctl reload systemd-resolved
resolvectl status
assert_eq "$(resolvectl --json=short | jq -rc '.[] | select(.delegate == "testcase") | .servers | .[0].addressString')" '192.168.77.78'
assert_eq "$(resolvectl --json=short | jq -rc '.[] | select(.delegate == "testcase") | .searchDomains | .[0].name')" 'exercise.test'
# Now that we installed the delegation the resolution should fail, because nothing is listening on that IP address
(! resolvectl query delegation.exercise.test)