]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolve-tool.c
Two CODING_STYLE additions
[thirdparty/systemd.git] / src / resolve / resolve-tool.c
CommitLineData
bdef7319
ZJS
1/***
2 This file is part of systemd.
3
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
5
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.
10
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.
15
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/>.
18***/
19
bdef7319 20#include <getopt.h>
cf0fbc49 21#include <net/if.h>
bdef7319
ZJS
22
23#include "sd-bus.h"
3f6fd1ba
LP
24
25#include "af-list.h"
b5efdb8a 26#include "alloc-util.h"
bdef7319 27#include "bus-error.h"
3f6fd1ba 28#include "bus-util.h"
45ec7efb 29#include "escape.h"
bdef7319 30#include "in-addr-util.h"
4ac2ca1b 31#include "gcrypt-util.h"
6bedfcbb 32#include "parse-util.h"
51323288 33#include "resolved-def.h"
3f6fd1ba 34#include "resolved-dns-packet.h"
a150ff5e 35#include "terminal-util.h"
2d4c5cbc 36
bdef7319
ZJS
37#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
38
39static int arg_family = AF_UNSPEC;
40static int arg_ifindex = 0;
4b548ef3 41static uint16_t arg_type = 0;
2d4c5cbc 42static uint16_t arg_class = 0;
b93312f5 43static bool arg_legend = true;
51323288 44static uint64_t arg_flags = 0;
dab48ea6 45
82d1d240
ZJS
46typedef enum ServiceFamily {
47 SERVICE_FAMILY_TCP,
48 SERVICE_FAMILY_UDP,
49 SERVICE_FAMILY_SCTP,
50 _SERVICE_FAMILY_INVALID = -1,
51} ServiceFamily;
52static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
53
dab48ea6
ZJS
54typedef enum RawType {
55 RAW_NONE,
56 RAW_PAYLOAD,
57 RAW_PACKET,
58} RawType;
dab48ea6 59static RawType arg_raw = RAW_NONE;
a150ff5e
LP
60
61static enum {
62 MODE_RESOLVE_HOST,
63 MODE_RESOLVE_RECORD,
64 MODE_RESOLVE_SERVICE,
4ac2ca1b 65 MODE_RESOLVE_OPENPGP,
82d1d240 66 MODE_RESOLVE_TLSA,
a150ff5e
LP
67 MODE_STATISTICS,
68 MODE_RESET_STATISTICS,
69} arg_mode = MODE_RESOLVE_HOST;
51323288 70
82d1d240
ZJS
71static ServiceFamily service_family_from_string(const char *s) {
72 if (s == NULL || streq(s, "tcp"))
73 return SERVICE_FAMILY_TCP;
74 if (streq(s, "udp"))
75 return SERVICE_FAMILY_UDP;
76 if (streq(s, "sctp"))
77 return SERVICE_FAMILY_SCTP;
78 return _SERVICE_FAMILY_INVALID;
79}
80
81static const char* service_family_to_string(ServiceFamily service) {
82 switch(service) {
83 case SERVICE_FAMILY_TCP:
84 return "_tcp";
85 case SERVICE_FAMILY_UDP:
86 return "_udp";
87 case SERVICE_FAMILY_SCTP:
88 return "_sctp";
89 default:
90 assert_not_reached("invalid service");
91 }
92}
93
78c6a153 94static void print_source(uint64_t flags, usec_t rtt) {
74998408 95 char rtt_str[FORMAT_TIMESTAMP_MAX];
51323288
LP
96
97 if (!arg_legend)
98 return;
99
78c6a153 100 if (flags == 0)
51323288
LP
101 return;
102
103 fputs("\n-- Information acquired via", stdout);
104
105 if (flags != 0)
786c8e9f 106 printf(" protocol%s%s%s%s%s",
51323288
LP
107 flags & SD_RESOLVED_DNS ? " DNS" :"",
108 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
786c8e9f
LP
109 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
110 flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "",
111 flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : "");
51323288 112
74998408
TG
113 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
114
115 printf(" in %s", rtt_str);
116
51323288
LP
117 fputc('.', stdout);
118 fputc('\n', stdout);
931851e8
LP
119
120 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
51323288 121}
bdef7319 122
79266746 123static int resolve_host(sd_bus *bus, const char *name) {
bdef7319 124
4afd3348
LP
125 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
126 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 127 const char *canonical = NULL;
78c6a153 128 char ifname[IF_NAMESIZE] = "";
bdef7319 129 unsigned c = 0;
78c6a153 130 int r;
51323288 131 uint64_t flags;
74998408 132 usec_t ts;
bdef7319
ZJS
133
134 assert(name);
135
78c6a153
LP
136 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
137 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
138
139 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
bdef7319
ZJS
140
141 r = sd_bus_message_new_method_call(
142 bus,
143 &req,
144 "org.freedesktop.resolve1",
145 "/org/freedesktop/resolve1",
146 "org.freedesktop.resolve1.Manager",
147 "ResolveHostname");
02dd6e18
LP
148 if (r < 0)
149 return bus_log_create_error(r);
bdef7319 150
51323288 151 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
152 if (r < 0)
153 return bus_log_create_error(r);
bdef7319 154
74998408
TG
155 ts = now(CLOCK_MONOTONIC);
156
bdef7319 157 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
158 if (r < 0)
159 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 160
74998408
TG
161 ts = now(CLOCK_MONOTONIC) - ts;
162
78c6a153 163 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
164 if (r < 0)
165 return bus_log_parse_error(r);
bdef7319 166
78c6a153 167 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 168 _cleanup_free_ char *pretty = NULL;
78c6a153 169 int ifindex, family;
45ec7efb
LP
170 const void *a;
171 size_t sz;
78c6a153
LP
172
173 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 174
78c6a153 175 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
02dd6e18
LP
176 if (r < 0)
177 return bus_log_parse_error(r);
bdef7319
ZJS
178
179 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
02dd6e18
LP
180 if (r < 0)
181 return bus_log_parse_error(r);
bdef7319 182
bdef7319 183 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
184 if (r < 0)
185 return bus_log_parse_error(r);
bdef7319 186
79266746 187 if (!IN_SET(family, AF_INET, AF_INET6)) {
be636413 188 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
bdef7319
ZJS
189 continue;
190 }
191
192 if (sz != FAMILY_ADDRESS_SIZE(family)) {
78c6a153 193 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
45ec7efb 194 return -EINVAL;
bdef7319
ZJS
195 }
196
78c6a153
LP
197 ifname[0] = 0;
198 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
199 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
bdef7319 200
bdef7319 201 r = in_addr_to_string(family, a, &pretty);
78c6a153
LP
202 if (r < 0)
203 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 204
79266746
LP
205 printf("%*s%s %s%s%s\n",
206 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
207 pretty,
208 isempty(ifname) ? "" : "%", ifname);
bdef7319
ZJS
209
210 c++;
211 }
79266746
LP
212 if (r < 0)
213 return bus_log_parse_error(r);
214
215 r = sd_bus_message_exit_container(reply);
216 if (r < 0)
217 return bus_log_parse_error(r);
218
51323288 219 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
220 if (r < 0)
221 return bus_log_parse_error(r);
222
ece174c5 223 if (!streq(name, canonical))
79266746
LP
224 printf("%*s%s (%s)\n",
225 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
226 canonical);
bdef7319
ZJS
227
228 if (c == 0) {
229 log_error("%s: no addresses found", name);
79266746
LP
230 return -ESRCH;
231 }
232
78c6a153 233 print_source(flags, ts);
51323288 234
79266746
LP
235 return 0;
236}
237
238static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
4afd3348
LP
239 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
240 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746
LP
241 _cleanup_free_ char *pretty = NULL;
242 char ifname[IF_NAMESIZE] = "";
51323288 243 uint64_t flags;
79266746 244 unsigned c = 0;
74998408 245 usec_t ts;
79266746
LP
246 int r;
247
248 assert(bus);
249 assert(IN_SET(family, AF_INET, AF_INET6));
250 assert(address);
251
78c6a153
LP
252 if (ifindex <= 0)
253 ifindex = arg_ifindex;
254
79266746
LP
255 r = in_addr_to_string(family, address, &pretty);
256 if (r < 0)
257 return log_oom();
258
78c6a153
LP
259 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
260 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
79266746
LP
261
262 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
263
264 r = sd_bus_message_new_method_call(
265 bus,
266 &req,
267 "org.freedesktop.resolve1",
268 "/org/freedesktop/resolve1",
269 "org.freedesktop.resolve1.Manager",
270 "ResolveAddress");
271 if (r < 0)
272 return bus_log_create_error(r);
273
51323288 274 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
275 if (r < 0)
276 return bus_log_create_error(r);
277
278 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
279 if (r < 0)
280 return bus_log_create_error(r);
281
51323288 282 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
283 if (r < 0)
284 return bus_log_create_error(r);
285
74998408
TG
286 ts = now(CLOCK_MONOTONIC);
287
79266746
LP
288 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
289 if (r < 0) {
290 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
291 return r;
292 }
293
74998408
TG
294 ts = now(CLOCK_MONOTONIC) - ts;
295
78c6a153 296 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
297 if (r < 0)
298 return bus_log_create_error(r);
299
78c6a153
LP
300 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
301 const char *n;
302
303 assert_cc(sizeof(int) == sizeof(int32_t));
79266746 304
78c6a153
LP
305 r = sd_bus_message_read(reply, "is", &ifindex, &n);
306 if (r < 0)
307 return r;
308
309 r = sd_bus_message_exit_container(reply);
310 if (r < 0)
311 return r;
312
313 ifname[0] = 0;
314 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
315 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
316
317 printf("%*s%*s%*s%s %s\n",
79266746 318 (int) strlen(pretty), c == 0 ? pretty : "",
78c6a153
LP
319 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
320 (int) strlen(ifname), c == 0 ? ifname : "",
79266746
LP
321 c == 0 ? ":" : " ",
322 n);
323
324 c++;
bdef7319 325 }
79266746
LP
326 if (r < 0)
327 return bus_log_parse_error(r);
bdef7319 328
02dd6e18
LP
329 r = sd_bus_message_exit_container(reply);
330 if (r < 0)
331 return bus_log_parse_error(r);
332
51323288
LP
333 r = sd_bus_message_read(reply, "t", &flags);
334 if (r < 0)
335 return bus_log_parse_error(r);
336
79266746
LP
337 if (c == 0) {
338 log_error("%s: no names found", pretty);
339 return -ESRCH;
340 }
341
78c6a153 342 print_source(flags, ts);
51323288 343
79266746
LP
344 return 0;
345}
346
347static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) {
348 const char *percent, *a;
349 int ifi = 0;
350 int r;
351
352 percent = strchr(s, '%');
353 if (percent) {
6ad623a3 354 if (parse_ifindex(percent+1, &ifi) < 0) {
79266746
LP
355 ifi = if_nametoindex(percent+1);
356 if (ifi <= 0)
357 return -EINVAL;
358 }
359
360 a = strndupa(s, percent - s);
361 } else
362 a = s;
363
364 r = in_addr_from_string_auto(a, family, address);
365 if (r < 0)
366 return r;
367
368 *ifindex = ifi;
02dd6e18 369 return 0;
bdef7319
ZJS
370}
371
dab48ea6
ZJS
372static int output_rr_packet(const void *d, size_t l, int ifindex) {
373 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
374 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
375 int r;
376 char ifname[IF_NAMESIZE] = "";
377
378 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
379 if (r < 0)
380 return log_oom();
381
382 p->refuse_compression = true;
383
384 r = dns_packet_append_blob(p, d, l, NULL);
385 if (r < 0)
386 return log_oom();
387
388 r = dns_packet_read_rr(p, &rr, NULL, NULL);
389 if (r < 0)
390 return log_error_errno(r, "Failed to parse RR: %m");
391
392 if (arg_raw == RAW_PAYLOAD) {
393 void *data;
394 ssize_t k;
395
396 k = dns_resource_record_payload(rr, &data);
397 if (k < 0)
398 return log_error_errno(k, "Cannot dump RR: %m");
399 fwrite(data, 1, k, stdout);
400 } else {
401 const char *s;
402
403 s = dns_resource_record_to_string(rr);
404 if (!s)
405 return log_oom();
406
407 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
408 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
409
410 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
411 }
412
413 return 0;
414}
415
c1dafe4f 416static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
4afd3348
LP
417 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
418 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
78c6a153 419 char ifname[IF_NAMESIZE] = "";
2d4c5cbc 420 unsigned n = 0;
51323288 421 uint64_t flags;
78c6a153 422 int r;
74998408 423 usec_t ts;
41815a4a 424 bool needs_authentication = false;
2d4c5cbc
LP
425
426 assert(name);
427
78c6a153
LP
428 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
429 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
430
c1dafe4f 431 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
2d4c5cbc
LP
432
433 r = sd_bus_message_new_method_call(
434 bus,
435 &req,
436 "org.freedesktop.resolve1",
437 "/org/freedesktop/resolve1",
438 "org.freedesktop.resolve1.Manager",
439 "ResolveRecord");
440 if (r < 0)
441 return bus_log_create_error(r);
442
c1dafe4f 443 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2d4c5cbc
LP
444 if (r < 0)
445 return bus_log_create_error(r);
446
74998408
TG
447 ts = now(CLOCK_MONOTONIC);
448
2d4c5cbc
LP
449 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
450 if (r < 0) {
451 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
452 return r;
453 }
454
74998408
TG
455 ts = now(CLOCK_MONOTONIC) - ts;
456
78c6a153 457 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
458 if (r < 0)
459 return bus_log_parse_error(r);
460
78c6a153 461 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc 462 uint16_t c, t;
78c6a153 463 int ifindex;
2d4c5cbc
LP
464 const void *d;
465 size_t l;
466
78c6a153
LP
467 assert_cc(sizeof(int) == sizeof(int32_t));
468
469 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
470 if (r < 0)
471 return bus_log_parse_error(r);
472
473 r = sd_bus_message_read_array(reply, 'y', &d, &l);
474 if (r < 0)
475 return bus_log_parse_error(r);
476
477 r = sd_bus_message_exit_container(reply);
478 if (r < 0)
479 return bus_log_parse_error(r);
480
dab48ea6
ZJS
481 if (arg_raw == RAW_PACKET) {
482 uint64_t u64 = htole64(l);
2d4c5cbc 483
dab48ea6
ZJS
484 fwrite(&u64, sizeof(u64), 1, stdout);
485 fwrite(d, 1, l, stdout);
2e74028a 486 } else {
dab48ea6
ZJS
487 r = output_rr_packet(d, l, ifindex);
488 if (r < 0)
489 return r;
2e74028a 490 }
78c6a153 491
41815a4a
LP
492 if (dns_type_needs_authentication(t))
493 needs_authentication = true;
494
2d4c5cbc
LP
495 n++;
496 }
497 if (r < 0)
498 return bus_log_parse_error(r);
499
500 r = sd_bus_message_exit_container(reply);
501 if (r < 0)
502 return bus_log_parse_error(r);
503
51323288
LP
504 r = sd_bus_message_read(reply, "t", &flags);
505 if (r < 0)
506 return bus_log_parse_error(r);
507
2d4c5cbc
LP
508 if (n == 0) {
509 log_error("%s: no records found", name);
510 return -ESRCH;
511 }
512
78c6a153 513 print_source(flags, ts);
51323288 514
41815a4a
LP
515 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
516 fflush(stdout);
517
518 fprintf(stderr, "\n%s"
519 "WARNING: The resources shown contain cryptographic key data which could not be\n"
520 " authenticated. It is not suitable to authenticate any communication.\n"
521 " This is usually indication that DNSSEC authentication was not enabled\n"
522 " or is not available for the selected protocol or DNS servers.%s\n",
523 ansi_highlight_red(),
524 ansi_normal());
525 }
526
2d4c5cbc
LP
527 return 0;
528}
529
c1dafe4f
LP
530static int resolve_rfc4501(sd_bus *bus, const char *name) {
531 uint16_t type = 0, class = 0;
532 const char *p, *q, *n;
533 int r;
534
535 assert(bus);
536 assert(name);
537 assert(startswith(name, "dns:"));
538
539 /* Parse RFC 4501 dns: URIs */
540
541 p = name + 4;
542
543 if (p[0] == '/') {
544 const char *e;
545
546 if (p[1] != '/')
547 goto invalid;
548
549 e = strchr(p + 2, '/');
550 if (!e)
551 goto invalid;
552
553 if (e != p + 2)
554 log_warning("DNS authority specification not supported; ignoring specified authority.");
555
556 p = e + 1;
557 }
558
559 q = strchr(p, '?');
560 if (q) {
561 n = strndupa(p, q - p);
562 q++;
563
564 for (;;) {
565 const char *f;
566
567 f = startswith_no_case(q, "class=");
568 if (f) {
569 _cleanup_free_ char *t = NULL;
570 const char *e;
571
572 if (class != 0) {
573 log_error("DNS class specified twice.");
574 return -EINVAL;
575 }
576
577 e = strchrnul(f, ';');
578 t = strndup(f, e - f);
579 if (!t)
580 return log_oom();
581
582 r = dns_class_from_string(t);
583 if (r < 0) {
584 log_error("Unknown DNS class %s.", t);
585 return -EINVAL;
586 }
587
588 class = r;
589
590 if (*e == ';') {
591 q = e + 1;
592 continue;
593 }
594
595 break;
596 }
597
598 f = startswith_no_case(q, "type=");
599 if (f) {
600 _cleanup_free_ char *t = NULL;
601 const char *e;
602
603 if (type != 0) {
604 log_error("DNS type specified twice.");
605 return -EINVAL;
606 }
607
608 e = strchrnul(f, ';');
609 t = strndup(f, e - f);
610 if (!t)
611 return log_oom();
612
613 r = dns_type_from_string(t);
614 if (r < 0) {
615 log_error("Unknown DNS type %s.", t);
616 return -EINVAL;
617 }
618
619 type = r;
620
621 if (*e == ';') {
622 q = e + 1;
623 continue;
624 }
625
626 break;
627 }
628
629 goto invalid;
630 }
631 } else
632 n = p;
633
c1dafe4f 634 if (class == 0)
4ac2ca1b
ZJS
635 class = arg_class ?: DNS_CLASS_IN;
636 if (type == 0)
637 type = arg_type ?: DNS_TYPE_A;
c1dafe4f
LP
638
639 return resolve_record(bus, n, class, type);
640
641invalid:
642 log_error("Invalid DNS URI: %s", name);
643 return -EINVAL;
644}
645
45ec7efb
LP
646static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
647 const char *canonical_name, *canonical_type, *canonical_domain;
4afd3348
LP
648 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
649 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
45ec7efb
LP
650 char ifname[IF_NAMESIZE] = "";
651 size_t indent, sz;
652 uint64_t flags;
653 const char *p;
654 unsigned c;
655 usec_t ts;
656 int r;
657
658 assert(bus);
659 assert(domain);
660
3c6f7c34
LP
661 name = empty_to_null(name);
662 type = empty_to_null(type);
45ec7efb
LP
663
664 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
665 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
666
667 if (name)
668 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);
669 else if (type)
670 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
671 else
672 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
673
674 r = sd_bus_message_new_method_call(
675 bus,
676 &req,
677 "org.freedesktop.resolve1",
678 "/org/freedesktop/resolve1",
679 "org.freedesktop.resolve1.Manager",
680 "ResolveService");
681 if (r < 0)
682 return bus_log_create_error(r);
683
684 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
685 if (r < 0)
686 return bus_log_create_error(r);
687
688 ts = now(CLOCK_MONOTONIC);
689
690 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
691 if (r < 0)
692 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
693
694 ts = now(CLOCK_MONOTONIC) - ts;
695
696 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
697 if (r < 0)
698 return bus_log_parse_error(r);
699
700 indent =
701 (name ? strlen(name) + 1 : 0) +
702 (type ? strlen(type) + 1 : 0) +
703 strlen(domain) + 2;
704
705 c = 0;
706 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
707 uint16_t priority, weight, port;
708 const char *hostname, *canonical;
709
710 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
711 if (r < 0)
712 return bus_log_parse_error(r);
713
714 if (name)
715 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
716 if (type)
717 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
718
719 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
720 (int) strlen(domain), c == 0 ? domain : "",
721 c == 0 ? ":" : " ",
722 hostname, port,
723 priority, weight);
724
725 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
726 if (r < 0)
727 return bus_log_parse_error(r);
728
729 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
730 _cleanup_free_ char *pretty = NULL;
731 int ifindex, family;
732 const void *a;
733
734 assert_cc(sizeof(int) == sizeof(int32_t));
735
736 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
737 if (r < 0)
738 return bus_log_parse_error(r);
739
740 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
741 if (r < 0)
742 return bus_log_parse_error(r);
743
744 r = sd_bus_message_exit_container(reply);
745 if (r < 0)
746 return bus_log_parse_error(r);
747
748 if (!IN_SET(family, AF_INET, AF_INET6)) {
749 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
750 continue;
751 }
752
753 if (sz != FAMILY_ADDRESS_SIZE(family)) {
754 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
755 return -EINVAL;
756 }
757
758 ifname[0] = 0;
759 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
760 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
761
762 r = in_addr_to_string(family, a, &pretty);
763 if (r < 0)
764 return log_error_errno(r, "Failed to print address for %s: %m", name);
765
766 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
767 }
768 if (r < 0)
769 return bus_log_parse_error(r);
770
771 r = sd_bus_message_exit_container(reply);
772 if (r < 0)
773 return bus_log_parse_error(r);
774
775 r = sd_bus_message_read(reply, "s", &canonical);
776 if (r < 0)
777 return bus_log_parse_error(r);
778
779 if (!streq(hostname, canonical))
780 printf("%*s(%s)\n", (int) indent, "", canonical);
781
782 r = sd_bus_message_exit_container(reply);
783 if (r < 0)
784 return bus_log_parse_error(r);
785
786 c++;
787 }
788 if (r < 0)
789 return bus_log_parse_error(r);
790
791 r = sd_bus_message_exit_container(reply);
792 if (r < 0)
793 return bus_log_parse_error(r);
794
795 r = sd_bus_message_enter_container(reply, 'a', "ay");
796 if (r < 0)
797 return bus_log_parse_error(r);
798
799 c = 0;
800 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
801 _cleanup_free_ char *escaped = NULL;
802
803 escaped = cescape_length(p, sz);
804 if (!escaped)
805 return log_oom();
806
807 printf("%*s%s\n", (int) indent, "", escaped);
808 c++;
809 }
810 if (r < 0)
811 return bus_log_parse_error(r);
812
813 r = sd_bus_message_exit_container(reply);
814 if (r < 0)
815 return bus_log_parse_error(r);
816
817 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
818 if (r < 0)
819 return bus_log_parse_error(r);
820
3c6f7c34
LP
821 canonical_name = empty_to_null(canonical_name);
822 canonical_type = empty_to_null(canonical_type);
45ec7efb
LP
823
824 if (!streq_ptr(name, canonical_name) ||
825 !streq_ptr(type, canonical_type) ||
826 !streq_ptr(domain, canonical_domain)) {
827
828 printf("%*s(", (int) indent, "");
829
830 if (canonical_name)
831 printf("%s/", canonical_name);
832 if (canonical_type)
833 printf("%s/", canonical_type);
834
835 printf("%s)\n", canonical_domain);
836 }
837
838 print_source(flags, ts);
839
840 return 0;
841}
842
4ac2ca1b
ZJS
843static int resolve_openpgp(sd_bus *bus, const char *address) {
844 const char *domain, *full;
845 int r;
846 _cleanup_free_ char *hashed = NULL;
847
848 assert(bus);
849 assert(address);
850
851 domain = strrchr(address, '@');
852 if (!domain) {
853 log_error("Address does not contain '@': \"%s\"", address);
854 return -EINVAL;
855 } else if (domain == address || domain[1] == '\0') {
856 log_error("Address starts or ends with '@': \"%s\"", address);
857 return -EINVAL;
858 }
859 domain++;
860
b68f10bf 861 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
4ac2ca1b
ZJS
862 if (r < 0)
863 return log_error_errno(r, "Hashing failed: %m");
864
865 full = strjoina(hashed, "._openpgpkey.", domain);
866 log_debug("Looking up \"%s\".", full);
867
868 return resolve_record(bus, full,
869 arg_class ?: DNS_CLASS_IN,
870 arg_type ?: DNS_TYPE_OPENPGPKEY);
871}
872
82d1d240
ZJS
873static int resolve_tlsa(sd_bus *bus, const char *address) {
874 const char *port;
875 uint16_t port_num = 443;
876 _cleanup_free_ char *full = NULL;
877 int r;
878
879 assert(bus);
880 assert(address);
881
882 port = strrchr(address, ':');
883 if (port) {
884 r = safe_atou16(port + 1, &port_num);
885 if (r < 0 || port_num == 0)
886 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
887
888 address = strndupa(address, port - address);
889 }
890
891 r = asprintf(&full, "_%u.%s.%s",
892 port_num,
893 service_family_to_string(arg_service_family),
894 address);
895 if (r < 0)
896 return log_oom();
897
898 log_debug("Looking up \"%s\".", full);
899
900 return resolve_record(bus, full,
901 arg_class ?: DNS_CLASS_IN,
902 arg_type ?: DNS_TYPE_TLSA);
903}
904
a150ff5e
LP
905static int show_statistics(sd_bus *bus) {
906 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
907 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
908 uint64_t n_current_transactions, n_total_transactions,
909 cache_size, n_cache_hit, n_cache_miss,
910 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
593f665c 911 int r, dnssec_supported;
a150ff5e
LP
912
913 assert(bus);
914
593f665c
LP
915 r = sd_bus_get_property_trivial(bus,
916 "org.freedesktop.resolve1",
917 "/org/freedesktop/resolve1",
918 "org.freedesktop.resolve1.Manager",
919 "DNSSECSupported",
920 &error,
921 'b',
922 &dnssec_supported);
923 if (r < 0)
924 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
925
926 printf("DNSSEC supported by current servers: %s%s%s\n\n",
927 ansi_highlight(),
928 yes_no(dnssec_supported),
929 ansi_normal());
930
a150ff5e
LP
931 r = sd_bus_get_property(bus,
932 "org.freedesktop.resolve1",
933 "/org/freedesktop/resolve1",
934 "org.freedesktop.resolve1.Manager",
935 "TransactionStatistics",
936 &error,
937 &reply,
938 "(tt)");
939 if (r < 0)
940 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
941
942 r = sd_bus_message_read(reply, "(tt)",
943 &n_current_transactions,
944 &n_total_transactions);
945 if (r < 0)
946 return bus_log_parse_error(r);
947
948 printf("%sTransactions%s\n"
949 "Current Transactions: %" PRIu64 "\n"
950 " Total Transactions: %" PRIu64 "\n",
951 ansi_highlight(),
952 ansi_normal(),
953 n_current_transactions,
954 n_total_transactions);
955
956 reply = sd_bus_message_unref(reply);
957
958 r = sd_bus_get_property(bus,
959 "org.freedesktop.resolve1",
960 "/org/freedesktop/resolve1",
961 "org.freedesktop.resolve1.Manager",
962 "CacheStatistics",
963 &error,
964 &reply,
965 "(ttt)");
f7700834
TA
966 if (r < 0)
967 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
968
969 r = sd_bus_message_read(reply, "(ttt)",
970 &cache_size,
971 &n_cache_hit,
972 &n_cache_miss);
973 if (r < 0)
974 return bus_log_parse_error(r);
975
976 printf("\n%sCache%s\n"
977 " Current Cache Size: %" PRIu64 "\n"
978 " Cache Hits: %" PRIu64 "\n"
979 " Cache Misses: %" PRIu64 "\n",
980 ansi_highlight(),
981 ansi_normal(),
982 cache_size,
983 n_cache_hit,
984 n_cache_miss);
985
986 reply = sd_bus_message_unref(reply);
987
988 r = sd_bus_get_property(bus,
989 "org.freedesktop.resolve1",
990 "/org/freedesktop/resolve1",
991 "org.freedesktop.resolve1.Manager",
992 "DNSSECStatistics",
993 &error,
994 &reply,
995 "(tttt)");
f7700834
TA
996 if (r < 0)
997 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
998
999 r = sd_bus_message_read(reply, "(tttt)",
1000 &n_dnssec_secure,
1001 &n_dnssec_insecure,
1002 &n_dnssec_bogus,
1003 &n_dnssec_indeterminate);
1004 if (r < 0)
1005 return bus_log_parse_error(r);
1006
7405bb3e
LP
1007 printf("\n%sDNSSEC Verdicts%s\n"
1008 " Secure: %" PRIu64 "\n"
1009 " Insecure: %" PRIu64 "\n"
1010 " Bogus: %" PRIu64 "\n"
1011 " Indeterminate: %" PRIu64 "\n",
a150ff5e
LP
1012 ansi_highlight(),
1013 ansi_normal(),
1014 n_dnssec_secure,
1015 n_dnssec_insecure,
1016 n_dnssec_bogus,
1017 n_dnssec_indeterminate);
1018
1019 return 0;
1020}
1021
1022static int reset_statistics(sd_bus *bus) {
1023 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1024 int r;
1025
1026 r = sd_bus_call_method(bus,
1027 "org.freedesktop.resolve1",
1028 "/org/freedesktop/resolve1",
1029 "org.freedesktop.resolve1.Manager",
1030 "ResetStatistics",
1031 &error,
1032 NULL,
1033 NULL);
1034 if (r < 0)
1035 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1036
1037 return 0;
1038}
1039
ba82da3b
ZJS
1040static void help_protocol_types(void) {
1041 if (arg_legend)
1042 puts("Known protocol types:");
1043 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
1044}
1045
b93312f5
ZJS
1046static void help_dns_types(void) {
1047 int i;
1048 const char *t;
1049
1050 if (arg_legend)
09b1fe14 1051 puts("Known DNS RR types:");
b93312f5
ZJS
1052 for (i = 0; i < _DNS_TYPE_MAX; i++) {
1053 t = dns_type_to_string(i);
1054 if (t)
1055 puts(t);
1056 }
1057}
1058
1059static void help_dns_classes(void) {
1060 int i;
1061 const char *t;
1062
1063 if (arg_legend)
09b1fe14 1064 puts("Known DNS RR classes:");
b93312f5
ZJS
1065 for (i = 0; i < _DNS_CLASS_MAX; i++) {
1066 t = dns_class_to_string(i);
1067 if (t)
1068 puts(t);
1069 }
1070}
1071
bdef7319 1072static void help(void) {
1ace2438
ZJS
1073 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
1074 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
1075 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
1076 "%1$s [OPTIONS...] --statistics\n"
1077 "%1$s [OPTIONS...] --reset-statistics\n"
1078 "\n"
300a716d 1079 "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
1ace2438
ZJS
1080 " -h --help Show this help\n"
1081 " --version Show package version\n"
1082 " -4 Resolve IPv4 addresses\n"
1083 " -6 Resolve IPv6 addresses\n"
1084 " -i --interface=INTERFACE Look on interface\n"
1085 " -p --protocol=PROTO|help Look via protocol\n"
1086 " -t --type=TYPE|help Query RR with DNS type\n"
1087 " -c --class=CLASS|help Query RR with DNS class\n"
1088 " --service Resolve service (SRV)\n"
1089 " --service-address=BOOL Resolve address for services (default: yes)\n"
1090 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
1091 " --openpgp Query OpenPGP public key\n"
82d1d240 1092 " --tlsa Query TLS public key\n"
1ace2438
ZJS
1093 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
1094 " --search=BOOL Use search domains for single-label names\n"
1095 " (default: yes)\n"
dab48ea6 1096 " --raw[=payload|packet] Dump the answer as binary data\n"
1ace2438
ZJS
1097 " --legend=BOOL Print headers and additional info (default: yes)\n"
1098 " --statistics Show resolver statistics\n"
1099 " --reset-statistics Reset resolver statistics\n"
1100 , program_invocation_short_name);
bdef7319
ZJS
1101}
1102
1103static int parse_argv(int argc, char *argv[]) {
1104 enum {
1105 ARG_VERSION = 0x100,
dad29dff 1106 ARG_LEGEND,
45ec7efb
LP
1107 ARG_SERVICE,
1108 ARG_CNAME,
1109 ARG_SERVICE_ADDRESS,
1110 ARG_SERVICE_TXT,
4ac2ca1b 1111 ARG_OPENPGP,
82d1d240 1112 ARG_TLSA,
2e74028a 1113 ARG_RAW,
801ad6a6 1114 ARG_SEARCH,
a150ff5e
LP
1115 ARG_STATISTICS,
1116 ARG_RESET_STATISTICS,
bdef7319
ZJS
1117 };
1118
1119 static const struct option options[] = {
a150ff5e
LP
1120 { "help", no_argument, NULL, 'h' },
1121 { "version", no_argument, NULL, ARG_VERSION },
1122 { "type", required_argument, NULL, 't' },
1123 { "class", required_argument, NULL, 'c' },
1124 { "legend", required_argument, NULL, ARG_LEGEND },
5b911843 1125 { "interface", required_argument, NULL, 'i' },
a150ff5e
LP
1126 { "protocol", required_argument, NULL, 'p' },
1127 { "cname", required_argument, NULL, ARG_CNAME },
1128 { "service", no_argument, NULL, ARG_SERVICE },
1129 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
1130 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
4ac2ca1b 1131 { "openpgp", no_argument, NULL, ARG_OPENPGP },
82d1d240 1132 { "tlsa", optional_argument, NULL, ARG_TLSA },
dab48ea6 1133 { "raw", optional_argument, NULL, ARG_RAW },
a150ff5e
LP
1134 { "search", required_argument, NULL, ARG_SEARCH },
1135 { "statistics", no_argument, NULL, ARG_STATISTICS, },
1136 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
bdef7319
ZJS
1137 {}
1138 };
1139
2d4c5cbc 1140 int c, r;
bdef7319
ZJS
1141
1142 assert(argc >= 0);
1143 assert(argv);
1144
51323288 1145 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
bdef7319
ZJS
1146 switch(c) {
1147
1148 case 'h':
1149 help();
1150 return 0; /* done */;
1151
1152 case ARG_VERSION:
3f6fd1ba 1153 return version();
bdef7319
ZJS
1154
1155 case '4':
1156 arg_family = AF_INET;
1157 break;
1158
1159 case '6':
1160 arg_family = AF_INET6;
1161 break;
1162
3fa4999b
LP
1163 case 'i': {
1164 int ifi;
1165
6ad623a3 1166 if (parse_ifindex(optarg, &ifi) >= 0)
3fa4999b
LP
1167 arg_ifindex = ifi;
1168 else {
1169 ifi = if_nametoindex(optarg);
1170 if (ifi <= 0)
1171 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
1172
1173 arg_ifindex = ifi;
1174 }
1175
2d4c5cbc 1176 break;
3fa4999b 1177 }
2d4c5cbc
LP
1178
1179 case 't':
b93312f5
ZJS
1180 if (streq(optarg, "help")) {
1181 help_dns_types();
1182 return 0;
1183 }
1184
4b548ef3
LP
1185 r = dns_type_from_string(optarg);
1186 if (r < 0) {
2d4c5cbc 1187 log_error("Failed to parse RR record type %s", optarg);
4b548ef3 1188 return r;
2d4c5cbc 1189 }
4b548ef3
LP
1190 arg_type = (uint16_t) r;
1191 assert((int) arg_type == r);
b93312f5 1192
a150ff5e 1193 arg_mode = MODE_RESOLVE_RECORD;
2d4c5cbc
LP
1194 break;
1195
1196 case 'c':
b93312f5
ZJS
1197 if (streq(optarg, "help")) {
1198 help_dns_classes();
1199 return 0;
1200 }
1201
4b548ef3 1202 r = dns_class_from_string(optarg);
2d4c5cbc
LP
1203 if (r < 0) {
1204 log_error("Failed to parse RR record class %s", optarg);
1205 return r;
bdef7319 1206 }
4b548ef3
LP
1207 arg_class = (uint16_t) r;
1208 assert((int) arg_class == r);
b93312f5
ZJS
1209
1210 break;
1211
dad29dff 1212 case ARG_LEGEND:
45ec7efb
LP
1213 r = parse_boolean(optarg);
1214 if (r < 0)
1215 return log_error_errno(r, "Failed to parse --legend= argument");
1216
1217 arg_legend = r;
bdef7319
ZJS
1218 break;
1219
51323288 1220 case 'p':
ba82da3b
ZJS
1221 if (streq(optarg, "help")) {
1222 help_protocol_types();
1223 return 0;
1224 } else if (streq(optarg, "dns"))
51323288
LP
1225 arg_flags |= SD_RESOLVED_DNS;
1226 else if (streq(optarg, "llmnr"))
1227 arg_flags |= SD_RESOLVED_LLMNR;
1228 else if (streq(optarg, "llmnr-ipv4"))
1229 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
1230 else if (streq(optarg, "llmnr-ipv6"))
1231 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
1232 else {
1233 log_error("Unknown protocol specifier: %s", optarg);
1234 return -EINVAL;
1235 }
1236
1237 break;
1238
45ec7efb 1239 case ARG_SERVICE:
a150ff5e 1240 arg_mode = MODE_RESOLVE_SERVICE;
45ec7efb
LP
1241 break;
1242
4ac2ca1b
ZJS
1243 case ARG_OPENPGP:
1244 arg_mode = MODE_RESOLVE_OPENPGP;
1245 break;
1246
82d1d240
ZJS
1247 case ARG_TLSA:
1248 arg_mode = MODE_RESOLVE_TLSA;
1249 arg_service_family = service_family_from_string(optarg);
1250 if (arg_service_family < 0) {
1251 log_error("Unknown service family \"%s\".", optarg);
1252 return -EINVAL;
1253 }
1254 break;
1255
2e74028a
ZJS
1256 case ARG_RAW:
1257 if (on_tty()) {
1258 log_error("Refusing to write binary data to tty.");
1259 return -ENOTTY;
1260 }
1261
dab48ea6
ZJS
1262 if (optarg == NULL || streq(optarg, "payload"))
1263 arg_raw = RAW_PAYLOAD;
1264 else if (streq(optarg, "packet"))
1265 arg_raw = RAW_PACKET;
1266 else {
1267 log_error("Unknown --raw specifier \"%s\".", optarg);
1268 return -EINVAL;
1269 }
1270
2e74028a
ZJS
1271 arg_legend = false;
1272 break;
1273
45ec7efb
LP
1274 case ARG_CNAME:
1275 r = parse_boolean(optarg);
1276 if (r < 0)
1277 return log_error_errno(r, "Failed to parse --cname= argument.");
5883ff60 1278 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
45ec7efb
LP
1279 break;
1280
1281 case ARG_SERVICE_ADDRESS:
1282 r = parse_boolean(optarg);
1283 if (r < 0)
1284 return log_error_errno(r, "Failed to parse --service-address= argument.");
5883ff60 1285 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
45ec7efb
LP
1286 break;
1287
1288 case ARG_SERVICE_TXT:
1289 r = parse_boolean(optarg);
1290 if (r < 0)
1291 return log_error_errno(r, "Failed to parse --service-txt= argument.");
5883ff60 1292 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
45ec7efb
LP
1293 break;
1294
801ad6a6
LP
1295 case ARG_SEARCH:
1296 r = parse_boolean(optarg);
1297 if (r < 0)
1298 return log_error_errno(r, "Failed to parse --search argument.");
5883ff60 1299 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
801ad6a6
LP
1300 break;
1301
a150ff5e
LP
1302 case ARG_STATISTICS:
1303 arg_mode = MODE_STATISTICS;
1304 break;
1305
1306 case ARG_RESET_STATISTICS:
1307 arg_mode = MODE_RESET_STATISTICS;
1308 break;
1309
bdef7319
ZJS
1310 case '?':
1311 return -EINVAL;
1312
1313 default:
1314 assert_not_reached("Unhandled option");
1315 }
1316
2d4c5cbc 1317 if (arg_type == 0 && arg_class != 0) {
45ec7efb
LP
1318 log_error("--class= may only be used in conjunction with --type=.");
1319 return -EINVAL;
1320 }
1321
82d1d240 1322 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
45ec7efb 1323 log_error("--service and --type= may not be combined.");
2d4c5cbc
LP
1324 return -EINVAL;
1325 }
1326
1327 if (arg_type != 0 && arg_class == 0)
1328 arg_class = DNS_CLASS_IN;
1329
c1dafe4f
LP
1330 if (arg_class != 0 && arg_type == 0)
1331 arg_type = DNS_TYPE_A;
1332
bdef7319
ZJS
1333 return 1 /* work to do */;
1334}
1335
bdef7319 1336int main(int argc, char **argv) {
4afd3348 1337 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
bdef7319
ZJS
1338 int r;
1339
1340 log_parse_environment();
1341 log_open();
1342
1343 r = parse_argv(argc, argv);
1344 if (r <= 0)
79266746
LP
1345 goto finish;
1346
bdef7319
ZJS
1347 r = sd_bus_open_system(&bus);
1348 if (r < 0) {
da927ba9 1349 log_error_errno(r, "sd_bus_open_system: %m");
79266746 1350 goto finish;
bdef7319
ZJS
1351 }
1352
a150ff5e 1353 switch (arg_mode) {
45ec7efb 1354
a150ff5e
LP
1355 case MODE_RESOLVE_HOST:
1356 if (optind >= argc) {
300a716d 1357 log_error("No arguments passed.");
a150ff5e
LP
1358 r = -EINVAL;
1359 goto finish;
1360 }
1361
1362 while (argv[optind]) {
1363 int family, ifindex, k;
1364 union in_addr_union a;
1365
c1dafe4f
LP
1366 if (startswith(argv[optind], "dns:"))
1367 k = resolve_rfc4501(bus, argv[optind]);
1368 else {
1369 k = parse_address(argv[optind], &family, &a, &ifindex);
1370 if (k >= 0)
1371 k = resolve_address(bus, family, &a, ifindex);
1372 else
1373 k = resolve_host(bus, argv[optind]);
1374 }
a150ff5e
LP
1375
1376 if (r == 0)
1377 r = k;
1378
1379 optind++;
1380 }
1381 break;
1382
1383 case MODE_RESOLVE_RECORD:
1384 if (optind >= argc) {
300a716d 1385 log_error("No arguments passed.");
a150ff5e
LP
1386 r = -EINVAL;
1387 goto finish;
1388 }
1389
1390 while (argv[optind]) {
1391 int k;
1392
c1dafe4f 1393 k = resolve_record(bus, argv[optind], arg_class, arg_type);
a150ff5e
LP
1394 if (r == 0)
1395 r = k;
1396
1397 optind++;
1398 }
1399 break;
1400
1401 case MODE_RESOLVE_SERVICE:
45ec7efb
LP
1402 if (argc < optind + 1) {
1403 log_error("Domain specification required.");
1404 r = -EINVAL;
1405 goto finish;
1406
1407 } else if (argc == optind + 1)
1408 r = resolve_service(bus, NULL, NULL, argv[optind]);
1409 else if (argc == optind + 2)
1410 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
1411 else if (argc == optind + 3)
1412 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
1413 else {
300a716d 1414 log_error("Too many arguments.");
45ec7efb
LP
1415 r = -EINVAL;
1416 goto finish;
1417 }
1418
a150ff5e 1419 break;
79266746 1420
4ac2ca1b
ZJS
1421 case MODE_RESOLVE_OPENPGP:
1422 if (argc < optind + 1) {
1423 log_error("E-mail address required.");
1424 r = -EINVAL;
1425 goto finish;
1426
1427 }
1428
1429 r = 0;
1430 while (optind < argc) {
1431 int k;
1432
1433 k = resolve_openpgp(bus, argv[optind++]);
1434 if (k < 0)
1435 r = k;
1436 }
1437 break;
1438
82d1d240
ZJS
1439 case MODE_RESOLVE_TLSA:
1440 if (argc < optind + 1) {
1441 log_error("Domain name required.");
1442 r = -EINVAL;
1443 goto finish;
1444
1445 }
1446
1447 r = 0;
1448 while (optind < argc) {
1449 int k;
1450
1451 k = resolve_tlsa(bus, argv[optind++]);
1452 if (k < 0)
1453 r = k;
1454 }
1455 break;
1456
a150ff5e
LP
1457 case MODE_STATISTICS:
1458 if (argc > optind) {
1459 log_error("Too many arguments.");
1460 r = -EINVAL;
1461 goto finish;
2d4c5cbc 1462 }
bdef7319 1463
a150ff5e
LP
1464 r = show_statistics(bus);
1465 break;
1466
1467 case MODE_RESET_STATISTICS:
1468 if (argc > optind) {
1469 log_error("Too many arguments.");
1470 r = -EINVAL;
1471 goto finish;
1472 }
79266746 1473
a150ff5e
LP
1474 r = reset_statistics(bus);
1475 break;
bdef7319
ZJS
1476 }
1477
79266746 1478finish:
bdef7319
ZJS
1479 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1480}