]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve-host/resolve-host.c
Merge pull request #2049 from evverx/journal-test-dont-run-on-incomplete-setup
[thirdparty/systemd.git] / src / resolve-host / resolve-host.c
CommitLineData
bdef7319
ZJS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Zbigniew Jędrzejewski-Szmek
7
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.
12
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.
17
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/>.
20***/
21
bdef7319 22#include <getopt.h>
cf0fbc49 23#include <net/if.h>
bdef7319
ZJS
24
25#include "sd-bus.h"
3f6fd1ba
LP
26
27#include "af-list.h"
b5efdb8a 28#include "alloc-util.h"
bdef7319 29#include "bus-error.h"
3f6fd1ba 30#include "bus-util.h"
45ec7efb 31#include "escape.h"
bdef7319 32#include "in-addr-util.h"
6bedfcbb 33#include "parse-util.h"
51323288 34#include "resolved-def.h"
3f6fd1ba 35#include "resolved-dns-packet.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;
de292aa1 41static int arg_type = 0;
2d4c5cbc 42static uint16_t arg_class = 0;
b93312f5 43static bool arg_legend = true;
51323288 44static uint64_t arg_flags = 0;
45ec7efb 45static bool arg_resolve_service = false;
51323288 46
78c6a153 47static void print_source(uint64_t flags, usec_t rtt) {
74998408 48 char rtt_str[FORMAT_TIMESTAMP_MAX];
51323288
LP
49
50 if (!arg_legend)
51 return;
52
78c6a153 53 if (flags == 0)
51323288
LP
54 return;
55
56 fputs("\n-- Information acquired via", stdout);
57
58 if (flags != 0)
59 printf(" protocol%s%s%s",
60 flags & SD_RESOLVED_DNS ? " DNS" :"",
61 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
62 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "");
63
74998408
TG
64 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
65
66 printf(" in %s", rtt_str);
67
51323288
LP
68 fputc('.', stdout);
69 fputc('\n', stdout);
70}
bdef7319 71
79266746 72static int resolve_host(sd_bus *bus, const char *name) {
bdef7319
ZJS
73
74 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
75 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 76 const char *canonical = NULL;
78c6a153 77 char ifname[IF_NAMESIZE] = "";
bdef7319 78 unsigned c = 0;
78c6a153 79 int r;
51323288 80 uint64_t flags;
74998408 81 usec_t ts;
bdef7319
ZJS
82
83 assert(name);
84
78c6a153
LP
85 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
86 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
87
88 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
bdef7319
ZJS
89
90 r = sd_bus_message_new_method_call(
91 bus,
92 &req,
93 "org.freedesktop.resolve1",
94 "/org/freedesktop/resolve1",
95 "org.freedesktop.resolve1.Manager",
96 "ResolveHostname");
02dd6e18
LP
97 if (r < 0)
98 return bus_log_create_error(r);
bdef7319 99
51323288 100 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
101 if (r < 0)
102 return bus_log_create_error(r);
bdef7319 103
74998408
TG
104 ts = now(CLOCK_MONOTONIC);
105
bdef7319 106 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
107 if (r < 0)
108 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 109
74998408
TG
110 ts = now(CLOCK_MONOTONIC) - ts;
111
78c6a153 112 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
113 if (r < 0)
114 return bus_log_parse_error(r);
bdef7319 115
78c6a153 116 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 117 _cleanup_free_ char *pretty = NULL;
78c6a153 118 int ifindex, family;
45ec7efb
LP
119 const void *a;
120 size_t sz;
78c6a153
LP
121
122 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 123
78c6a153 124 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
02dd6e18
LP
125 if (r < 0)
126 return bus_log_parse_error(r);
bdef7319
ZJS
127
128 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
02dd6e18
LP
129 if (r < 0)
130 return bus_log_parse_error(r);
bdef7319 131
bdef7319 132 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
133 if (r < 0)
134 return bus_log_parse_error(r);
bdef7319 135
79266746 136 if (!IN_SET(family, AF_INET, AF_INET6)) {
be636413 137 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
bdef7319
ZJS
138 continue;
139 }
140
141 if (sz != FAMILY_ADDRESS_SIZE(family)) {
78c6a153 142 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
45ec7efb 143 return -EINVAL;
bdef7319
ZJS
144 }
145
78c6a153
LP
146 ifname[0] = 0;
147 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
148 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
bdef7319 149
bdef7319 150 r = in_addr_to_string(family, a, &pretty);
78c6a153
LP
151 if (r < 0)
152 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 153
79266746
LP
154 printf("%*s%s %s%s%s\n",
155 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
156 pretty,
157 isempty(ifname) ? "" : "%", ifname);
bdef7319
ZJS
158
159 c++;
160 }
79266746
LP
161 if (r < 0)
162 return bus_log_parse_error(r);
163
164 r = sd_bus_message_exit_container(reply);
165 if (r < 0)
166 return bus_log_parse_error(r);
167
51323288 168 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
169 if (r < 0)
170 return bus_log_parse_error(r);
171
ece174c5 172 if (!streq(name, canonical))
79266746
LP
173 printf("%*s%s (%s)\n",
174 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
175 canonical);
bdef7319
ZJS
176
177 if (c == 0) {
178 log_error("%s: no addresses found", name);
79266746
LP
179 return -ESRCH;
180 }
181
78c6a153 182 print_source(flags, ts);
51323288 183
79266746
LP
184 return 0;
185}
186
187static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
188 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
189 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
190 _cleanup_free_ char *pretty = NULL;
191 char ifname[IF_NAMESIZE] = "";
51323288 192 uint64_t flags;
79266746 193 unsigned c = 0;
74998408 194 usec_t ts;
79266746
LP
195 int r;
196
197 assert(bus);
198 assert(IN_SET(family, AF_INET, AF_INET6));
199 assert(address);
200
78c6a153
LP
201 if (ifindex <= 0)
202 ifindex = arg_ifindex;
203
79266746
LP
204 r = in_addr_to_string(family, address, &pretty);
205 if (r < 0)
206 return log_oom();
207
78c6a153
LP
208 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
209 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
79266746
LP
210
211 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
212
213 r = sd_bus_message_new_method_call(
214 bus,
215 &req,
216 "org.freedesktop.resolve1",
217 "/org/freedesktop/resolve1",
218 "org.freedesktop.resolve1.Manager",
219 "ResolveAddress");
220 if (r < 0)
221 return bus_log_create_error(r);
222
51323288 223 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
224 if (r < 0)
225 return bus_log_create_error(r);
226
227 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
228 if (r < 0)
229 return bus_log_create_error(r);
230
51323288 231 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
232 if (r < 0)
233 return bus_log_create_error(r);
234
74998408
TG
235 ts = now(CLOCK_MONOTONIC);
236
79266746
LP
237 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
238 if (r < 0) {
239 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
240 return r;
241 }
242
74998408
TG
243 ts = now(CLOCK_MONOTONIC) - ts;
244
78c6a153 245 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
246 if (r < 0)
247 return bus_log_create_error(r);
248
78c6a153
LP
249 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
250 const char *n;
251
252 assert_cc(sizeof(int) == sizeof(int32_t));
79266746 253
78c6a153
LP
254 r = sd_bus_message_read(reply, "is", &ifindex, &n);
255 if (r < 0)
256 return r;
257
258 r = sd_bus_message_exit_container(reply);
259 if (r < 0)
260 return r;
261
262 ifname[0] = 0;
263 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
264 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
265
266 printf("%*s%*s%*s%s %s\n",
79266746 267 (int) strlen(pretty), c == 0 ? pretty : "",
78c6a153
LP
268 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
269 (int) strlen(ifname), c == 0 ? ifname : "",
79266746
LP
270 c == 0 ? ":" : " ",
271 n);
272
273 c++;
bdef7319 274 }
79266746
LP
275 if (r < 0)
276 return bus_log_parse_error(r);
bdef7319 277
02dd6e18
LP
278 r = sd_bus_message_exit_container(reply);
279 if (r < 0)
280 return bus_log_parse_error(r);
281
51323288
LP
282 r = sd_bus_message_read(reply, "t", &flags);
283 if (r < 0)
284 return bus_log_parse_error(r);
285
79266746
LP
286 if (c == 0) {
287 log_error("%s: no names found", pretty);
288 return -ESRCH;
289 }
290
78c6a153 291 print_source(flags, ts);
51323288 292
79266746
LP
293 return 0;
294}
295
296static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) {
297 const char *percent, *a;
298 int ifi = 0;
299 int r;
300
301 percent = strchr(s, '%');
302 if (percent) {
6ad623a3 303 if (parse_ifindex(percent+1, &ifi) < 0) {
79266746
LP
304 ifi = if_nametoindex(percent+1);
305 if (ifi <= 0)
306 return -EINVAL;
307 }
308
309 a = strndupa(s, percent - s);
310 } else
311 a = s;
312
313 r = in_addr_from_string_auto(a, family, address);
314 if (r < 0)
315 return r;
316
317 *ifindex = ifi;
02dd6e18 318 return 0;
bdef7319
ZJS
319}
320
2d4c5cbc
LP
321static int resolve_record(sd_bus *bus, const char *name) {
322
323 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
78c6a153 325 char ifname[IF_NAMESIZE] = "";
2d4c5cbc 326 unsigned n = 0;
51323288 327 uint64_t flags;
78c6a153 328 int r;
74998408 329 usec_t ts;
2d4c5cbc
LP
330
331 assert(name);
332
78c6a153
LP
333 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
334 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
335
336 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type), isempty(ifname) ? "*" : ifname);
2d4c5cbc
LP
337
338 r = sd_bus_message_new_method_call(
339 bus,
340 &req,
341 "org.freedesktop.resolve1",
342 "/org/freedesktop/resolve1",
343 "org.freedesktop.resolve1.Manager",
344 "ResolveRecord");
345 if (r < 0)
346 return bus_log_create_error(r);
347
de292aa1 348 assert((uint16_t) arg_type == arg_type);
51323288 349 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, arg_flags);
2d4c5cbc
LP
350 if (r < 0)
351 return bus_log_create_error(r);
352
74998408
TG
353 ts = now(CLOCK_MONOTONIC);
354
2d4c5cbc
LP
355 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
356 if (r < 0) {
357 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
358 return r;
359 }
360
74998408
TG
361 ts = now(CLOCK_MONOTONIC) - ts;
362
78c6a153 363 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
364 if (r < 0)
365 return bus_log_parse_error(r);
366
78c6a153 367 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc
LP
368 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
369 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
370 _cleanup_free_ char *s = NULL;
371 uint16_t c, t;
78c6a153 372 int ifindex;
2d4c5cbc
LP
373 const void *d;
374 size_t l;
375
78c6a153
LP
376 assert_cc(sizeof(int) == sizeof(int32_t));
377
378 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
379 if (r < 0)
380 return bus_log_parse_error(r);
381
382 r = sd_bus_message_read_array(reply, 'y', &d, &l);
383 if (r < 0)
384 return bus_log_parse_error(r);
385
386 r = sd_bus_message_exit_container(reply);
387 if (r < 0)
388 return bus_log_parse_error(r);
389
390 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
391 if (r < 0)
392 return log_oom();
393
f6a5fec6
LP
394 p->refuse_compression = true;
395
2d4c5cbc
LP
396 r = dns_packet_append_blob(p, d, l, NULL);
397 if (r < 0)
398 return log_oom();
399
400 r = dns_packet_read_rr(p, &rr, NULL);
401 if (r < 0) {
402 log_error("Failed to parse RR.");
403 return r;
404 }
405
406 r = dns_resource_record_to_string(rr, &s);
407 if (r < 0) {
408 log_error("Failed to format RR.");
409 return r;
410 }
411
78c6a153
LP
412 ifname[0] = 0;
413 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
414 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
415
416 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
2d4c5cbc
LP
417 n++;
418 }
419 if (r < 0)
420 return bus_log_parse_error(r);
421
422 r = sd_bus_message_exit_container(reply);
423 if (r < 0)
424 return bus_log_parse_error(r);
425
51323288
LP
426 r = sd_bus_message_read(reply, "t", &flags);
427 if (r < 0)
428 return bus_log_parse_error(r);
429
2d4c5cbc
LP
430 if (n == 0) {
431 log_error("%s: no records found", name);
432 return -ESRCH;
433 }
434
78c6a153 435 print_source(flags, ts);
51323288 436
2d4c5cbc
LP
437 return 0;
438}
439
45ec7efb
LP
440static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
441 const char *canonical_name, *canonical_type, *canonical_domain;
442 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
443 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
444 char ifname[IF_NAMESIZE] = "";
445 size_t indent, sz;
446 uint64_t flags;
447 const char *p;
448 unsigned c;
449 usec_t ts;
450 int r;
451
452 assert(bus);
453 assert(domain);
454
455 if (isempty(name))
456 name = NULL;
457 if (isempty(type))
458 type = NULL;
459
460 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
461 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
462
463 if (name)
464 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);
465 else if (type)
466 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
467 else
468 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
469
470 r = sd_bus_message_new_method_call(
471 bus,
472 &req,
473 "org.freedesktop.resolve1",
474 "/org/freedesktop/resolve1",
475 "org.freedesktop.resolve1.Manager",
476 "ResolveService");
477 if (r < 0)
478 return bus_log_create_error(r);
479
480 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
481 if (r < 0)
482 return bus_log_create_error(r);
483
484 ts = now(CLOCK_MONOTONIC);
485
486 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
487 if (r < 0)
488 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
489
490 ts = now(CLOCK_MONOTONIC) - ts;
491
492 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
493 if (r < 0)
494 return bus_log_parse_error(r);
495
496 indent =
497 (name ? strlen(name) + 1 : 0) +
498 (type ? strlen(type) + 1 : 0) +
499 strlen(domain) + 2;
500
501 c = 0;
502 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
503 uint16_t priority, weight, port;
504 const char *hostname, *canonical;
505
506 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
507 if (r < 0)
508 return bus_log_parse_error(r);
509
510 if (name)
511 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
512 if (type)
513 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
514
515 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
516 (int) strlen(domain), c == 0 ? domain : "",
517 c == 0 ? ":" : " ",
518 hostname, port,
519 priority, weight);
520
521 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
522 if (r < 0)
523 return bus_log_parse_error(r);
524
525 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
526 _cleanup_free_ char *pretty = NULL;
527 int ifindex, family;
528 const void *a;
529
530 assert_cc(sizeof(int) == sizeof(int32_t));
531
532 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
533 if (r < 0)
534 return bus_log_parse_error(r);
535
536 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
537 if (r < 0)
538 return bus_log_parse_error(r);
539
540 r = sd_bus_message_exit_container(reply);
541 if (r < 0)
542 return bus_log_parse_error(r);
543
544 if (!IN_SET(family, AF_INET, AF_INET6)) {
545 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
546 continue;
547 }
548
549 if (sz != FAMILY_ADDRESS_SIZE(family)) {
550 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
551 return -EINVAL;
552 }
553
554 ifname[0] = 0;
555 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
556 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
557
558 r = in_addr_to_string(family, a, &pretty);
559 if (r < 0)
560 return log_error_errno(r, "Failed to print address for %s: %m", name);
561
562 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
563 }
564 if (r < 0)
565 return bus_log_parse_error(r);
566
567 r = sd_bus_message_exit_container(reply);
568 if (r < 0)
569 return bus_log_parse_error(r);
570
571 r = sd_bus_message_read(reply, "s", &canonical);
572 if (r < 0)
573 return bus_log_parse_error(r);
574
575 if (!streq(hostname, canonical))
576 printf("%*s(%s)\n", (int) indent, "", canonical);
577
578 r = sd_bus_message_exit_container(reply);
579 if (r < 0)
580 return bus_log_parse_error(r);
581
582 c++;
583 }
584 if (r < 0)
585 return bus_log_parse_error(r);
586
587 r = sd_bus_message_exit_container(reply);
588 if (r < 0)
589 return bus_log_parse_error(r);
590
591 r = sd_bus_message_enter_container(reply, 'a', "ay");
592 if (r < 0)
593 return bus_log_parse_error(r);
594
595 c = 0;
596 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
597 _cleanup_free_ char *escaped = NULL;
598
599 escaped = cescape_length(p, sz);
600 if (!escaped)
601 return log_oom();
602
603 printf("%*s%s\n", (int) indent, "", escaped);
604 c++;
605 }
606 if (r < 0)
607 return bus_log_parse_error(r);
608
609 r = sd_bus_message_exit_container(reply);
610 if (r < 0)
611 return bus_log_parse_error(r);
612
613 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
614 if (r < 0)
615 return bus_log_parse_error(r);
616
617 if (isempty(canonical_name))
618 canonical_name = NULL;
619 if (isempty(canonical_type))
620 canonical_type = NULL;
621
622 if (!streq_ptr(name, canonical_name) ||
623 !streq_ptr(type, canonical_type) ||
624 !streq_ptr(domain, canonical_domain)) {
625
626 printf("%*s(", (int) indent, "");
627
628 if (canonical_name)
629 printf("%s/", canonical_name);
630 if (canonical_type)
631 printf("%s/", canonical_type);
632
633 printf("%s)\n", canonical_domain);
634 }
635
636 print_source(flags, ts);
637
638 return 0;
639}
640
b93312f5
ZJS
641static void help_dns_types(void) {
642 int i;
643 const char *t;
644
645 if (arg_legend)
09b1fe14 646 puts("Known DNS RR types:");
b93312f5
ZJS
647 for (i = 0; i < _DNS_TYPE_MAX; i++) {
648 t = dns_type_to_string(i);
649 if (t)
650 puts(t);
651 }
652}
653
654static void help_dns_classes(void) {
655 int i;
656 const char *t;
657
658 if (arg_legend)
09b1fe14 659 puts("Known DNS RR classes:");
b93312f5
ZJS
660 for (i = 0; i < _DNS_CLASS_MAX; i++) {
661 t = dns_class_to_string(i);
662 if (t)
663 puts(t);
664 }
665}
666
bdef7319 667static void help(void) {
45ec7efb
LP
668 printf("%s [OPTIONS...] NAME...\n"
669 "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
670 "Resolve domain names, IPv4 or IPv6 addresses, resource records, and services.\n\n"
671 " -h --help Show this help\n"
672 " --version Show package version\n"
673 " -4 Resolve IPv4 addresses\n"
674 " -6 Resolve IPv6 addresses\n"
675 " -i INTERFACE Look on interface\n"
676 " -p --protocol=PROTOCOL Look via protocol\n"
677 " -t --type=TYPE Query RR with DNS type\n"
678 " -c --class=CLASS Query RR with DNS class\n"
679 " --service Resolve service (SRV)\n"
680 " --service-address=BOOL Do [not] resolve address for services\n"
681 " --service-txt=BOOL Do [not] resolve TXT records for services\n"
682 " --cname=BOOL Do [not] follow CNAME redirects\n"
801ad6a6 683 " --search=BOOL Do [not] use search domains\n"
45ec7efb
LP
684 " --legend=BOOL Do [not] print column headers\n"
685 , program_invocation_short_name, program_invocation_short_name);
bdef7319
ZJS
686}
687
688static int parse_argv(int argc, char *argv[]) {
689 enum {
690 ARG_VERSION = 0x100,
dad29dff 691 ARG_LEGEND,
45ec7efb
LP
692 ARG_SERVICE,
693 ARG_CNAME,
694 ARG_SERVICE_ADDRESS,
695 ARG_SERVICE_TXT,
801ad6a6 696 ARG_SEARCH,
bdef7319
ZJS
697 };
698
699 static const struct option options[] = {
45ec7efb
LP
700 { "help", no_argument, NULL, 'h' },
701 { "version", no_argument, NULL, ARG_VERSION },
702 { "type", required_argument, NULL, 't' },
703 { "class", required_argument, NULL, 'c' },
704 { "legend", required_argument, NULL, ARG_LEGEND },
705 { "protocol", required_argument, NULL, 'p' },
706 { "cname", required_argument, NULL, ARG_CNAME },
707 { "service", no_argument, NULL, ARG_SERVICE },
708 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
709 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
801ad6a6 710 { "search", required_argument, NULL, ARG_SEARCH },
bdef7319
ZJS
711 {}
712 };
713
2d4c5cbc 714 int c, r;
bdef7319
ZJS
715
716 assert(argc >= 0);
717 assert(argv);
718
51323288 719 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
bdef7319
ZJS
720 switch(c) {
721
722 case 'h':
723 help();
724 return 0; /* done */;
725
726 case ARG_VERSION:
3f6fd1ba 727 return version();
bdef7319
ZJS
728
729 case '4':
730 arg_family = AF_INET;
731 break;
732
733 case '6':
734 arg_family = AF_INET6;
735 break;
736
3fa4999b
LP
737 case 'i': {
738 int ifi;
739
6ad623a3 740 if (parse_ifindex(optarg, &ifi) >= 0)
3fa4999b
LP
741 arg_ifindex = ifi;
742 else {
743 ifi = if_nametoindex(optarg);
744 if (ifi <= 0)
745 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
746
747 arg_ifindex = ifi;
748 }
749
2d4c5cbc 750 break;
3fa4999b 751 }
2d4c5cbc
LP
752
753 case 't':
b93312f5
ZJS
754 if (streq(optarg, "help")) {
755 help_dns_types();
756 return 0;
757 }
758
de292aa1
ZJS
759 arg_type = dns_type_from_string(optarg);
760 if (arg_type < 0) {
2d4c5cbc 761 log_error("Failed to parse RR record type %s", optarg);
590baf91 762 return arg_type;
2d4c5cbc 763 }
de292aa1 764 assert(arg_type > 0 && (uint16_t) arg_type == arg_type);
b93312f5 765
2d4c5cbc
LP
766 break;
767
768 case 'c':
b93312f5
ZJS
769 if (streq(optarg, "help")) {
770 help_dns_classes();
771 return 0;
772 }
773
2d4c5cbc
LP
774 r = dns_class_from_string(optarg, &arg_class);
775 if (r < 0) {
776 log_error("Failed to parse RR record class %s", optarg);
777 return r;
bdef7319 778 }
b93312f5
ZJS
779
780 break;
781
dad29dff 782 case ARG_LEGEND:
45ec7efb
LP
783 r = parse_boolean(optarg);
784 if (r < 0)
785 return log_error_errno(r, "Failed to parse --legend= argument");
786
787 arg_legend = r;
bdef7319
ZJS
788 break;
789
51323288
LP
790 case 'p':
791 if (streq(optarg, "dns"))
792 arg_flags |= SD_RESOLVED_DNS;
793 else if (streq(optarg, "llmnr"))
794 arg_flags |= SD_RESOLVED_LLMNR;
795 else if (streq(optarg, "llmnr-ipv4"))
796 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
797 else if (streq(optarg, "llmnr-ipv6"))
798 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
799 else {
800 log_error("Unknown protocol specifier: %s", optarg);
801 return -EINVAL;
802 }
803
804 break;
805
45ec7efb
LP
806 case ARG_SERVICE:
807 arg_resolve_service = true;
808 break;
809
810 case ARG_CNAME:
811 r = parse_boolean(optarg);
812 if (r < 0)
813 return log_error_errno(r, "Failed to parse --cname= argument.");
814 if (r == 0)
815 arg_flags |= SD_RESOLVED_NO_CNAME;
816 else
817 arg_flags &= ~SD_RESOLVED_NO_CNAME;
818 break;
819
820 case ARG_SERVICE_ADDRESS:
821 r = parse_boolean(optarg);
822 if (r < 0)
823 return log_error_errno(r, "Failed to parse --service-address= argument.");
824 if (r == 0)
825 arg_flags |= SD_RESOLVED_NO_ADDRESS;
826 else
827 arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
828 break;
829
830 case ARG_SERVICE_TXT:
831 r = parse_boolean(optarg);
832 if (r < 0)
833 return log_error_errno(r, "Failed to parse --service-txt= argument.");
834 if (r == 0)
835 arg_flags |= SD_RESOLVED_NO_TXT;
836 else
837 arg_flags &= ~SD_RESOLVED_NO_TXT;
838 break;
839
801ad6a6
LP
840 case ARG_SEARCH:
841 r = parse_boolean(optarg);
842 if (r < 0)
843 return log_error_errno(r, "Failed to parse --search argument.");
844 if (r == 0)
845 arg_flags |= SD_RESOLVED_NO_SEARCH;
846 else
847 arg_flags &= ~SD_RESOLVED_NO_SEARCH;
848 break;
849
bdef7319
ZJS
850 case '?':
851 return -EINVAL;
852
853 default:
854 assert_not_reached("Unhandled option");
855 }
856
2d4c5cbc 857 if (arg_type == 0 && arg_class != 0) {
45ec7efb
LP
858 log_error("--class= may only be used in conjunction with --type=.");
859 return -EINVAL;
860 }
861
862 if (arg_type != 0 && arg_resolve_service) {
863 log_error("--service and --type= may not be combined.");
2d4c5cbc
LP
864 return -EINVAL;
865 }
866
867 if (arg_type != 0 && arg_class == 0)
868 arg_class = DNS_CLASS_IN;
869
bdef7319
ZJS
870 return 1 /* work to do */;
871}
872
bdef7319 873int main(int argc, char **argv) {
03976f7b 874 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
bdef7319
ZJS
875 int r;
876
877 log_parse_environment();
878 log_open();
879
880 r = parse_argv(argc, argv);
881 if (r <= 0)
79266746
LP
882 goto finish;
883
884 if (optind >= argc) {
885 log_error("No arguments passed");
886 r = -EINVAL;
887 goto finish;
888 }
bdef7319
ZJS
889
890 r = sd_bus_open_system(&bus);
891 if (r < 0) {
da927ba9 892 log_error_errno(r, "sd_bus_open_system: %m");
79266746 893 goto finish;
bdef7319
ZJS
894 }
895
45ec7efb
LP
896 if (arg_resolve_service) {
897
898 if (argc < optind + 1) {
899 log_error("Domain specification required.");
900 r = -EINVAL;
901 goto finish;
902
903 } else if (argc == optind + 1)
904 r = resolve_service(bus, NULL, NULL, argv[optind]);
905 else if (argc == optind + 2)
906 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
907 else if (argc == optind + 3)
908 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
909 else {
910 log_error("Too many arguments");
911 r = -EINVAL;
912 goto finish;
913 }
914
915 goto finish;
916 }
917
bdef7319 918 while (argv[optind]) {
79266746
LP
919 int family, ifindex, k;
920 union in_addr_union a;
921
2d4c5cbc
LP
922 if (arg_type != 0)
923 k = resolve_record(bus, argv[optind]);
924 else {
925 k = parse_address(argv[optind], &family, &a, &ifindex);
926 if (k >= 0)
927 k = resolve_address(bus, family, &a, ifindex);
928 else
929 k = resolve_host(bus, argv[optind]);
930 }
bdef7319 931
bdef7319
ZJS
932 if (r == 0)
933 r = k;
79266746
LP
934
935 optind++;
bdef7319
ZJS
936 }
937
79266746 938finish:
bdef7319
ZJS
939 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
940}