diff options
Diffstat (limited to 'src/resolve/resolvectl.c')
-rw-r--r-- | src/resolve/resolvectl.c | 124 |
1 files changed, 90 insertions, 34 deletions
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index afa537f..f2e9e7a 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -184,6 +184,9 @@ static void print_source(uint64_t flags, usec_t rtt) { if (!arg_legend) return; + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return; + if (flags == 0) return; @@ -250,6 +253,9 @@ static int resolve_host(sd_bus *bus, const char *name) { assert(name); + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type=A or --type=AAAA to acquire address record information in JSON format."); + log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname); r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname"); @@ -348,6 +354,9 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a assert(IN_SET(family, AF_INET, AF_INET6)); assert(address); + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format."); + if (ifindex <= 0) ifindex = arg_ifindex; @@ -433,11 +442,26 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; int r; + assert(d || l == 0); + r = dns_resource_record_new_from_raw(&rr, d, l); if (r < 0) return log_error_errno(r, "Failed to parse RR: %m"); - if (arg_raw == RAW_PAYLOAD) { + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { + _cleanup_(json_variant_unrefp) JsonVariant *j = NULL; + r = dns_resource_record_to_json(rr, &j); + if (r < 0) + return log_error_errno(r, "Failed to convert RR to JSON: %m"); + + if (!j) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "JSON formatting for records of type %s (%u) not available.", dns_type_to_string(rr->key->type), rr->key->type); + + r = json_variant_dump(j, arg_json_format_flags, NULL, NULL); + if (r < 0) + return r; + + } else if (arg_raw == RAW_PAYLOAD) { void *data; ssize_t k; @@ -946,6 +970,9 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons static int verb_service(int argc, char **argv, void *userdata) { sd_bus *bus = userdata; + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format."); + if (argc == 2) return resolve_service(bus, NULL, NULL, argv[1]); else if (argc == 3) @@ -1005,6 +1032,9 @@ static int verb_openpgp(int argc, char **argv, void *userdata) { sd_bus *bus = userdata; int q, r = 0; + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format."); + STRV_FOREACH(p, argv + 1) { q = resolve_openpgp(bus, *p); if (q < 0) @@ -1056,6 +1086,9 @@ static int verb_tlsa(int argc, char **argv, void *userdata) { const char *family = "tcp"; int q, r = 0; + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Use --json=pretty with --type= to acquire resource record information in JSON format."); + if (service_family_is_valid(argv[1])) { family = argv[1]; args++; @@ -1080,9 +1113,9 @@ static int show_statistics(int argc, char **argv, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m"); - r = varlink_call(vl, "io.systemd.Resolve.Monitor.DumpStatistics", NULL, &reply, NULL, 0); + r = varlink_call_and_log(vl, "io.systemd.Resolve.Monitor.DumpStatistics", /* parameters= */ NULL, &reply); if (r < 0) - return log_error_errno(r, "Failed to issue DumpStatistics() varlink call: %m"); + return r; if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) return json_variant_dump(reply, arg_json_format_flags, NULL, NULL); @@ -1238,9 +1271,9 @@ static int reset_statistics(int argc, char **argv, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m"); - r = varlink_call(vl, "io.systemd.Resolve.Monitor.ResetStatistics", NULL, &reply, NULL, 0); + r = varlink_call_and_log(vl, "io.systemd.Resolve.Monitor.ResetStatistics", /* parameters= */ NULL, &reply); if (r < 0) - return log_error_errno(r, "Failed to issue ResetStatistics() varlink call: %m"); + return r; if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) return json_variant_dump(reply, arg_json_format_flags, NULL, NULL); @@ -2715,24 +2748,26 @@ static int print_answer(JsonVariant *answer) { static void monitor_query_dump(JsonVariant *v) { _cleanup_(json_variant_unrefp) JsonVariant *question = NULL, *answer = NULL, *collected_questions = NULL; - int rcode = -1, error = 0, r; - const char *state = NULL; + int rcode = -1, error = 0, ede_code = -1; + const char *state = NULL, *result = NULL, *ede_msg = NULL; assert(v); JsonDispatch dispatch_table[] = { - { "question", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&question), JSON_MANDATORY }, - { "answer", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&answer), 0 }, - { "collectedQuestions", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 }, - { "state", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&state), JSON_MANDATORY }, - { "rcode", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, PTR_TO_SIZE(&rcode), 0 }, - { "errno", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, PTR_TO_SIZE(&error), 0 }, + { "question", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&question), JSON_MANDATORY }, + { "answer", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&answer), 0 }, + { "collectedQuestions", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 }, + { "state", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&state), JSON_MANDATORY }, + { "result", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&result), 0 }, + { "rcode", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, PTR_TO_SIZE(&rcode), 0 }, + { "errno", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, PTR_TO_SIZE(&error), 0 }, + { "extendedDNSErrorCode", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, PTR_TO_SIZE(&ede_code), 0 }, + { "extendedDNSErrorMessage", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&ede_msg), 0 }, {} }; - r = json_dispatch(v, dispatch_table, 0, NULL); - if (r < 0) - return (void) log_warning("Received malformed monitor message, ignoring."); + if (json_dispatch(v, dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, NULL) < 0) + return; /* First show the current question */ print_question('Q', ansi_highlight_cyan(), question); @@ -2740,7 +2775,7 @@ static void monitor_query_dump(JsonVariant *v) { /* And then show the questions that led to this one in case this was a CNAME chain */ print_question('C', ansi_highlight_grey(), collected_questions); - printf("%s%s S%s: %s\n", + printf("%s%s S%s: %s", streq_ptr(state, "success") ? ansi_highlight_green() : ansi_highlight_red(), special_glyph(SPECIAL_GLYPH_ARROW_LEFT), ansi_normal(), @@ -2748,6 +2783,17 @@ static void monitor_query_dump(JsonVariant *v) { streq_ptr(state, "rcode-failure") ? dns_rcode_to_string(rcode) : state)); + if (!isempty(result)) + printf(": %s", result); + + if (ede_code >= 0) + printf(" (%s%s%s)", + FORMAT_DNS_EDE_RCODE(ede_code), + !isempty(ede_msg) ? ": " : "", + strempty(ede_msg)); + + puts(""); + print_answer(answer); } @@ -2856,7 +2902,7 @@ static int dump_cache_item(JsonVariant *item) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL; int r, c = 0; - r = json_dispatch(item, dispatch_table, JSON_LOG, &item_info); + r = json_dispatch(item, dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &item_info); if (r < 0) return r; @@ -2918,7 +2964,7 @@ static int dump_cache_scope(JsonVariant *scope) { {}, }; - r = json_dispatch(scope, dispatch_table, JSON_LOG, &scope_info); + r = json_dispatch(scope, dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &scope_info); if (r < 0) return r; @@ -2959,9 +3005,9 @@ static int verb_show_cache(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m"); - r = varlink_call(vl, "io.systemd.Resolve.Monitor.DumpCache", NULL, &reply, NULL, 0); + r = varlink_call_and_log(vl, "io.systemd.Resolve.Monitor.DumpCache", /* parameters= */ NULL, &reply); if (r < 0) - return log_error_errno(r, "Failed to issue DumpCache() varlink call: %m"); + return r; d = json_variant_by_key(reply, "dump"); if (!d) @@ -3034,7 +3080,7 @@ static int dump_server_state(JsonVariant *server) { {}, }; - r = json_dispatch(server, dispatch_table, JSON_LOG|JSON_PERMISSIVE, &server_state); + r = json_dispatch(server, dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &server_state); if (r < 0) return r; @@ -3133,9 +3179,9 @@ static int verb_show_server_state(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m"); - r = varlink_call(vl, "io.systemd.Resolve.Monitor.DumpServerState", NULL, &reply, NULL, 0); + r = varlink_call_and_log(vl, "io.systemd.Resolve.Monitor.DumpServerState", /* parameters= */ NULL, &reply); if (r < 0) - return log_error_errno(r, "Failed to issue DumpServerState() varlink call: %m"); + return r; d = json_variant_by_key(reply, "dump"); if (!d) @@ -3252,11 +3298,11 @@ static int native_help(void) { if (r < 0) return log_oom(); - printf("%s [OPTIONS...] COMMAND ...\n" + printf("%1$s [OPTIONS...] COMMAND ...\n" "\n" - "%sSend control commands to the network name resolution manager, or%s\n" - "%sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%s\n" - "\nCommands:\n" + "%5$sSend control commands to the network name resolution manager, or%6$s\n" + "%5$sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%6$s\n" + "\n%3$sCommands:%4$s\n" " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n" " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n" " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n" @@ -3279,7 +3325,7 @@ static int native_help(void) { " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n" " revert LINK Revert per-interface configuration\n" " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n" - "\nOptions:\n" + "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" " --version Show package version\n" " --no-pager Do not pipe output into a pager\n" @@ -3296,6 +3342,7 @@ static int native_help(void) { " --synthesize=BOOL Allow synthetic response (default: yes)\n" " --cache=BOOL Allow response from cache (default: yes)\n" " --stale-data=BOOL Allow response from cache with stale data (default: yes)\n" + " --relax-single-label=BOOL Allow single label lookups to go upstream (default: no)\n" " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n" " records (default: yes)\n" " --trust-anchor=BOOL Allow response from local trust anchor (default:\n" @@ -3308,13 +3355,13 @@ static int native_help(void) { " --json=MODE Output as JSON\n" " -j Same as --json=pretty on tty, --json=short\n" " otherwise\n" - "\nSee the %s for details.\n", + "\nSee the %2$s for details.\n", program_invocation_short_name, - ansi_highlight(), + link, + ansi_underline(), ansi_normal(), ansi_highlight(), - ansi_normal(), - link); + ansi_normal()); return 0; } @@ -3655,7 +3702,8 @@ static int native_parse_argv(int argc, char *argv[]) { ARG_SEARCH, ARG_NO_PAGER, ARG_JSON, - ARG_STALE_DATA + ARG_STALE_DATA, + ARG_RELAX_SINGLE_LABEL, }; static const struct option options[] = { @@ -3680,6 +3728,7 @@ static int native_parse_argv(int argc, char *argv[]) { { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "json", required_argument, NULL, ARG_JSON }, { "stale-data", required_argument, NULL, ARG_STALE_DATA }, + { "relax-single-label", required_argument, NULL, ARG_RELAX_SINGLE_LABEL }, {} }; @@ -3866,6 +3915,13 @@ static int native_parse_argv(int argc, char *argv[]) { SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; + case ARG_RELAX_SINGLE_LABEL: + r = parse_boolean_argument("--relax-single-label=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_RELAX_SINGLE_LABEL, r > 0); + break; + case ARG_NO_PAGER: arg_pager_flags |= PAGER_DISABLE; break; |