2 This file is part of systemd.
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
28 #include "bus-error.h"
31 #include "in-addr-util.h"
32 #include "gcrypt-util.h"
33 #include "parse-util.h"
34 #include "resolved-def.h"
35 #include "resolved-dns-packet.h"
36 #include "terminal-util.h"
38 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
40 static int arg_family
= AF_UNSPEC
;
41 static int arg_ifindex
= 0;
42 static uint16_t arg_type
= 0;
43 static uint16_t arg_class
= 0;
44 static bool arg_legend
= true;
45 static uint64_t arg_flags
= 0;
47 typedef enum RawType
{
53 static RawType arg_raw
= RAW_NONE
;
61 MODE_RESET_STATISTICS
,
62 } arg_mode
= MODE_RESOLVE_HOST
;
64 static void print_source(uint64_t flags
, usec_t rtt
) {
65 char rtt_str
[FORMAT_TIMESTAMP_MAX
];
73 fputs("\n-- Information acquired via", stdout
);
76 printf(" protocol%s%s%s%s%s",
77 flags
& SD_RESOLVED_DNS
? " DNS" :"",
78 flags
& SD_RESOLVED_LLMNR_IPV4
? " LLMNR/IPv4" : "",
79 flags
& SD_RESOLVED_LLMNR_IPV6
? " LLMNR/IPv6" : "",
80 flags
& SD_RESOLVED_MDNS_IPV4
? "mDNS/IPv4" : "",
81 flags
& SD_RESOLVED_MDNS_IPV6
? "mDNS/IPv6" : "");
83 assert_se(format_timespan(rtt_str
, sizeof(rtt_str
), rtt
, 100));
85 printf(" in %s", rtt_str
);
90 printf("-- Data is authenticated: %s\n", yes_no(flags
& SD_RESOLVED_AUTHENTICATED
));
93 static int resolve_host(sd_bus
*bus
, const char *name
) {
95 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
96 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
97 const char *canonical
= NULL
;
98 char ifname
[IF_NAMESIZE
] = "";
106 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
107 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
109 log_debug("Resolving %s (family %s, interface %s).", name
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
111 r
= sd_bus_message_new_method_call(
114 "org.freedesktop.resolve1",
115 "/org/freedesktop/resolve1",
116 "org.freedesktop.resolve1.Manager",
119 return bus_log_create_error(r
);
121 r
= sd_bus_message_append(req
, "isit", arg_ifindex
, name
, arg_family
, arg_flags
);
123 return bus_log_create_error(r
);
125 ts
= now(CLOCK_MONOTONIC
);
127 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
129 return log_error_errno(r
, "%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
131 ts
= now(CLOCK_MONOTONIC
) - ts
;
133 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
135 return bus_log_parse_error(r
);
137 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
138 _cleanup_free_
char *pretty
= NULL
;
143 assert_cc(sizeof(int) == sizeof(int32_t));
145 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
147 return bus_log_parse_error(r
);
149 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
151 return bus_log_parse_error(r
);
153 r
= sd_bus_message_exit_container(reply
);
155 return bus_log_parse_error(r
);
157 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
158 log_debug("%s: skipping entry with family %d (%s)", name
, family
, af_to_name(family
) ?: "unknown");
162 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
163 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name
, sz
, af_to_name(family
) ?: "unknown");
168 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
169 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
171 r
= in_addr_to_string(family
, a
, &pretty
);
173 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
175 printf("%*s%s %s%s%s\n",
176 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
178 isempty(ifname
) ? "" : "%", ifname
);
183 return bus_log_parse_error(r
);
185 r
= sd_bus_message_exit_container(reply
);
187 return bus_log_parse_error(r
);
189 r
= sd_bus_message_read(reply
, "st", &canonical
, &flags
);
191 return bus_log_parse_error(r
);
193 if (!streq(name
, canonical
))
194 printf("%*s%s (%s)\n",
195 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
199 log_error("%s: no addresses found", name
);
203 print_source(flags
, ts
);
208 static int resolve_address(sd_bus
*bus
, int family
, const union in_addr_union
*address
, int ifindex
) {
209 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
210 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
211 _cleanup_free_
char *pretty
= NULL
;
212 char ifname
[IF_NAMESIZE
] = "";
219 assert(IN_SET(family
, AF_INET
, AF_INET6
));
223 ifindex
= arg_ifindex
;
225 r
= in_addr_to_string(family
, address
, &pretty
);
229 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
230 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
232 log_debug("Resolving %s%s%s.", pretty
, isempty(ifname
) ? "" : "%", ifname
);
234 r
= sd_bus_message_new_method_call(
237 "org.freedesktop.resolve1",
238 "/org/freedesktop/resolve1",
239 "org.freedesktop.resolve1.Manager",
242 return bus_log_create_error(r
);
244 r
= sd_bus_message_append(req
, "ii", ifindex
, family
);
246 return bus_log_create_error(r
);
248 r
= sd_bus_message_append_array(req
, 'y', address
, FAMILY_ADDRESS_SIZE(family
));
250 return bus_log_create_error(r
);
252 r
= sd_bus_message_append(req
, "t", arg_flags
);
254 return bus_log_create_error(r
);
256 ts
= now(CLOCK_MONOTONIC
);
258 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
260 log_error("%s: resolve call failed: %s", pretty
, bus_error_message(&error
, r
));
264 ts
= now(CLOCK_MONOTONIC
) - ts
;
266 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
268 return bus_log_create_error(r
);
270 while ((r
= sd_bus_message_enter_container(reply
, 'r', "is")) > 0) {
273 assert_cc(sizeof(int) == sizeof(int32_t));
275 r
= sd_bus_message_read(reply
, "is", &ifindex
, &n
);
279 r
= sd_bus_message_exit_container(reply
);
284 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
285 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
287 printf("%*s%*s%*s%s %s\n",
288 (int) strlen(pretty
), c
== 0 ? pretty
: "",
289 isempty(ifname
) ? 0 : 1, c
> 0 || isempty(ifname
) ? "" : "%",
290 (int) strlen(ifname
), c
== 0 ? ifname
: "",
297 return bus_log_parse_error(r
);
299 r
= sd_bus_message_exit_container(reply
);
301 return bus_log_parse_error(r
);
303 r
= sd_bus_message_read(reply
, "t", &flags
);
305 return bus_log_parse_error(r
);
308 log_error("%s: no names found", pretty
);
312 print_source(flags
, ts
);
317 static int parse_address(const char *s
, int *family
, union in_addr_union
*address
, int *ifindex
) {
318 const char *percent
, *a
;
322 percent
= strchr(s
, '%');
324 if (parse_ifindex(percent
+1, &ifi
) < 0) {
325 ifi
= if_nametoindex(percent
+1);
330 a
= strndupa(s
, percent
- s
);
334 r
= in_addr_from_string_auto(a
, family
, address
);
342 static int output_rr_packet(const void *d
, size_t l
, int ifindex
) {
343 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
344 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
346 char ifname
[IF_NAMESIZE
] = "";
348 r
= dns_packet_new(&p
, DNS_PROTOCOL_DNS
, 0);
352 p
->refuse_compression
= true;
354 r
= dns_packet_append_blob(p
, d
, l
, NULL
);
358 r
= dns_packet_read_rr(p
, &rr
, NULL
, NULL
);
360 return log_error_errno(r
, "Failed to parse RR: %m");
362 if (arg_raw
== RAW_PAYLOAD
) {
366 k
= dns_resource_record_payload(rr
, &data
);
368 return log_error_errno(k
, "Cannot dump RR: %m");
369 fwrite(data
, 1, k
, stdout
);
373 s
= dns_resource_record_to_string(rr
);
377 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
378 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
380 printf("%s%s%s\n", s
, isempty(ifname
) ? "" : " # interface ", ifname
);
386 static int resolve_record(sd_bus
*bus
, const char *name
, uint16_t class, uint16_t type
) {
387 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
388 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
389 char ifname
[IF_NAMESIZE
] = "";
394 bool needs_authentication
= false;
398 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
399 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
401 log_debug("Resolving %s %s %s (interface %s).", name
, dns_class_to_string(class), dns_type_to_string(type
), isempty(ifname
) ? "*" : ifname
);
403 r
= sd_bus_message_new_method_call(
406 "org.freedesktop.resolve1",
407 "/org/freedesktop/resolve1",
408 "org.freedesktop.resolve1.Manager",
411 return bus_log_create_error(r
);
413 r
= sd_bus_message_append(req
, "isqqt", arg_ifindex
, name
, class, type
, arg_flags
);
415 return bus_log_create_error(r
);
417 ts
= now(CLOCK_MONOTONIC
);
419 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
421 log_error("%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
425 ts
= now(CLOCK_MONOTONIC
) - ts
;
427 r
= sd_bus_message_enter_container(reply
, 'a', "(iqqay)");
429 return bus_log_parse_error(r
);
431 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iqqay")) > 0) {
437 assert_cc(sizeof(int) == sizeof(int32_t));
439 r
= sd_bus_message_read(reply
, "iqq", &ifindex
, &c
, &t
);
441 return bus_log_parse_error(r
);
443 r
= sd_bus_message_read_array(reply
, 'y', &d
, &l
);
445 return bus_log_parse_error(r
);
447 r
= sd_bus_message_exit_container(reply
);
449 return bus_log_parse_error(r
);
451 if (arg_raw
== RAW_PACKET
) {
452 uint64_t u64
= htole64(l
);
454 fwrite(&u64
, sizeof(u64
), 1, stdout
);
455 fwrite(d
, 1, l
, stdout
);
457 r
= output_rr_packet(d
, l
, ifindex
);
462 if (dns_type_needs_authentication(t
))
463 needs_authentication
= true;
468 return bus_log_parse_error(r
);
470 r
= sd_bus_message_exit_container(reply
);
472 return bus_log_parse_error(r
);
474 r
= sd_bus_message_read(reply
, "t", &flags
);
476 return bus_log_parse_error(r
);
479 log_error("%s: no records found", name
);
483 print_source(flags
, ts
);
485 if ((flags
& SD_RESOLVED_AUTHENTICATED
) == 0 && needs_authentication
) {
488 fprintf(stderr
, "\n%s"
489 "WARNING: The resources shown contain cryptographic key data which could not be\n"
490 " authenticated. It is not suitable to authenticate any communication.\n"
491 " This is usually indication that DNSSEC authentication was not enabled\n"
492 " or is not available for the selected protocol or DNS servers.%s\n",
493 ansi_highlight_red(),
500 static int resolve_rfc4501(sd_bus
*bus
, const char *name
) {
501 uint16_t type
= 0, class = 0;
502 const char *p
, *q
, *n
;
507 assert(startswith(name
, "dns:"));
509 /* Parse RFC 4501 dns: URIs */
519 e
= strchr(p
+ 2, '/');
524 log_warning("DNS authority specification not supported; ignoring specified authority.");
531 n
= strndupa(p
, q
- p
);
537 f
= startswith_no_case(q
, "class=");
539 _cleanup_free_
char *t
= NULL
;
543 log_error("DNS class specified twice.");
547 e
= strchrnul(f
, ';');
548 t
= strndup(f
, e
- f
);
552 r
= dns_class_from_string(t
);
554 log_error("Unknown DNS class %s.", t
);
568 f
= startswith_no_case(q
, "type=");
570 _cleanup_free_
char *t
= NULL
;
574 log_error("DNS type specified twice.");
578 e
= strchrnul(f
, ';');
579 t
= strndup(f
, e
- f
);
583 r
= dns_type_from_string(t
);
585 log_error("Unknown DNS type %s.", t
);
605 class = arg_class
?: DNS_CLASS_IN
;
607 type
= arg_type
?: DNS_TYPE_A
;
609 return resolve_record(bus
, n
, class, type
);
612 log_error("Invalid DNS URI: %s", name
);
616 static int resolve_service(sd_bus
*bus
, const char *name
, const char *type
, const char *domain
) {
617 const char *canonical_name
, *canonical_type
, *canonical_domain
;
618 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
619 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
620 char ifname
[IF_NAMESIZE
] = "";
636 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
637 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
640 log_debug("Resolving service \"%s\" of type %s in %s (family %s, interface %s).", name
, type
, domain
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
642 log_debug("Resolving service type %s of %s (family %s, interface %s).", type
, domain
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
644 log_debug("Resolving service type %s (family %s, interface %s).", domain
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
646 r
= sd_bus_message_new_method_call(
649 "org.freedesktop.resolve1",
650 "/org/freedesktop/resolve1",
651 "org.freedesktop.resolve1.Manager",
654 return bus_log_create_error(r
);
656 r
= sd_bus_message_append(req
, "isssit", arg_ifindex
, name
, type
, domain
, arg_family
, arg_flags
);
658 return bus_log_create_error(r
);
660 ts
= now(CLOCK_MONOTONIC
);
662 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
664 return log_error_errno(r
, "Resolve call failed: %s", bus_error_message(&error
, r
));
666 ts
= now(CLOCK_MONOTONIC
) - ts
;
668 r
= sd_bus_message_enter_container(reply
, 'a', "(qqqsa(iiay)s)");
670 return bus_log_parse_error(r
);
673 (name
? strlen(name
) + 1 : 0) +
674 (type
? strlen(type
) + 1 : 0) +
678 while ((r
= sd_bus_message_enter_container(reply
, 'r', "qqqsa(iiay)s")) > 0) {
679 uint16_t priority
, weight
, port
;
680 const char *hostname
, *canonical
;
682 r
= sd_bus_message_read(reply
, "qqqs", &priority
, &weight
, &port
, &hostname
);
684 return bus_log_parse_error(r
);
687 printf("%*s%s", (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? "/" : " ");
689 printf("%*s%s", (int) strlen(type
), c
== 0 ? type
: "", c
== 0 ? "/" : " ");
691 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
692 (int) strlen(domain
), c
== 0 ? domain
: "",
697 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
699 return bus_log_parse_error(r
);
701 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
702 _cleanup_free_
char *pretty
= NULL
;
706 assert_cc(sizeof(int) == sizeof(int32_t));
708 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
710 return bus_log_parse_error(r
);
712 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
714 return bus_log_parse_error(r
);
716 r
= sd_bus_message_exit_container(reply
);
718 return bus_log_parse_error(r
);
720 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
721 log_debug("%s: skipping entry with family %d (%s)", name
, family
, af_to_name(family
) ?: "unknown");
725 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
726 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name
, sz
, af_to_name(family
) ?: "unknown");
731 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
732 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
734 r
= in_addr_to_string(family
, a
, &pretty
);
736 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
738 printf("%*s%s%s%s\n", (int) indent
, "", pretty
, isempty(ifname
) ? "" : "%s", ifname
);
741 return bus_log_parse_error(r
);
743 r
= sd_bus_message_exit_container(reply
);
745 return bus_log_parse_error(r
);
747 r
= sd_bus_message_read(reply
, "s", &canonical
);
749 return bus_log_parse_error(r
);
751 if (!streq(hostname
, canonical
))
752 printf("%*s(%s)\n", (int) indent
, "", canonical
);
754 r
= sd_bus_message_exit_container(reply
);
756 return bus_log_parse_error(r
);
761 return bus_log_parse_error(r
);
763 r
= sd_bus_message_exit_container(reply
);
765 return bus_log_parse_error(r
);
767 r
= sd_bus_message_enter_container(reply
, 'a', "ay");
769 return bus_log_parse_error(r
);
772 while ((r
= sd_bus_message_read_array(reply
, 'y', (const void**) &p
, &sz
)) > 0) {
773 _cleanup_free_
char *escaped
= NULL
;
775 escaped
= cescape_length(p
, sz
);
779 printf("%*s%s\n", (int) indent
, "", escaped
);
783 return bus_log_parse_error(r
);
785 r
= sd_bus_message_exit_container(reply
);
787 return bus_log_parse_error(r
);
789 r
= sd_bus_message_read(reply
, "ssst", &canonical_name
, &canonical_type
, &canonical_domain
, &flags
);
791 return bus_log_parse_error(r
);
793 if (isempty(canonical_name
))
794 canonical_name
= NULL
;
795 if (isempty(canonical_type
))
796 canonical_type
= NULL
;
798 if (!streq_ptr(name
, canonical_name
) ||
799 !streq_ptr(type
, canonical_type
) ||
800 !streq_ptr(domain
, canonical_domain
)) {
802 printf("%*s(", (int) indent
, "");
805 printf("%s/", canonical_name
);
807 printf("%s/", canonical_type
);
809 printf("%s)\n", canonical_domain
);
812 print_source(flags
, ts
);
817 static int resolve_openpgp(sd_bus
*bus
, const char *address
) {
818 const char *domain
, *full
;
820 _cleanup_free_
char *hashed
= NULL
;
825 domain
= strrchr(address
, '@');
827 log_error("Address does not contain '@': \"%s\"", address
);
829 } else if (domain
== address
|| domain
[1] == '\0') {
830 log_error("Address starts or ends with '@': \"%s\"", address
);
835 r
= string_hashsum(address
, domain
- 1 - address
, GCRY_MD_SHA224
, &hashed
);
837 return log_error_errno(r
, "Hashing failed: %m");
839 full
= strjoina(hashed
, "._openpgpkey.", domain
);
840 log_debug("Looking up \"%s\".", full
);
842 return resolve_record(bus
, full
,
843 arg_class
?: DNS_CLASS_IN
,
844 arg_type
?: DNS_TYPE_OPENPGPKEY
);
847 static int show_statistics(sd_bus
*bus
) {
848 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
849 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
850 uint64_t n_current_transactions
, n_total_transactions
,
851 cache_size
, n_cache_hit
, n_cache_miss
,
852 n_dnssec_secure
, n_dnssec_insecure
, n_dnssec_bogus
, n_dnssec_indeterminate
;
853 int r
, dnssec_supported
;
857 r
= sd_bus_get_property_trivial(bus
,
858 "org.freedesktop.resolve1",
859 "/org/freedesktop/resolve1",
860 "org.freedesktop.resolve1.Manager",
866 return log_error_errno(r
, "Failed to get DNSSEC supported state: %s", bus_error_message(&error
, r
));
868 printf("DNSSEC supported by current servers: %s%s%s\n\n",
870 yes_no(dnssec_supported
),
873 r
= sd_bus_get_property(bus
,
874 "org.freedesktop.resolve1",
875 "/org/freedesktop/resolve1",
876 "org.freedesktop.resolve1.Manager",
877 "TransactionStatistics",
882 return log_error_errno(r
, "Failed to get transaction statistics: %s", bus_error_message(&error
, r
));
884 r
= sd_bus_message_read(reply
, "(tt)",
885 &n_current_transactions
,
886 &n_total_transactions
);
888 return bus_log_parse_error(r
);
890 printf("%sTransactions%s\n"
891 "Current Transactions: %" PRIu64
"\n"
892 " Total Transactions: %" PRIu64
"\n",
895 n_current_transactions
,
896 n_total_transactions
);
898 reply
= sd_bus_message_unref(reply
);
900 r
= sd_bus_get_property(bus
,
901 "org.freedesktop.resolve1",
902 "/org/freedesktop/resolve1",
903 "org.freedesktop.resolve1.Manager",
909 return log_error_errno(r
, "Failed to get cache statistics: %s", bus_error_message(&error
, r
));
911 r
= sd_bus_message_read(reply
, "(ttt)",
916 return bus_log_parse_error(r
);
918 printf("\n%sCache%s\n"
919 " Current Cache Size: %" PRIu64
"\n"
920 " Cache Hits: %" PRIu64
"\n"
921 " Cache Misses: %" PRIu64
"\n",
928 reply
= sd_bus_message_unref(reply
);
930 r
= sd_bus_get_property(bus
,
931 "org.freedesktop.resolve1",
932 "/org/freedesktop/resolve1",
933 "org.freedesktop.resolve1.Manager",
939 return log_error_errno(r
, "Failed to get DNSSEC statistics: %s", bus_error_message(&error
, r
));
941 r
= sd_bus_message_read(reply
, "(tttt)",
945 &n_dnssec_indeterminate
);
947 return bus_log_parse_error(r
);
949 printf("\n%sDNSSEC Verdicts%s\n"
950 " Secure: %" PRIu64
"\n"
951 " Insecure: %" PRIu64
"\n"
952 " Bogus: %" PRIu64
"\n"
953 " Indeterminate: %" PRIu64
"\n",
959 n_dnssec_indeterminate
);
964 static int reset_statistics(sd_bus
*bus
) {
965 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
968 r
= sd_bus_call_method(bus
,
969 "org.freedesktop.resolve1",
970 "/org/freedesktop/resolve1",
971 "org.freedesktop.resolve1.Manager",
977 return log_error_errno(r
, "Failed to reset statistics: %s", bus_error_message(&error
, r
));
982 static void help_protocol_types(void) {
984 puts("Known protocol types:");
985 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
988 static void help_dns_types(void) {
993 puts("Known DNS RR types:");
994 for (i
= 0; i
< _DNS_TYPE_MAX
; i
++) {
995 t
= dns_type_to_string(i
);
1001 static void help_dns_classes(void) {
1006 puts("Known DNS RR classes:");
1007 for (i
= 0; i
< _DNS_CLASS_MAX
; i
++) {
1008 t
= dns_class_to_string(i
);
1014 static void help(void) {
1015 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
1016 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
1017 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
1018 "%1$s [OPTIONS...] --statistics\n"
1019 "%1$s [OPTIONS...] --reset-statistics\n"
1021 "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
1022 " -h --help Show this help\n"
1023 " --version Show package version\n"
1024 " -4 Resolve IPv4 addresses\n"
1025 " -6 Resolve IPv6 addresses\n"
1026 " -i --interface=INTERFACE Look on interface\n"
1027 " -p --protocol=PROTO|help Look via protocol\n"
1028 " -t --type=TYPE|help Query RR with DNS type\n"
1029 " -c --class=CLASS|help Query RR with DNS class\n"
1030 " --service Resolve service (SRV)\n"
1031 " --service-address=BOOL Resolve address for services (default: yes)\n"
1032 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
1033 " --openpgp Query OpenPGP public key\n"
1034 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
1035 " --search=BOOL Use search domains for single-label names\n"
1037 " --raw[=payload|packet] Dump the answer as binary data\n"
1038 " --legend=BOOL Print headers and additional info (default: yes)\n"
1039 " --statistics Show resolver statistics\n"
1040 " --reset-statistics Reset resolver statistics\n"
1041 , program_invocation_short_name
);
1044 static int parse_argv(int argc
, char *argv
[]) {
1046 ARG_VERSION
= 0x100,
1050 ARG_SERVICE_ADDRESS
,
1056 ARG_RESET_STATISTICS
,
1059 static const struct option options
[] = {
1060 { "help", no_argument
, NULL
, 'h' },
1061 { "version", no_argument
, NULL
, ARG_VERSION
},
1062 { "type", required_argument
, NULL
, 't' },
1063 { "class", required_argument
, NULL
, 'c' },
1064 { "legend", required_argument
, NULL
, ARG_LEGEND
},
1065 { "interface", required_argument
, NULL
, 'i' },
1066 { "protocol", required_argument
, NULL
, 'p' },
1067 { "cname", required_argument
, NULL
, ARG_CNAME
},
1068 { "service", no_argument
, NULL
, ARG_SERVICE
},
1069 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
1070 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
1071 { "openpgp", no_argument
, NULL
, ARG_OPENPGP
},
1072 { "raw", optional_argument
, NULL
, ARG_RAW
},
1073 { "search", required_argument
, NULL
, ARG_SEARCH
},
1074 { "statistics", no_argument
, NULL
, ARG_STATISTICS
, },
1075 { "reset-statistics", no_argument
, NULL
, ARG_RESET_STATISTICS
},
1084 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:", options
, NULL
)) >= 0)
1089 return 0; /* done */;
1095 arg_family
= AF_INET
;
1099 arg_family
= AF_INET6
;
1105 if (parse_ifindex(optarg
, &ifi
) >= 0)
1108 ifi
= if_nametoindex(optarg
);
1110 return log_error_errno(errno
, "Unknown interface %s: %m", optarg
);
1119 if (streq(optarg
, "help")) {
1124 r
= dns_type_from_string(optarg
);
1126 log_error("Failed to parse RR record type %s", optarg
);
1129 arg_type
= (uint16_t) r
;
1130 assert((int) arg_type
== r
);
1132 arg_mode
= MODE_RESOLVE_RECORD
;
1136 if (streq(optarg
, "help")) {
1141 r
= dns_class_from_string(optarg
);
1143 log_error("Failed to parse RR record class %s", optarg
);
1146 arg_class
= (uint16_t) r
;
1147 assert((int) arg_class
== r
);
1152 r
= parse_boolean(optarg
);
1154 return log_error_errno(r
, "Failed to parse --legend= argument");
1160 if (streq(optarg
, "help")) {
1161 help_protocol_types();
1163 } else if (streq(optarg
, "dns"))
1164 arg_flags
|= SD_RESOLVED_DNS
;
1165 else if (streq(optarg
, "llmnr"))
1166 arg_flags
|= SD_RESOLVED_LLMNR
;
1167 else if (streq(optarg
, "llmnr-ipv4"))
1168 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
1169 else if (streq(optarg
, "llmnr-ipv6"))
1170 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
1172 log_error("Unknown protocol specifier: %s", optarg
);
1179 arg_mode
= MODE_RESOLVE_SERVICE
;
1183 arg_mode
= MODE_RESOLVE_OPENPGP
;
1188 log_error("Refusing to write binary data to tty.");
1192 if (optarg
== NULL
|| streq(optarg
, "payload"))
1193 arg_raw
= RAW_PAYLOAD
;
1194 else if (streq(optarg
, "packet"))
1195 arg_raw
= RAW_PACKET
;
1197 log_error("Unknown --raw specifier \"%s\".", optarg
);
1205 r
= parse_boolean(optarg
);
1207 return log_error_errno(r
, "Failed to parse --cname= argument.");
1209 arg_flags
|= SD_RESOLVED_NO_CNAME
;
1211 arg_flags
&= ~SD_RESOLVED_NO_CNAME
;
1214 case ARG_SERVICE_ADDRESS
:
1215 r
= parse_boolean(optarg
);
1217 return log_error_errno(r
, "Failed to parse --service-address= argument.");
1219 arg_flags
|= SD_RESOLVED_NO_ADDRESS
;
1221 arg_flags
&= ~SD_RESOLVED_NO_ADDRESS
;
1224 case ARG_SERVICE_TXT
:
1225 r
= parse_boolean(optarg
);
1227 return log_error_errno(r
, "Failed to parse --service-txt= argument.");
1229 arg_flags
|= SD_RESOLVED_NO_TXT
;
1231 arg_flags
&= ~SD_RESOLVED_NO_TXT
;
1235 r
= parse_boolean(optarg
);
1237 return log_error_errno(r
, "Failed to parse --search argument.");
1239 arg_flags
|= SD_RESOLVED_NO_SEARCH
;
1241 arg_flags
&= ~SD_RESOLVED_NO_SEARCH
;
1244 case ARG_STATISTICS
:
1245 arg_mode
= MODE_STATISTICS
;
1248 case ARG_RESET_STATISTICS
:
1249 arg_mode
= MODE_RESET_STATISTICS
;
1256 assert_not_reached("Unhandled option");
1259 if (arg_type
== 0 && arg_class
!= 0) {
1260 log_error("--class= may only be used in conjunction with --type=.");
1264 if (arg_type
!= 0 && arg_mode
!= MODE_RESOLVE_RECORD
) {
1265 log_error("--service and --type= may not be combined.");
1269 if (arg_type
!= 0 && arg_class
== 0)
1270 arg_class
= DNS_CLASS_IN
;
1272 if (arg_class
!= 0 && arg_type
== 0)
1273 arg_type
= DNS_TYPE_A
;
1275 return 1 /* work to do */;
1278 int main(int argc
, char **argv
) {
1279 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1282 log_parse_environment();
1285 r
= parse_argv(argc
, argv
);
1289 r
= sd_bus_open_system(&bus
);
1291 log_error_errno(r
, "sd_bus_open_system: %m");
1297 case MODE_RESOLVE_HOST
:
1298 if (optind
>= argc
) {
1299 log_error("No arguments passed.");
1304 while (argv
[optind
]) {
1305 int family
, ifindex
, k
;
1306 union in_addr_union a
;
1308 if (startswith(argv
[optind
], "dns:"))
1309 k
= resolve_rfc4501(bus
, argv
[optind
]);
1311 k
= parse_address(argv
[optind
], &family
, &a
, &ifindex
);
1313 k
= resolve_address(bus
, family
, &a
, ifindex
);
1315 k
= resolve_host(bus
, argv
[optind
]);
1325 case MODE_RESOLVE_RECORD
:
1326 if (optind
>= argc
) {
1327 log_error("No arguments passed.");
1332 while (argv
[optind
]) {
1335 k
= resolve_record(bus
, argv
[optind
], arg_class
, arg_type
);
1343 case MODE_RESOLVE_SERVICE
:
1344 if (argc
< optind
+ 1) {
1345 log_error("Domain specification required.");
1349 } else if (argc
== optind
+ 1)
1350 r
= resolve_service(bus
, NULL
, NULL
, argv
[optind
]);
1351 else if (argc
== optind
+ 2)
1352 r
= resolve_service(bus
, NULL
, argv
[optind
], argv
[optind
+1]);
1353 else if (argc
== optind
+ 3)
1354 r
= resolve_service(bus
, argv
[optind
], argv
[optind
+1], argv
[optind
+2]);
1356 log_error("Too many arguments.");
1363 case MODE_RESOLVE_OPENPGP
:
1364 if (argc
< optind
+ 1) {
1365 log_error("E-mail address required.");
1372 while (optind
< argc
) {
1375 k
= resolve_openpgp(bus
, argv
[optind
++]);
1381 case MODE_STATISTICS
:
1382 if (argc
> optind
) {
1383 log_error("Too many arguments.");
1388 r
= show_statistics(bus
);
1391 case MODE_RESET_STATISTICS
:
1392 if (argc
> optind
) {
1393 log_error("Too many arguments.");
1398 r
= reset_statistics(bus
);
1403 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;