1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "alloc-util.h"
29 #include "bus-error.h"
32 #include "in-addr-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;
52 MODE_RESET_STATISTICS
,
53 } arg_mode
= MODE_RESOLVE_HOST
;
55 static void print_source(uint64_t flags
, usec_t rtt
) {
56 char rtt_str
[FORMAT_TIMESTAMP_MAX
];
64 fputs("\n-- Information acquired via", stdout
);
67 printf(" protocol%s%s%s%s%s",
68 flags
& SD_RESOLVED_DNS
? " DNS" :"",
69 flags
& SD_RESOLVED_LLMNR_IPV4
? " LLMNR/IPv4" : "",
70 flags
& SD_RESOLVED_LLMNR_IPV6
? " LLMNR/IPv6" : "",
71 flags
& SD_RESOLVED_MDNS_IPV4
? "mDNS/IPv4" : "",
72 flags
& SD_RESOLVED_MDNS_IPV6
? "mDNS/IPv6" : "");
74 assert_se(format_timespan(rtt_str
, sizeof(rtt_str
), rtt
, 100));
76 printf(" in %s", rtt_str
);
81 printf("-- Data is authenticated: %s\n", yes_no(flags
& SD_RESOLVED_AUTHENTICATED
));
84 static int resolve_host(sd_bus
*bus
, const char *name
) {
86 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
87 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
88 const char *canonical
= NULL
;
89 char ifname
[IF_NAMESIZE
] = "";
97 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
98 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
100 log_debug("Resolving %s (family %s, interface %s).", name
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
102 r
= sd_bus_message_new_method_call(
105 "org.freedesktop.resolve1",
106 "/org/freedesktop/resolve1",
107 "org.freedesktop.resolve1.Manager",
110 return bus_log_create_error(r
);
112 r
= sd_bus_message_append(req
, "isit", arg_ifindex
, name
, arg_family
, arg_flags
);
114 return bus_log_create_error(r
);
116 ts
= now(CLOCK_MONOTONIC
);
118 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
120 return log_error_errno(r
, "%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
122 ts
= now(CLOCK_MONOTONIC
) - ts
;
124 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
126 return bus_log_parse_error(r
);
128 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
129 _cleanup_free_
char *pretty
= NULL
;
134 assert_cc(sizeof(int) == sizeof(int32_t));
136 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
138 return bus_log_parse_error(r
);
140 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
142 return bus_log_parse_error(r
);
144 r
= sd_bus_message_exit_container(reply
);
146 return bus_log_parse_error(r
);
148 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
149 log_debug("%s: skipping entry with family %d (%s)", name
, family
, af_to_name(family
) ?: "unknown");
153 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
154 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name
, sz
, af_to_name(family
) ?: "unknown");
159 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
160 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
162 r
= in_addr_to_string(family
, a
, &pretty
);
164 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
166 printf("%*s%s %s%s%s\n",
167 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
169 isempty(ifname
) ? "" : "%", ifname
);
174 return bus_log_parse_error(r
);
176 r
= sd_bus_message_exit_container(reply
);
178 return bus_log_parse_error(r
);
180 r
= sd_bus_message_read(reply
, "st", &canonical
, &flags
);
182 return bus_log_parse_error(r
);
184 if (!streq(name
, canonical
))
185 printf("%*s%s (%s)\n",
186 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
190 log_error("%s: no addresses found", name
);
194 print_source(flags
, ts
);
199 static int resolve_address(sd_bus
*bus
, int family
, const union in_addr_union
*address
, int ifindex
) {
200 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
201 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
202 _cleanup_free_
char *pretty
= NULL
;
203 char ifname
[IF_NAMESIZE
] = "";
210 assert(IN_SET(family
, AF_INET
, AF_INET6
));
214 ifindex
= arg_ifindex
;
216 r
= in_addr_to_string(family
, address
, &pretty
);
220 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
221 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
223 log_debug("Resolving %s%s%s.", pretty
, isempty(ifname
) ? "" : "%", ifname
);
225 r
= sd_bus_message_new_method_call(
228 "org.freedesktop.resolve1",
229 "/org/freedesktop/resolve1",
230 "org.freedesktop.resolve1.Manager",
233 return bus_log_create_error(r
);
235 r
= sd_bus_message_append(req
, "ii", ifindex
, family
);
237 return bus_log_create_error(r
);
239 r
= sd_bus_message_append_array(req
, 'y', address
, FAMILY_ADDRESS_SIZE(family
));
241 return bus_log_create_error(r
);
243 r
= sd_bus_message_append(req
, "t", arg_flags
);
245 return bus_log_create_error(r
);
247 ts
= now(CLOCK_MONOTONIC
);
249 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
251 log_error("%s: resolve call failed: %s", pretty
, bus_error_message(&error
, r
));
255 ts
= now(CLOCK_MONOTONIC
) - ts
;
257 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
259 return bus_log_create_error(r
);
261 while ((r
= sd_bus_message_enter_container(reply
, 'r', "is")) > 0) {
264 assert_cc(sizeof(int) == sizeof(int32_t));
266 r
= sd_bus_message_read(reply
, "is", &ifindex
, &n
);
270 r
= sd_bus_message_exit_container(reply
);
275 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
276 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
278 printf("%*s%*s%*s%s %s\n",
279 (int) strlen(pretty
), c
== 0 ? pretty
: "",
280 isempty(ifname
) ? 0 : 1, c
> 0 || isempty(ifname
) ? "" : "%",
281 (int) strlen(ifname
), c
== 0 ? ifname
: "",
288 return bus_log_parse_error(r
);
290 r
= sd_bus_message_exit_container(reply
);
292 return bus_log_parse_error(r
);
294 r
= sd_bus_message_read(reply
, "t", &flags
);
296 return bus_log_parse_error(r
);
299 log_error("%s: no names found", pretty
);
303 print_source(flags
, ts
);
308 static int parse_address(const char *s
, int *family
, union in_addr_union
*address
, int *ifindex
) {
309 const char *percent
, *a
;
313 percent
= strchr(s
, '%');
315 if (parse_ifindex(percent
+1, &ifi
) < 0) {
316 ifi
= if_nametoindex(percent
+1);
321 a
= strndupa(s
, percent
- s
);
325 r
= in_addr_from_string_auto(a
, family
, address
);
333 static int resolve_record(sd_bus
*bus
, const char *name
, uint16_t class, uint16_t type
) {
334 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
335 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
336 char ifname
[IF_NAMESIZE
] = "";
344 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
345 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
347 log_debug("Resolving %s %s %s (interface %s).", name
, dns_class_to_string(class), dns_type_to_string(type
), isempty(ifname
) ? "*" : ifname
);
349 r
= sd_bus_message_new_method_call(
352 "org.freedesktop.resolve1",
353 "/org/freedesktop/resolve1",
354 "org.freedesktop.resolve1.Manager",
357 return bus_log_create_error(r
);
359 r
= sd_bus_message_append(req
, "isqqt", arg_ifindex
, name
, class, type
, arg_flags
);
361 return bus_log_create_error(r
);
363 ts
= now(CLOCK_MONOTONIC
);
365 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
367 log_error("%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
371 ts
= now(CLOCK_MONOTONIC
) - ts
;
373 r
= sd_bus_message_enter_container(reply
, 'a', "(iqqay)");
375 return bus_log_parse_error(r
);
377 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iqqay")) > 0) {
378 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
379 _cleanup_(dns_packet_unrefp
) DnsPacket
*p
= NULL
;
386 assert_cc(sizeof(int) == sizeof(int32_t));
388 r
= sd_bus_message_read(reply
, "iqq", &ifindex
, &c
, &t
);
390 return bus_log_parse_error(r
);
392 r
= sd_bus_message_read_array(reply
, 'y', &d
, &l
);
394 return bus_log_parse_error(r
);
396 r
= sd_bus_message_exit_container(reply
);
398 return bus_log_parse_error(r
);
400 r
= dns_packet_new(&p
, DNS_PROTOCOL_DNS
, 0);
404 p
->refuse_compression
= true;
406 r
= dns_packet_append_blob(p
, d
, l
, NULL
);
410 r
= dns_packet_read_rr(p
, &rr
, NULL
, NULL
);
412 return log_error_errno(r
, "Failed to parse RR: %m");
414 s
= dns_resource_record_to_string(rr
);
419 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
420 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
422 printf("%s%s%s\n", s
, isempty(ifname
) ? "" : " # interface ", ifname
);
426 return bus_log_parse_error(r
);
428 r
= sd_bus_message_exit_container(reply
);
430 return bus_log_parse_error(r
);
432 r
= sd_bus_message_read(reply
, "t", &flags
);
434 return bus_log_parse_error(r
);
437 log_error("%s: no records found", name
);
441 print_source(flags
, ts
);
446 static int resolve_rfc4501(sd_bus
*bus
, const char *name
) {
447 uint16_t type
= 0, class = 0;
448 const char *p
, *q
, *n
;
453 assert(startswith(name
, "dns:"));
455 /* Parse RFC 4501 dns: URIs */
465 e
= strchr(p
+ 2, '/');
470 log_warning("DNS authority specification not supported; ignoring specified authority.");
477 n
= strndupa(p
, q
- p
);
483 f
= startswith_no_case(q
, "class=");
485 _cleanup_free_
char *t
= NULL
;
489 log_error("DNS class specified twice.");
493 e
= strchrnul(f
, ';');
494 t
= strndup(f
, e
- f
);
498 r
= dns_class_from_string(t
);
500 log_error("Unknown DNS class %s.", t
);
514 f
= startswith_no_case(q
, "type=");
516 _cleanup_free_
char *t
= NULL
;
520 log_error("DNS type specified twice.");
524 e
= strchrnul(f
, ';');
525 t
= strndup(f
, e
- f
);
529 r
= dns_type_from_string(t
);
531 log_error("Unknown DNS type %s.", t
);
558 class = DNS_CLASS_IN
;
560 return resolve_record(bus
, n
, class, type
);
563 log_error("Invalid DNS URI: %s", name
);
567 static int resolve_service(sd_bus
*bus
, const char *name
, const char *type
, const char *domain
) {
568 const char *canonical_name
, *canonical_type
, *canonical_domain
;
569 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
570 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
571 char ifname
[IF_NAMESIZE
] = "";
587 if (arg_ifindex
> 0 && !if_indextoname(arg_ifindex
, ifname
))
588 return log_error_errno(errno
, "Failed to resolve interface name for index %i: %m", arg_ifindex
);
591 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
);
593 log_debug("Resolving service type %s of %s (family %s, interface %s).", type
, domain
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
595 log_debug("Resolving service type %s (family %s, interface %s).", domain
, af_to_name(arg_family
) ?: "*", isempty(ifname
) ? "*" : ifname
);
597 r
= sd_bus_message_new_method_call(
600 "org.freedesktop.resolve1",
601 "/org/freedesktop/resolve1",
602 "org.freedesktop.resolve1.Manager",
605 return bus_log_create_error(r
);
607 r
= sd_bus_message_append(req
, "isssit", arg_ifindex
, name
, type
, domain
, arg_family
, arg_flags
);
609 return bus_log_create_error(r
);
611 ts
= now(CLOCK_MONOTONIC
);
613 r
= sd_bus_call(bus
, req
, DNS_CALL_TIMEOUT_USEC
, &error
, &reply
);
615 return log_error_errno(r
, "Resolve call failed: %s", bus_error_message(&error
, r
));
617 ts
= now(CLOCK_MONOTONIC
) - ts
;
619 r
= sd_bus_message_enter_container(reply
, 'a', "(qqqsa(iiay)s)");
621 return bus_log_parse_error(r
);
624 (name
? strlen(name
) + 1 : 0) +
625 (type
? strlen(type
) + 1 : 0) +
629 while ((r
= sd_bus_message_enter_container(reply
, 'r', "qqqsa(iiay)s")) > 0) {
630 uint16_t priority
, weight
, port
;
631 const char *hostname
, *canonical
;
633 r
= sd_bus_message_read(reply
, "qqqs", &priority
, &weight
, &port
, &hostname
);
635 return bus_log_parse_error(r
);
638 printf("%*s%s", (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? "/" : " ");
640 printf("%*s%s", (int) strlen(type
), c
== 0 ? type
: "", c
== 0 ? "/" : " ");
642 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
643 (int) strlen(domain
), c
== 0 ? domain
: "",
648 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
650 return bus_log_parse_error(r
);
652 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
653 _cleanup_free_
char *pretty
= NULL
;
657 assert_cc(sizeof(int) == sizeof(int32_t));
659 r
= sd_bus_message_read(reply
, "ii", &ifindex
, &family
);
661 return bus_log_parse_error(r
);
663 r
= sd_bus_message_read_array(reply
, 'y', &a
, &sz
);
665 return bus_log_parse_error(r
);
667 r
= sd_bus_message_exit_container(reply
);
669 return bus_log_parse_error(r
);
671 if (!IN_SET(family
, AF_INET
, AF_INET6
)) {
672 log_debug("%s: skipping entry with family %d (%s)", name
, family
, af_to_name(family
) ?: "unknown");
676 if (sz
!= FAMILY_ADDRESS_SIZE(family
)) {
677 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name
, sz
, af_to_name(family
) ?: "unknown");
682 if (ifindex
> 0 && !if_indextoname(ifindex
, ifname
))
683 log_warning_errno(errno
, "Failed to resolve interface name for index %i: %m", ifindex
);
685 r
= in_addr_to_string(family
, a
, &pretty
);
687 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
689 printf("%*s%s%s%s\n", (int) indent
, "", pretty
, isempty(ifname
) ? "" : "%s", ifname
);
692 return bus_log_parse_error(r
);
694 r
= sd_bus_message_exit_container(reply
);
696 return bus_log_parse_error(r
);
698 r
= sd_bus_message_read(reply
, "s", &canonical
);
700 return bus_log_parse_error(r
);
702 if (!streq(hostname
, canonical
))
703 printf("%*s(%s)\n", (int) indent
, "", canonical
);
705 r
= sd_bus_message_exit_container(reply
);
707 return bus_log_parse_error(r
);
712 return bus_log_parse_error(r
);
714 r
= sd_bus_message_exit_container(reply
);
716 return bus_log_parse_error(r
);
718 r
= sd_bus_message_enter_container(reply
, 'a', "ay");
720 return bus_log_parse_error(r
);
723 while ((r
= sd_bus_message_read_array(reply
, 'y', (const void**) &p
, &sz
)) > 0) {
724 _cleanup_free_
char *escaped
= NULL
;
726 escaped
= cescape_length(p
, sz
);
730 printf("%*s%s\n", (int) indent
, "", escaped
);
734 return bus_log_parse_error(r
);
736 r
= sd_bus_message_exit_container(reply
);
738 return bus_log_parse_error(r
);
740 r
= sd_bus_message_read(reply
, "ssst", &canonical_name
, &canonical_type
, &canonical_domain
, &flags
);
742 return bus_log_parse_error(r
);
744 if (isempty(canonical_name
))
745 canonical_name
= NULL
;
746 if (isempty(canonical_type
))
747 canonical_type
= NULL
;
749 if (!streq_ptr(name
, canonical_name
) ||
750 !streq_ptr(type
, canonical_type
) ||
751 !streq_ptr(domain
, canonical_domain
)) {
753 printf("%*s(", (int) indent
, "");
756 printf("%s/", canonical_name
);
758 printf("%s/", canonical_type
);
760 printf("%s)\n", canonical_domain
);
763 print_source(flags
, ts
);
768 static int show_statistics(sd_bus
*bus
) {
769 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
770 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
771 uint64_t n_current_transactions
, n_total_transactions
,
772 cache_size
, n_cache_hit
, n_cache_miss
,
773 n_dnssec_secure
, n_dnssec_insecure
, n_dnssec_bogus
, n_dnssec_indeterminate
;
774 int r
, dnssec_supported
;
778 r
= sd_bus_get_property_trivial(bus
,
779 "org.freedesktop.resolve1",
780 "/org/freedesktop/resolve1",
781 "org.freedesktop.resolve1.Manager",
787 return log_error_errno(r
, "Failed to get DNSSEC supported state: %s", bus_error_message(&error
, r
));
789 printf("DNSSEC supported by current servers: %s%s%s\n\n",
791 yes_no(dnssec_supported
),
794 r
= sd_bus_get_property(bus
,
795 "org.freedesktop.resolve1",
796 "/org/freedesktop/resolve1",
797 "org.freedesktop.resolve1.Manager",
798 "TransactionStatistics",
803 return log_error_errno(r
, "Failed to get transaction statistics: %s", bus_error_message(&error
, r
));
805 r
= sd_bus_message_read(reply
, "(tt)",
806 &n_current_transactions
,
807 &n_total_transactions
);
809 return bus_log_parse_error(r
);
811 printf("%sTransactions%s\n"
812 "Current Transactions: %" PRIu64
"\n"
813 " Total Transactions: %" PRIu64
"\n",
816 n_current_transactions
,
817 n_total_transactions
);
819 reply
= sd_bus_message_unref(reply
);
821 r
= sd_bus_get_property(bus
,
822 "org.freedesktop.resolve1",
823 "/org/freedesktop/resolve1",
824 "org.freedesktop.resolve1.Manager",
830 return log_error_errno(r
, "Failed to get cache statistics: %s", bus_error_message(&error
, r
));
832 r
= sd_bus_message_read(reply
, "(ttt)",
837 return bus_log_parse_error(r
);
839 printf("\n%sCache%s\n"
840 " Current Cache Size: %" PRIu64
"\n"
841 " Cache Hits: %" PRIu64
"\n"
842 " Cache Misses: %" PRIu64
"\n",
849 reply
= sd_bus_message_unref(reply
);
851 r
= sd_bus_get_property(bus
,
852 "org.freedesktop.resolve1",
853 "/org/freedesktop/resolve1",
854 "org.freedesktop.resolve1.Manager",
860 return log_error_errno(r
, "Failed to get DNSSEC statistics: %s", bus_error_message(&error
, r
));
862 r
= sd_bus_message_read(reply
, "(tttt)",
866 &n_dnssec_indeterminate
);
868 return bus_log_parse_error(r
);
870 printf("\n%sDNSSEC Verdicts%s\n"
871 " Secure: %" PRIu64
"\n"
872 " Insecure: %" PRIu64
"\n"
873 " Bogus: %" PRIu64
"\n"
874 " Indeterminate: %" PRIu64
"\n",
880 n_dnssec_indeterminate
);
885 static int reset_statistics(sd_bus
*bus
) {
886 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
889 r
= sd_bus_call_method(bus
,
890 "org.freedesktop.resolve1",
891 "/org/freedesktop/resolve1",
892 "org.freedesktop.resolve1.Manager",
898 return log_error_errno(r
, "Failed to reset statistics: %s", bus_error_message(&error
, r
));
903 static void help_dns_types(void) {
908 puts("Known DNS RR types:");
909 for (i
= 0; i
< _DNS_TYPE_MAX
; i
++) {
910 t
= dns_type_to_string(i
);
916 static void help_dns_classes(void) {
921 puts("Known DNS RR classes:");
922 for (i
= 0; i
< _DNS_CLASS_MAX
; i
++) {
923 t
= dns_class_to_string(i
);
929 static void help(void) {
930 printf("%s [OPTIONS...] NAME...\n"
931 "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
932 "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
933 " -h --help Show this help\n"
934 " --version Show package version\n"
935 " -4 Resolve IPv4 addresses\n"
936 " -6 Resolve IPv6 addresses\n"
937 " -i --interface=INTERFACE Look on interface\n"
938 " -p --protocol=PROTOCOL Look via protocol\n"
939 " -t --type=TYPE Query RR with DNS type\n"
940 " -c --class=CLASS Query RR with DNS class\n"
941 " --service Resolve service (SRV)\n"
942 " --service-address=BOOL Do [not] resolve address for services\n"
943 " --service-txt=BOOL Do [not] resolve TXT records for services\n"
944 " --cname=BOOL Do [not] follow CNAME redirects\n"
945 " --search=BOOL Do [not] use search domains\n"
946 " --legend=BOOL Do [not] print column headers and meta information\n"
947 " --statistics Show resolver statistics\n"
948 " --reset-statistics Reset resolver statistics\n"
949 , program_invocation_short_name
, program_invocation_short_name
);
952 static int parse_argv(int argc
, char *argv
[]) {
962 ARG_RESET_STATISTICS
,
965 static const struct option options
[] = {
966 { "help", no_argument
, NULL
, 'h' },
967 { "version", no_argument
, NULL
, ARG_VERSION
},
968 { "type", required_argument
, NULL
, 't' },
969 { "class", required_argument
, NULL
, 'c' },
970 { "legend", required_argument
, NULL
, ARG_LEGEND
},
971 { "interface", required_argument
, NULL
, 'i' },
972 { "protocol", required_argument
, NULL
, 'p' },
973 { "cname", required_argument
, NULL
, ARG_CNAME
},
974 { "service", no_argument
, NULL
, ARG_SERVICE
},
975 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
976 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
977 { "search", required_argument
, NULL
, ARG_SEARCH
},
978 { "statistics", no_argument
, NULL
, ARG_STATISTICS
, },
979 { "reset-statistics", no_argument
, NULL
, ARG_RESET_STATISTICS
},
988 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:", options
, NULL
)) >= 0)
993 return 0; /* done */;
999 arg_family
= AF_INET
;
1003 arg_family
= AF_INET6
;
1009 if (parse_ifindex(optarg
, &ifi
) >= 0)
1012 ifi
= if_nametoindex(optarg
);
1014 return log_error_errno(errno
, "Unknown interface %s: %m", optarg
);
1023 if (streq(optarg
, "help")) {
1028 r
= dns_type_from_string(optarg
);
1030 log_error("Failed to parse RR record type %s", optarg
);
1033 arg_type
= (uint16_t) r
;
1034 assert((int) arg_type
== r
);
1036 arg_mode
= MODE_RESOLVE_RECORD
;
1040 if (streq(optarg
, "help")) {
1045 r
= dns_class_from_string(optarg
);
1047 log_error("Failed to parse RR record class %s", optarg
);
1050 arg_class
= (uint16_t) r
;
1051 assert((int) arg_class
== r
);
1056 r
= parse_boolean(optarg
);
1058 return log_error_errno(r
, "Failed to parse --legend= argument");
1064 if (streq(optarg
, "dns"))
1065 arg_flags
|= SD_RESOLVED_DNS
;
1066 else if (streq(optarg
, "llmnr"))
1067 arg_flags
|= SD_RESOLVED_LLMNR
;
1068 else if (streq(optarg
, "llmnr-ipv4"))
1069 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
1070 else if (streq(optarg
, "llmnr-ipv6"))
1071 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
1073 log_error("Unknown protocol specifier: %s", optarg
);
1080 arg_mode
= MODE_RESOLVE_SERVICE
;
1084 r
= parse_boolean(optarg
);
1086 return log_error_errno(r
, "Failed to parse --cname= argument.");
1088 arg_flags
|= SD_RESOLVED_NO_CNAME
;
1090 arg_flags
&= ~SD_RESOLVED_NO_CNAME
;
1093 case ARG_SERVICE_ADDRESS
:
1094 r
= parse_boolean(optarg
);
1096 return log_error_errno(r
, "Failed to parse --service-address= argument.");
1098 arg_flags
|= SD_RESOLVED_NO_ADDRESS
;
1100 arg_flags
&= ~SD_RESOLVED_NO_ADDRESS
;
1103 case ARG_SERVICE_TXT
:
1104 r
= parse_boolean(optarg
);
1106 return log_error_errno(r
, "Failed to parse --service-txt= argument.");
1108 arg_flags
|= SD_RESOLVED_NO_TXT
;
1110 arg_flags
&= ~SD_RESOLVED_NO_TXT
;
1114 r
= parse_boolean(optarg
);
1116 return log_error_errno(r
, "Failed to parse --search argument.");
1118 arg_flags
|= SD_RESOLVED_NO_SEARCH
;
1120 arg_flags
&= ~SD_RESOLVED_NO_SEARCH
;
1123 case ARG_STATISTICS
:
1124 arg_mode
= MODE_STATISTICS
;
1127 case ARG_RESET_STATISTICS
:
1128 arg_mode
= MODE_RESET_STATISTICS
;
1135 assert_not_reached("Unhandled option");
1138 if (arg_type
== 0 && arg_class
!= 0) {
1139 log_error("--class= may only be used in conjunction with --type=.");
1143 if (arg_type
!= 0 && arg_mode
!= MODE_RESOLVE_RECORD
) {
1144 log_error("--service and --type= may not be combined.");
1148 if (arg_type
!= 0 && arg_class
== 0)
1149 arg_class
= DNS_CLASS_IN
;
1151 if (arg_class
!= 0 && arg_type
== 0)
1152 arg_type
= DNS_TYPE_A
;
1154 return 1 /* work to do */;
1157 int main(int argc
, char **argv
) {
1158 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1161 log_parse_environment();
1164 r
= parse_argv(argc
, argv
);
1168 r
= sd_bus_open_system(&bus
);
1170 log_error_errno(r
, "sd_bus_open_system: %m");
1176 case MODE_RESOLVE_HOST
:
1177 if (optind
>= argc
) {
1178 log_error("No arguments passed.");
1183 while (argv
[optind
]) {
1184 int family
, ifindex
, k
;
1185 union in_addr_union a
;
1187 if (startswith(argv
[optind
], "dns:"))
1188 k
= resolve_rfc4501(bus
, argv
[optind
]);
1190 k
= parse_address(argv
[optind
], &family
, &a
, &ifindex
);
1192 k
= resolve_address(bus
, family
, &a
, ifindex
);
1194 k
= resolve_host(bus
, argv
[optind
]);
1204 case MODE_RESOLVE_RECORD
:
1205 if (optind
>= argc
) {
1206 log_error("No arguments passed.");
1211 while (argv
[optind
]) {
1214 k
= resolve_record(bus
, argv
[optind
], arg_class
, arg_type
);
1222 case MODE_RESOLVE_SERVICE
:
1223 if (argc
< optind
+ 1) {
1224 log_error("Domain specification required.");
1228 } else if (argc
== optind
+ 1)
1229 r
= resolve_service(bus
, NULL
, NULL
, argv
[optind
]);
1230 else if (argc
== optind
+ 2)
1231 r
= resolve_service(bus
, NULL
, argv
[optind
], argv
[optind
+1]);
1232 else if (argc
== optind
+ 3)
1233 r
= resolve_service(bus
, argv
[optind
], argv
[optind
+1], argv
[optind
+2]);
1235 log_error("Too many arguments.");
1242 case MODE_STATISTICS
:
1243 if (argc
> optind
) {
1244 log_error("Too many arguments.");
1249 r
= show_statistics(bus
);
1252 case MODE_RESET_STATISTICS
:
1253 if (argc
> optind
) {
1254 log_error("Too many arguments.");
1259 r
= reset_statistics(bus
);
1264 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;