resolvectl: fix query option handling and resolvconf input errors (#43370)

This commit is contained in:
Yu Watanabe
2026-08-14 00:35:58 +09:00
committed by GitHub
5 changed files with 47 additions and 13 deletions
+3
View File
@@ -454,6 +454,9 @@ CHANGES WITH 261:
Changes in systemd-resolved:
* The resolvconf compatibility mode now rejects malformed stdin input
and leaves the existing per-link DNS configuration unchanged.
* systemd-resolved will now read additional DNS resource record
definitions to resolve locally from JSON drop-in files in
{/etc,/run,/usr/local/lib,/usr/lib}/systemd/resolve/static.d/. This
+6 -1
View File
@@ -482,6 +482,10 @@
types: SSHFP, TLSA, OPENPGPKEY where this dumps the key material only; and A, AAAA where
this dumps the address data.</para>
<para>This option may only be used with <option>--type=</option> or an RFC 4501
<literal>dns:</literal> URI, which both perform DNS resource record lookups. It may not be combined
with regular hostname or address lookups.</para>
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
</varlistentry>
@@ -560,7 +564,8 @@
DNS configuration data from its standard input. Relevant fields are <literal>nameserver</literal> and
<literal>domain</literal>/<literal>search</literal>. This command is mostly identical to invoking
<command>resolvectl</command> with a combination of <option>dns</option> and <option>domain</option>
commands.</para>
commands. If a relevant input line has invalid syntax, the command fails and leaves the existing
per-interface configuration unchanged.</para>
<xi:include href="version-info.xml" xpointer="v239"/></listitem>
</varlistentry>
+6 -2
View File
@@ -116,7 +116,9 @@ static int parse_stdin(LookupType lookup_type) {
a = first_word(line, "nameserver");
if (a) {
(void) parse_nameserver(a);
r = parse_nameserver(a);
if (r < 0)
return log_error_errno(r, "Failed to parse resolv.conf nameserver line: %m");
continue;
}
@@ -124,7 +126,9 @@ static int parse_stdin(LookupType lookup_type) {
if (!a)
a = first_word(line, "search");
if (a) {
(void) parse_search_domain(a);
r = parse_search_domain(a);
if (r < 0)
return log_error_errno(r, "Failed to parse resolv.conf domain/search line: %m");
continue;
}
+19 -7
View File
@@ -71,6 +71,7 @@ static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
bool arg_ifindex_permissive = false; /* If true, don't generate an error if the specified interface index doesn't exist */
static const char *arg_service_family = NULL;
static bool arg_service_txt_set = false;
static bool arg_ask_password = true;
typedef enum RawType {
@@ -893,6 +894,10 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
int family, ifindex;
union in_addr_union a;
if (arg_raw != RAW_NONE)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--raw may only be combined with --type= or dns: URIs.");
r = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
if (r >= 0)
RET_GATHER(ret, resolve_address(family, &a, ifindex));
@@ -904,7 +909,7 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
return ret;
}
static int resolve_service(const char *name, const char *type, const char *domain) {
static int resolve_service(const char *name, const char *type, const char *domain, uint64_t flags) {
int r;
assert(domain);
@@ -938,7 +943,7 @@ static int resolve_service(const char *name, const char *type, const char *domai
JSON_BUILD_PAIR_STRING_NON_EMPTY("type", type),
JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_ifindex > 0, "ifindex", arg_ifindex),
JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_family != AF_UNSPEC, "family", arg_family),
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags));
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", flags));
if (r < 0)
return log_error_errno(r, "Failed to issue varlink call: %m");
@@ -1019,15 +1024,20 @@ static int resolve_service(const char *name, const char *type, const char *domai
VERB(verb_service, "service", "[[NAME] TYPE] DOMAIN", 2, 4, 0,
"Resolve service (SRV)");
static int verb_service(int argc, char *argv[], uintptr_t _data, void *userdata) {
uint64_t flags = arg_flags;
if (sd_json_format_enabled(arg_json_format_flags))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
if (argc < 4 && !arg_service_txt_set)
flags |= SD_RESOLVED_NO_TXT;
if (argc == 2)
return resolve_service(NULL, NULL, argv[1]);
else if (argc == 3)
return resolve_service(NULL, argv[1], argv[2]);
else
return resolve_service(argv[1], argv[2], argv[3]);
return resolve_service(NULL, NULL, argv[1], flags);
if (argc == 3)
return resolve_service(NULL, argv[1], argv[2], flags);
return resolve_service(argv[1], argv[2], argv[3], flags);
}
#if HAVE_OPENSSL
@@ -3363,6 +3373,7 @@ static int compat_parse_argv(int argc, char *argv[], char ***remaining_args) {
if (r < 0)
return r;
SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
arg_service_txt_set = true;
break;
OPTION_LONG("openpgp", NULL, "Query OpenPGP public key"):
@@ -3597,6 +3608,7 @@ static int native_parse_argv(int argc, char *argv[], char ***remaining_args) {
if (r < 0)
return r;
SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
arg_service_txt_set = true;
break;
OPTION_LONG("cname", "BOOL", "Follow CNAME redirects (default: yes)"):
+13 -3
View File
@@ -273,6 +273,9 @@ manual_testcase_01_resolvectl() {
assert_in 'test-domain1.example.com' "$(resolvectl domain hoge)"
assert_in 'test-domain2.example.com' "$(resolvectl domain hoge)"
assert_in 'test-search-domain.example.com' "$(resolvectl domain hoge)"
resolvectl domain hoge keep.example
(! echo -e "nameserver 10.0.2.1\nsearch \"unterminated" | SYSTEMD_INVOKED_AS=resolvconf resolvectl -a hoge)
assert_in 'keep.example' "$(resolvectl domain hoge)"
# Tests for 'resolvconf -x'
echo nameserver 10.0.2.1 | SYSTEMD_INVOKED_AS=resolvconf resolvectl -x -a hoge
@@ -580,6 +583,10 @@ testcase_08_resolved() {
run resolvectl query signed.test
grep -qF "signed.test: 10.0.0.10" "$RUN_OUT"
grep -qF "authenticated: yes" "$RUN_OUT"
(! run resolvectl --raw query localhost)
grep -qF -- "--raw may only be combined with --type= or dns: URIs." "$RUN_OUT"
resolvectl --raw=packet query --type=A signed.test >"$RUN_OUT"
test -s "$RUN_OUT"
run dig @ns1.unsigned.test +short MX signed.test
grep -qF "10 mail.signed.test." "$RUN_OUT"
run resolvectl query --legend=no -t MX signed.test
@@ -594,10 +601,13 @@ testcase_08_resolved() {
# Check SRV support
run resolvectl service _mysvc._tcp signed.test
grep -qF "myservice.signed.test:1234" "$RUN_OUT"
grep -qF "This is TXT for myservice" "$RUN_OUT"
(! grep -qF "This is TXT for myservice" "$RUN_OUT")
grep -qF "10.0.0.20" "$RUN_OUT"
grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT"
grep -qF "authenticated: yes" "$RUN_OUT"
run resolvectl service "" _mysvc._tcp signed.test
grep -qF "myservice.signed.test:1234" "$RUN_OUT"
grep -qF "This is TXT for myservice" "$RUN_OUT"
# Test service resolve over Varlink
run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"name":"","type":"_mysvc._tcp","domain":"signed.test"}'
@@ -1355,7 +1365,7 @@ testcase_14_refuse_record_types() {
run resolvectl service _mysvc._tcp signed.test
grep -qF "myservice.signed.test:1234" "$RUN_OUT"
grep -qF "This is TXT for myservice" "$RUN_OUT"
(! grep -qF "This is TXT for myservice" "$RUN_OUT")
grep -qF "10.0.0.20" "$RUN_OUT"
(! grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT")
grep -qF "authenticated: yes" "$RUN_OUT"
@@ -1377,7 +1387,7 @@ testcase_14_refuse_record_types() {
run resolvectl service _mysvc._tcp signed.test
grep -qF "myservice.signed.test:1234" "$RUN_OUT"
grep -qF "This is TXT for myservice" "$RUN_OUT"
(! grep -qF "This is TXT for myservice" "$RUN_OUT")
(! grep -qF "10.0.0.20" "$RUN_OUT")
(! grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT")
grep -qF "authenticated: yes" "$RUN_OUT"