]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve-host/resolve-host.c
2c17ad6ede8a65568c62c735c22c7b9346acb341
[thirdparty/systemd.git] / src / resolve-host / resolve-host.c
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
22 #include <getopt.h>
23 #include <net/if.h>
24
25 #include "sd-bus.h"
26
27 #include "af-list.h"
28 #include "alloc-util.h"
29 #include "bus-error.h"
30 #include "bus-util.h"
31 #include "escape.h"
32 #include "in-addr-util.h"
33 #include "parse-util.h"
34 #include "resolved-def.h"
35 #include "resolved-dns-packet.h"
36
37 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
38
39 static int arg_family = AF_UNSPEC;
40 static int arg_ifindex = 0;
41 static int arg_type = 0;
42 static uint16_t arg_class = 0;
43 static bool arg_legend = true;
44 static uint64_t arg_flags = 0;
45 static bool arg_resolve_service = false;
46
47 static void print_source(uint64_t flags, usec_t rtt) {
48 char rtt_str[FORMAT_TIMESTAMP_MAX];
49
50 if (!arg_legend)
51 return;
52
53 if (flags == 0)
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
64 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
65
66 printf(" in %s", rtt_str);
67
68 fputc('.', stdout);
69 fputc('\n', stdout);
70 }
71
72 static int resolve_host(sd_bus *bus, const char *name) {
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;
76 const char *canonical = NULL;
77 char ifname[IF_NAMESIZE] = "";
78 unsigned c = 0;
79 int r;
80 uint64_t flags;
81 usec_t ts;
82
83 assert(name);
84
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);
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");
97 if (r < 0)
98 return bus_log_create_error(r);
99
100 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
101 if (r < 0)
102 return bus_log_create_error(r);
103
104 ts = now(CLOCK_MONOTONIC);
105
106 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
107 if (r < 0)
108 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
109
110 ts = now(CLOCK_MONOTONIC) - ts;
111
112 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
113 if (r < 0)
114 return bus_log_parse_error(r);
115
116 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
117 _cleanup_free_ char *pretty = NULL;
118 int ifindex, family;
119 const void *a;
120 size_t sz;
121
122 assert_cc(sizeof(int) == sizeof(int32_t));
123
124 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
125 if (r < 0)
126 return bus_log_parse_error(r);
127
128 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
129 if (r < 0)
130 return bus_log_parse_error(r);
131
132 r = sd_bus_message_exit_container(reply);
133 if (r < 0)
134 return bus_log_parse_error(r);
135
136 if (!IN_SET(family, AF_INET, AF_INET6)) {
137 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
138 continue;
139 }
140
141 if (sz != FAMILY_ADDRESS_SIZE(family)) {
142 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
143 return -EINVAL;
144 }
145
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);
149
150 r = in_addr_to_string(family, a, &pretty);
151 if (r < 0)
152 return log_error_errno(r, "Failed to print address for %s: %m", name);
153
154 printf("%*s%s %s%s%s\n",
155 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
156 pretty,
157 isempty(ifname) ? "" : "%", ifname);
158
159 c++;
160 }
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
168 r = sd_bus_message_read(reply, "st", &canonical, &flags);
169 if (r < 0)
170 return bus_log_parse_error(r);
171
172 if (!streq(name, canonical))
173 printf("%*s%s (%s)\n",
174 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
175 canonical);
176
177 if (c == 0) {
178 log_error("%s: no addresses found", name);
179 return -ESRCH;
180 }
181
182 print_source(flags, ts);
183
184 return 0;
185 }
186
187 static 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] = "";
192 uint64_t flags;
193 unsigned c = 0;
194 usec_t ts;
195 int r;
196
197 assert(bus);
198 assert(IN_SET(family, AF_INET, AF_INET6));
199 assert(address);
200
201 if (ifindex <= 0)
202 ifindex = arg_ifindex;
203
204 r = in_addr_to_string(family, address, &pretty);
205 if (r < 0)
206 return log_oom();
207
208 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
209 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
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
223 r = sd_bus_message_append(req, "ii", ifindex, family);
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
231 r = sd_bus_message_append(req, "t", arg_flags);
232 if (r < 0)
233 return bus_log_create_error(r);
234
235 ts = now(CLOCK_MONOTONIC);
236
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
243 ts = now(CLOCK_MONOTONIC) - ts;
244
245 r = sd_bus_message_enter_container(reply, 'a', "(is)");
246 if (r < 0)
247 return bus_log_create_error(r);
248
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));
253
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",
267 (int) strlen(pretty), c == 0 ? pretty : "",
268 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
269 (int) strlen(ifname), c == 0 ? ifname : "",
270 c == 0 ? ":" : " ",
271 n);
272
273 c++;
274 }
275 if (r < 0)
276 return bus_log_parse_error(r);
277
278 r = sd_bus_message_exit_container(reply);
279 if (r < 0)
280 return bus_log_parse_error(r);
281
282 r = sd_bus_message_read(reply, "t", &flags);
283 if (r < 0)
284 return bus_log_parse_error(r);
285
286 if (c == 0) {
287 log_error("%s: no names found", pretty);
288 return -ESRCH;
289 }
290
291 print_source(flags, ts);
292
293 return 0;
294 }
295
296 static 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) {
303 if (parse_ifindex(percent+1, &ifi) < 0) {
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;
318 return 0;
319 }
320
321 static 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;
325 char ifname[IF_NAMESIZE] = "";
326 unsigned n = 0;
327 uint64_t flags;
328 int r;
329 usec_t ts;
330
331 assert(name);
332
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);
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
348 assert((uint16_t) arg_type == arg_type);
349 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, arg_flags);
350 if (r < 0)
351 return bus_log_create_error(r);
352
353 ts = now(CLOCK_MONOTONIC);
354
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
361 ts = now(CLOCK_MONOTONIC) - ts;
362
363 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
364 if (r < 0)
365 return bus_log_parse_error(r);
366
367 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
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;
372 int ifindex;
373 const void *d;
374 size_t l;
375
376 assert_cc(sizeof(int) == sizeof(int32_t));
377
378 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
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
394 p->refuse_compression = true;
395
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
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);
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
426 r = sd_bus_message_read(reply, "t", &flags);
427 if (r < 0)
428 return bus_log_parse_error(r);
429
430 if (n == 0) {
431 log_error("%s: no records found", name);
432 return -ESRCH;
433 }
434
435 print_source(flags, ts);
436
437 return 0;
438 }
439
440 static 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
641 static void help_dns_types(void) {
642 int i;
643 const char *t;
644
645 if (arg_legend)
646 puts("Known DNS RR types:");
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
654 static void help_dns_classes(void) {
655 int i;
656 const char *t;
657
658 if (arg_legend)
659 puts("Known DNS RR classes:");
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
667 static void help(void) {
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"
683 " --legend=BOOL Do [not] print column headers\n"
684 , program_invocation_short_name, program_invocation_short_name);
685 }
686
687 static int parse_argv(int argc, char *argv[]) {
688 enum {
689 ARG_VERSION = 0x100,
690 ARG_LEGEND,
691 ARG_SERVICE,
692 ARG_CNAME,
693 ARG_SERVICE_ADDRESS,
694 ARG_SERVICE_TXT,
695 };
696
697 static const struct option options[] = {
698 { "help", no_argument, NULL, 'h' },
699 { "version", no_argument, NULL, ARG_VERSION },
700 { "type", required_argument, NULL, 't' },
701 { "class", required_argument, NULL, 'c' },
702 { "legend", required_argument, NULL, ARG_LEGEND },
703 { "protocol", required_argument, NULL, 'p' },
704 { "cname", required_argument, NULL, ARG_CNAME },
705 { "service", no_argument, NULL, ARG_SERVICE },
706 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
707 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
708 {}
709 };
710
711 int c, r;
712
713 assert(argc >= 0);
714 assert(argv);
715
716 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
717 switch(c) {
718
719 case 'h':
720 help();
721 return 0; /* done */;
722
723 case ARG_VERSION:
724 return version();
725
726 case '4':
727 arg_family = AF_INET;
728 break;
729
730 case '6':
731 arg_family = AF_INET6;
732 break;
733
734 case 'i': {
735 int ifi;
736
737 if (parse_ifindex(optarg, &ifi) >= 0)
738 arg_ifindex = ifi;
739 else {
740 ifi = if_nametoindex(optarg);
741 if (ifi <= 0)
742 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
743
744 arg_ifindex = ifi;
745 }
746
747 break;
748 }
749
750 case 't':
751 if (streq(optarg, "help")) {
752 help_dns_types();
753 return 0;
754 }
755
756 arg_type = dns_type_from_string(optarg);
757 if (arg_type < 0) {
758 log_error("Failed to parse RR record type %s", optarg);
759 return arg_type;
760 }
761 assert(arg_type > 0 && (uint16_t) arg_type == arg_type);
762
763 break;
764
765 case 'c':
766 if (streq(optarg, "help")) {
767 help_dns_classes();
768 return 0;
769 }
770
771 r = dns_class_from_string(optarg, &arg_class);
772 if (r < 0) {
773 log_error("Failed to parse RR record class %s", optarg);
774 return r;
775 }
776
777 break;
778
779 case ARG_LEGEND:
780 r = parse_boolean(optarg);
781 if (r < 0)
782 return log_error_errno(r, "Failed to parse --legend= argument");
783
784 arg_legend = r;
785 break;
786
787 case 'p':
788 if (streq(optarg, "dns"))
789 arg_flags |= SD_RESOLVED_DNS;
790 else if (streq(optarg, "llmnr"))
791 arg_flags |= SD_RESOLVED_LLMNR;
792 else if (streq(optarg, "llmnr-ipv4"))
793 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
794 else if (streq(optarg, "llmnr-ipv6"))
795 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
796 else {
797 log_error("Unknown protocol specifier: %s", optarg);
798 return -EINVAL;
799 }
800
801 break;
802
803 case ARG_SERVICE:
804 arg_resolve_service = true;
805 break;
806
807 case ARG_CNAME:
808 r = parse_boolean(optarg);
809 if (r < 0)
810 return log_error_errno(r, "Failed to parse --cname= argument.");
811 if (r == 0)
812 arg_flags |= SD_RESOLVED_NO_CNAME;
813 else
814 arg_flags &= ~SD_RESOLVED_NO_CNAME;
815 break;
816
817 case ARG_SERVICE_ADDRESS:
818 r = parse_boolean(optarg);
819 if (r < 0)
820 return log_error_errno(r, "Failed to parse --service-address= argument.");
821 if (r == 0)
822 arg_flags |= SD_RESOLVED_NO_ADDRESS;
823 else
824 arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
825 break;
826
827 case ARG_SERVICE_TXT:
828 r = parse_boolean(optarg);
829 if (r < 0)
830 return log_error_errno(r, "Failed to parse --service-txt= argument.");
831 if (r == 0)
832 arg_flags |= SD_RESOLVED_NO_TXT;
833 else
834 arg_flags &= ~SD_RESOLVED_NO_TXT;
835 break;
836
837 case '?':
838 return -EINVAL;
839
840 default:
841 assert_not_reached("Unhandled option");
842 }
843
844 if (arg_type == 0 && arg_class != 0) {
845 log_error("--class= may only be used in conjunction with --type=.");
846 return -EINVAL;
847 }
848
849 if (arg_type != 0 && arg_resolve_service) {
850 log_error("--service and --type= may not be combined.");
851 return -EINVAL;
852 }
853
854 if (arg_type != 0 && arg_class == 0)
855 arg_class = DNS_CLASS_IN;
856
857 return 1 /* work to do */;
858 }
859
860 int main(int argc, char **argv) {
861 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
862 int r;
863
864 log_parse_environment();
865 log_open();
866
867 r = parse_argv(argc, argv);
868 if (r <= 0)
869 goto finish;
870
871 if (optind >= argc) {
872 log_error("No arguments passed");
873 r = -EINVAL;
874 goto finish;
875 }
876
877 r = sd_bus_open_system(&bus);
878 if (r < 0) {
879 log_error_errno(r, "sd_bus_open_system: %m");
880 goto finish;
881 }
882
883 if (arg_resolve_service) {
884
885 if (argc < optind + 1) {
886 log_error("Domain specification required.");
887 r = -EINVAL;
888 goto finish;
889
890 } else if (argc == optind + 1)
891 r = resolve_service(bus, NULL, NULL, argv[optind]);
892 else if (argc == optind + 2)
893 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
894 else if (argc == optind + 3)
895 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
896 else {
897 log_error("Too many arguments");
898 r = -EINVAL;
899 goto finish;
900 }
901
902 goto finish;
903 }
904
905 while (argv[optind]) {
906 int family, ifindex, k;
907 union in_addr_union a;
908
909 if (arg_type != 0)
910 k = resolve_record(bus, argv[optind]);
911 else {
912 k = parse_address(argv[optind], &family, &a, &ifindex);
913 if (k >= 0)
914 k = resolve_address(bus, family, &a, ifindex);
915 else
916 k = resolve_host(bus, argv[optind]);
917 }
918
919 if (r == 0)
920 r = k;
921
922 optind++;
923 }
924
925 finish:
926 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
927 }