resolve-tool.c revision ba82da3bb547bb2db1b8637a4a9c4a8c69f7fb6d
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek/***
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek This file is part of systemd.
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek Copyright 2014 Zbigniew Jędrzejewski-Szmek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek systemd is free software; you can redistribute it and/or modify it
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek under the terms of the GNU Lesser General Public License as published by
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek the Free Software Foundation; either version 2.1 of the License, or
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek (at your option) any later version.
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek systemd is distributed in the hope that it will be useful, but
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek WITHOUT ANY WARRANTY; without even the implied warranty of
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek Lesser General Public License for more details.
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek You should have received a copy of the GNU Lesser General Public License
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek***/
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include <getopt.h>
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include <net/if.h>
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include "sd-bus.h"
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
ac67129265297ad55cb36a6749a8e79370986183Jakub Hrozek#include "af-list.h"
ac67129265297ad55cb36a6749a8e79370986183Jakub Hrozek#include "alloc-util.h"
ac67129265297ad55cb36a6749a8e79370986183Jakub Hrozek#include "bus-error.h"
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include "bus-util.h"
ac67129265297ad55cb36a6749a8e79370986183Jakub Hrozek#include "escape.h"
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include "in-addr-util.h"
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek#include "parse-util.h"
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek#include "resolved-def.h"
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek#include "resolved-dns-packet.h"
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#include "terminal-util.h"
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic int arg_family = AF_UNSPEC;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic int arg_ifindex = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic uint16_t arg_type = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic uint16_t arg_class = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic bool arg_legend = true;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic uint64_t arg_flags = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic enum {
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek MODE_RESOLVE_HOST,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek MODE_RESOLVE_RECORD,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek MODE_RESOLVE_SERVICE,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek MODE_STATISTICS,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek MODE_RESET_STATISTICS,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek} arg_mode = MODE_RESOLVE_HOST;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic void print_source(uint64_t flags, usec_t rtt) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek char rtt_str[FORMAT_TIMESTAMP_MAX];
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (!arg_legend)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (flags == 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek fputs("\n-- Information acquired via", stdout);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (flags != 0)
a171d77f40aa92e240e91aa4bafe5a392a98b5a2Michal Zidek printf(" protocol%s%s%s%s%s",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek flags & SD_RESOLVED_DNS ? " DNS" :"",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : "");
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek printf(" in %s", rtt_str);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek fputc('.', stdout);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek fputc('\n', stdout);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek}
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic int resolve_host(sd_bus *bus, const char *name) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *canonical = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek char ifname[IF_NAMESIZE] = "";
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek unsigned c = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek uint64_t flags;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek usec_t ts;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert(name);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
a171d77f40aa92e240e91aa4bafe5a392a98b5a2Michal Zidek log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
a171d77f40aa92e240e91aa4bafe5a392a98b5a2Michal Zidek
a171d77f40aa92e240e91aa4bafe5a392a98b5a2Michal Zidek r = sd_bus_message_new_method_call(
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek bus,
a171d77f40aa92e240e91aa4bafe5a392a98b5a2Michal Zidek &req,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "org.freedesktop.resolve1",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "/org/freedesktop/resolve1",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "org.freedesktop.resolve1.Manager",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "ResolveHostname");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_create_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_create_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ts = now(CLOCK_MONOTONIC);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ts = now(CLOCK_MONOTONIC) - ts;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_free_ char *pretty = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int ifindex, family;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const void *a;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek size_t sz;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert_cc(sizeof(int) == sizeof(int32_t));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_read(reply, "ii", &ifindex, &family);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_read_array(reply, 'y', &a, &sz);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_exit_container(reply);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (!IN_SET(family, AF_INET, AF_INET6)) {
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek continue;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (sz != FAMILY_ADDRESS_SIZE(family)) {
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return -EINVAL;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek ifname[0] = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (ifindex > 0 && !if_indextoname(ifindex, ifname))
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = in_addr_to_string(family, a, &pretty);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return log_error_errno(r, "Failed to print address for %s: %m", name);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek printf("%*s%s %s%s%s\n",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek pretty,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek isempty(ifname) ? "" : "%", ifname);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek c++;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_exit_container(reply);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_read(reply, "st", &canonical, &flags);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (!streq(name, canonical))
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek printf("%*s%s (%s)\n",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek canonical);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (c == 0) {
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek log_error("%s: no addresses found", name);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return -ESRCH;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek print_source(flags, ts);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek}
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozekstatic int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek _cleanup_free_ char *pretty = NULL;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek char ifname[IF_NAMESIZE] = "";
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek uint64_t flags;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek unsigned c = 0;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek usec_t ts;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek int r;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek assert(bus);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek assert(IN_SET(family, AF_INET, AF_INET6));
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek assert(address);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (ifindex <= 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek ifindex = arg_ifindex;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = in_addr_to_string(family, address, &pretty);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return log_oom();
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (ifindex > 0 && !if_indextoname(ifindex, ifname))
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_new_method_call(
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek bus,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek &req,
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek "org.freedesktop.resolve1",
1c383994ae898fa862f93c43501395bae6304f28Jakub Hrozek "/org/freedesktop/resolve1",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek "org.freedesktop.resolve1.Manager",
1c383994ae898fa862f93c43501395bae6304f28Jakub Hrozek "ResolveAddress");
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_create_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_append(req, "ii", ifindex, family);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
1c383994ae898fa862f93c43501395bae6304f28Jakub Hrozek return bus_log_create_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_create_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_append(req, "t", arg_flags);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (r < 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return bus_log_create_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek ts = now(CLOCK_MONOTONIC);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ts = now(CLOCK_MONOTONIC) - ts;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_enter_container(reply, 'a', "(is)");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_create_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *n;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert_cc(sizeof(int) == sizeof(int32_t));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_read(reply, "is", &ifindex, &n);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_exit_container(reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ifname[0] = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (ifindex > 0 && !if_indextoname(ifindex, ifname))
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek printf("%*s%*s%*s%s %s\n",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek (int) strlen(pretty), c == 0 ? pretty : "",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek (int) strlen(ifname), c == 0 ? ifname : "",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek c == 0 ? ":" : " ",
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek n);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek c++;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = sd_bus_message_exit_container(reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_read(reply, "t", &flags);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
1cde5866227feccf482f82c112c352c103afbc59Jakub Hrozek if (c == 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_error("%s: no names found", pretty);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return -ESRCH;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
1cde5866227feccf482f82c112c352c103afbc59Jakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek print_source(flags, ts);
1cde5866227feccf482f82c112c352c103afbc59Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek}
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *percent, *a;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int ifi = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek percent = strchr(s, '%');
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (percent) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (parse_ifindex(percent+1, &ifi) < 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ifi = if_nametoindex(percent+1);
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (ifi <= 0)
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return -EINVAL;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek }
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek a = strndupa(s, percent - s);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek } else
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek a = s;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek r = in_addr_from_string_auto(a, family, address);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek *ifindex = ifi;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek return 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek}
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek char ifname[IF_NAMESIZE] = "";
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek unsigned n = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek uint64_t flags;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek usec_t ts;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert(name);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_new_method_call(
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek bus,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek &req,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "org.freedesktop.resolve1",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "/org/freedesktop/resolve1",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "org.freedesktop.resolve1.Manager",
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "ResolveRecord");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_create_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_create_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ts = now(CLOCK_MONOTONIC);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ts = now(CLOCK_MONOTONIC) - ts;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
0a78bac242d0172a858d6b65402276aa734a4671Jakub Hrozek _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *s;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek uint16_t c, t;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int ifindex;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const void *d;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek size_t l;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert_cc(sizeof(int) == sizeof(int32_t));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_read_array(reply, 'y', &d, &l);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
1cde5866227feccf482f82c112c352c103afbc59Jakub Hrozek r = sd_bus_message_exit_container(reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
1cde5866227feccf482f82c112c352c103afbc59Jakub Hrozek r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_oom();
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek p->refuse_compression = true;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = dns_packet_append_blob(p, d, l, NULL);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_oom();
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = dns_packet_read_rr(p, &rr, NULL, NULL);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_error_errno(r, "Failed to parse RR: %m");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek s = dns_resource_record_to_string(rr);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (!s)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return log_oom();
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ifname[0] = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (ifindex > 0 && !if_indextoname(ifindex, ifname))
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek n++;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_exit_container(reply);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek r = sd_bus_message_read(reply, "t", &flags);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (r < 0)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return bus_log_parse_error(r);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (n == 0) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_error("%s: no records found", name);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return -ESRCH;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek print_source(flags, ts);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek return 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek}
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic int resolve_rfc4501(sd_bus *bus, const char *name) {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek uint16_t type = 0, class = 0;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *p, *q, *n;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek int r;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert(bus);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert(name);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek assert(startswith(name, "dns:"));
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek /* Parse RFC 4501 dns: URIs */
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek p = name + 4;
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek
c83ebdbc0629313ef6594215ed1674b9a783cfddJakub Hrozek if (p[0] == '/') {
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek const char *e;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (p[1] != '/')
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek goto invalid;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek e = strchr(p + 2, '/');
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (!e)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek goto invalid;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (e != p + 2)
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek log_warning("DNS authority specification not supported; ignoring specified authority.");
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek p = e + 1;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek }
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek q = strchr(p, '?');
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek if (q) {
n = strndupa(p, q - p);
q++;
for (;;) {
const char *f;
f = startswith_no_case(q, "class=");
if (f) {
_cleanup_free_ char *t = NULL;
const char *e;
if (class != 0) {
log_error("DNS class specified twice.");
return -EINVAL;
}
e = strchrnul(f, ';');
t = strndup(f, e - f);
if (!t)
return log_oom();
r = dns_class_from_string(t);
if (r < 0) {
log_error("Unknown DNS class %s.", t);
return -EINVAL;
}
class = r;
if (*e == ';') {
q = e + 1;
continue;
}
break;
}
f = startswith_no_case(q, "type=");
if (f) {
_cleanup_free_ char *t = NULL;
const char *e;
if (type != 0) {
log_error("DNS type specified twice.");
return -EINVAL;
}
e = strchrnul(f, ';');
t = strndup(f, e - f);
if (!t)
return log_oom();
r = dns_type_from_string(t);
if (r < 0) {
log_error("Unknown DNS type %s.", t);
return -EINVAL;
}
type = r;
if (*e == ';') {
q = e + 1;
continue;
}
break;
}
goto invalid;
}
} else
n = p;
if (type == 0)
type = arg_type;
if (type == 0)
type = DNS_TYPE_A;
if (class == 0)
class = arg_class;
if (class == 0)
class = DNS_CLASS_IN;
return resolve_record(bus, n, class, type);
invalid:
log_error("Invalid DNS URI: %s", name);
return -EINVAL;
}
static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
const char *canonical_name, *canonical_type, *canonical_domain;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char ifname[IF_NAMESIZE] = "";
size_t indent, sz;
uint64_t flags;
const char *p;
unsigned c;
usec_t ts;
int r;
assert(bus);
assert(domain);
if (isempty(name))
name = NULL;
if (isempty(type))
type = NULL;
if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
if (name)
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);
else if (type)
log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
else
log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
r = sd_bus_message_new_method_call(
bus,
&req,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"ResolveService");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
if (r < 0)
return bus_log_create_error(r);
ts = now(CLOCK_MONOTONIC);
r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
if (r < 0)
return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
ts = now(CLOCK_MONOTONIC) - ts;
r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
if (r < 0)
return bus_log_parse_error(r);
indent =
(name ? strlen(name) + 1 : 0) +
(type ? strlen(type) + 1 : 0) +
strlen(domain) + 2;
c = 0;
while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
uint16_t priority, weight, port;
const char *hostname, *canonical;
r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
if (r < 0)
return bus_log_parse_error(r);
if (name)
printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
if (type)
printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
(int) strlen(domain), c == 0 ? domain : "",
c == 0 ? ":" : " ",
hostname, port,
priority, weight);
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
_cleanup_free_ char *pretty = NULL;
int ifindex, family;
const void *a;
assert_cc(sizeof(int) == sizeof(int32_t));
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
if (!IN_SET(family, AF_INET, AF_INET6)) {
log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
continue;
}
if (sz != FAMILY_ADDRESS_SIZE(family)) {
log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
return -EINVAL;
}
ifname[0] = 0;
if (ifindex > 0 && !if_indextoname(ifindex, ifname))
log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
r = in_addr_to_string(family, a, &pretty);
if (r < 0)
return log_error_errno(r, "Failed to print address for %s: %m", name);
printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_read(reply, "s", &canonical);
if (r < 0)
return bus_log_parse_error(r);
if (!streq(hostname, canonical))
printf("%*s(%s)\n", (int) indent, "", canonical);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
c++;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_enter_container(reply, 'a', "ay");
if (r < 0)
return bus_log_parse_error(r);
c = 0;
while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
_cleanup_free_ char *escaped = NULL;
escaped = cescape_length(p, sz);
if (!escaped)
return log_oom();
printf("%*s%s\n", (int) indent, "", escaped);
c++;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
if (r < 0)
return bus_log_parse_error(r);
if (isempty(canonical_name))
canonical_name = NULL;
if (isempty(canonical_type))
canonical_type = NULL;
if (!streq_ptr(name, canonical_name) ||
!streq_ptr(type, canonical_type) ||
!streq_ptr(domain, canonical_domain)) {
printf("%*s(", (int) indent, "");
if (canonical_name)
printf("%s/", canonical_name);
if (canonical_type)
printf("%s/", canonical_type);
printf("%s)\n", canonical_domain);
}
print_source(flags, ts);
return 0;
}
static int show_statistics(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
uint64_t n_current_transactions, n_total_transactions,
cache_size, n_cache_hit, n_cache_miss,
n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
int r, dnssec_supported;
assert(bus);
r = sd_bus_get_property_trivial(bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"DNSSECSupported",
&error,
'b',
&dnssec_supported);
if (r < 0)
return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
printf("DNSSEC supported by current servers: %s%s%s\n\n",
ansi_highlight(),
yes_no(dnssec_supported),
ansi_normal());
r = sd_bus_get_property(bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"TransactionStatistics",
&error,
&reply,
"(tt)");
if (r < 0)
return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "(tt)",
&n_current_transactions,
&n_total_transactions);
if (r < 0)
return bus_log_parse_error(r);
printf("%sTransactions%s\n"
"Current Transactions: %" PRIu64 "\n"
" Total Transactions: %" PRIu64 "\n",
ansi_highlight(),
ansi_normal(),
n_current_transactions,
n_total_transactions);
reply = sd_bus_message_unref(reply);
r = sd_bus_get_property(bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"CacheStatistics",
&error,
&reply,
"(ttt)");
if (r < 0)
return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "(ttt)",
&cache_size,
&n_cache_hit,
&n_cache_miss);
if (r < 0)
return bus_log_parse_error(r);
printf("\n%sCache%s\n"
" Current Cache Size: %" PRIu64 "\n"
" Cache Hits: %" PRIu64 "\n"
" Cache Misses: %" PRIu64 "\n",
ansi_highlight(),
ansi_normal(),
cache_size,
n_cache_hit,
n_cache_miss);
reply = sd_bus_message_unref(reply);
r = sd_bus_get_property(bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"DNSSECStatistics",
&error,
&reply,
"(tttt)");
if (r < 0)
return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "(tttt)",
&n_dnssec_secure,
&n_dnssec_insecure,
&n_dnssec_bogus,
&n_dnssec_indeterminate);
if (r < 0)
return bus_log_parse_error(r);
printf("\n%sDNSSEC Verdicts%s\n"
" Secure: %" PRIu64 "\n"
" Insecure: %" PRIu64 "\n"
" Bogus: %" PRIu64 "\n"
" Indeterminate: %" PRIu64 "\n",
ansi_highlight(),
ansi_normal(),
n_dnssec_secure,
n_dnssec_insecure,
n_dnssec_bogus,
n_dnssec_indeterminate);
return 0;
}
static int reset_statistics(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = sd_bus_call_method(bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"ResetStatistics",
&error,
NULL,
NULL);
if (r < 0)
return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
return 0;
}
static void help_protocol_types(void) {
if (arg_legend)
puts("Known protocol types:");
puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
}
static void help_dns_types(void) {
int i;
const char *t;
if (arg_legend)
puts("Known DNS RR types:");
for (i = 0; i < _DNS_TYPE_MAX; i++) {
t = dns_type_to_string(i);
if (t)
puts(t);
}
}
static void help_dns_classes(void) {
int i;
const char *t;
if (arg_legend)
puts("Known DNS RR classes:");
for (i = 0; i < _DNS_CLASS_MAX; i++) {
t = dns_class_to_string(i);
if (t)
puts(t);
}
}
static void help(void) {
printf("%s [OPTIONS...] NAME...\n"
"%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
"Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -4 Resolve IPv4 addresses\n"
" -6 Resolve IPv6 addresses\n"
" -i --interface=INTERFACE Look on interface\n"
" -p --protocol=PROTOCOL|help Look via protocol\n"
" -t --type=TYPE|help Query RR with DNS type\n"
" -c --class=CLASS|help Query RR with DNS class\n"
" --service Resolve service (SRV)\n"
" --service-address=BOOL Do [not] resolve address for services\n"
" --service-txt=BOOL Do [not] resolve TXT records for services\n"
" --cname=BOOL Do [not] follow CNAME redirects\n"
" --search=BOOL Do [not] use search domains\n"
" --legend=BOOL Do [not] print column headers and meta information\n"
" --statistics Show resolver statistics\n"
" --reset-statistics Reset resolver statistics\n"
, program_invocation_short_name, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_LEGEND,
ARG_SERVICE,
ARG_CNAME,
ARG_SERVICE_ADDRESS,
ARG_SERVICE_TXT,
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "type", required_argument, NULL, 't' },
{ "class", required_argument, NULL, 'c' },
{ "legend", required_argument, NULL, ARG_LEGEND },
{ "interface", required_argument, NULL, 'i' },
{ "protocol", required_argument, NULL, 'p' },
{ "cname", required_argument, NULL, ARG_CNAME },
{ "service", no_argument, NULL, ARG_SERVICE },
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
{ "search", required_argument, NULL, ARG_SEARCH },
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
{ "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
switch(c) {
case 'h':
help();
return 0; /* done */;
case ARG_VERSION:
return version();
case '4':
arg_family = AF_INET;
break;
case '6':
arg_family = AF_INET6;
break;
case 'i': {
int ifi;
if (parse_ifindex(optarg, &ifi) >= 0)
arg_ifindex = ifi;
else {
ifi = if_nametoindex(optarg);
if (ifi <= 0)
return log_error_errno(errno, "Unknown interface %s: %m", optarg);
arg_ifindex = ifi;
}
break;
}
case 't':
if (streq(optarg, "help")) {
help_dns_types();
return 0;
}
r = dns_type_from_string(optarg);
if (r < 0) {
log_error("Failed to parse RR record type %s", optarg);
return r;
}
arg_type = (uint16_t) r;
assert((int) arg_type == r);
arg_mode = MODE_RESOLVE_RECORD;
break;
case 'c':
if (streq(optarg, "help")) {
help_dns_classes();
return 0;
}
r = dns_class_from_string(optarg);
if (r < 0) {
log_error("Failed to parse RR record class %s", optarg);
return r;
}
arg_class = (uint16_t) r;
assert((int) arg_class == r);
break;
case ARG_LEGEND:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --legend= argument");
arg_legend = r;
break;
case 'p':
if (streq(optarg, "help")) {
help_protocol_types();
return 0;
} else if (streq(optarg, "dns"))
arg_flags |= SD_RESOLVED_DNS;
else if (streq(optarg, "llmnr"))
arg_flags |= SD_RESOLVED_LLMNR;
else if (streq(optarg, "llmnr-ipv4"))
arg_flags |= SD_RESOLVED_LLMNR_IPV4;
else if (streq(optarg, "llmnr-ipv6"))
arg_flags |= SD_RESOLVED_LLMNR_IPV6;
else {
log_error("Unknown protocol specifier: %s", optarg);
return -EINVAL;
}
break;
case ARG_SERVICE:
arg_mode = MODE_RESOLVE_SERVICE;
break;
case ARG_CNAME:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --cname= argument.");
if (r == 0)
arg_flags |= SD_RESOLVED_NO_CNAME;
else
arg_flags &= ~SD_RESOLVED_NO_CNAME;
break;
case ARG_SERVICE_ADDRESS:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-address= argument.");
if (r == 0)
arg_flags |= SD_RESOLVED_NO_ADDRESS;
else
arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
break;
case ARG_SERVICE_TXT:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-txt= argument.");
if (r == 0)
arg_flags |= SD_RESOLVED_NO_TXT;
else
arg_flags &= ~SD_RESOLVED_NO_TXT;
break;
case ARG_SEARCH:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --search argument.");
if (r == 0)
arg_flags |= SD_RESOLVED_NO_SEARCH;
else
arg_flags &= ~SD_RESOLVED_NO_SEARCH;
break;
case ARG_STATISTICS:
arg_mode = MODE_STATISTICS;
break;
case ARG_RESET_STATISTICS:
arg_mode = MODE_RESET_STATISTICS;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
if (arg_type == 0 && arg_class != 0) {
log_error("--class= may only be used in conjunction with --type=.");
return -EINVAL;
}
if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) {
log_error("--service and --type= may not be combined.");
return -EINVAL;
}
if (arg_type != 0 && arg_class == 0)
arg_class = DNS_CLASS_IN;
if (arg_class != 0 && arg_type == 0)
arg_type = DNS_TYPE_A;
return 1 /* work to do */;
}
int main(int argc, char **argv) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = sd_bus_open_system(&bus);
if (r < 0) {
log_error_errno(r, "sd_bus_open_system: %m");
goto finish;
}
switch (arg_mode) {
case MODE_RESOLVE_HOST:
if (optind >= argc) {
log_error("No arguments passed.");
r = -EINVAL;
goto finish;
}
while (argv[optind]) {
int family, ifindex, k;
union in_addr_union a;
if (startswith(argv[optind], "dns:"))
k = resolve_rfc4501(bus, argv[optind]);
else {
k = parse_address(argv[optind], &family, &a, &ifindex);
if (k >= 0)
k = resolve_address(bus, family, &a, ifindex);
else
k = resolve_host(bus, argv[optind]);
}
if (r == 0)
r = k;
optind++;
}
break;
case MODE_RESOLVE_RECORD:
if (optind >= argc) {
log_error("No arguments passed.");
r = -EINVAL;
goto finish;
}
while (argv[optind]) {
int k;
k = resolve_record(bus, argv[optind], arg_class, arg_type);
if (r == 0)
r = k;
optind++;
}
break;
case MODE_RESOLVE_SERVICE:
if (argc < optind + 1) {
log_error("Domain specification required.");
r = -EINVAL;
goto finish;
} else if (argc == optind + 1)
r = resolve_service(bus, NULL, NULL, argv[optind]);
else if (argc == optind + 2)
r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
else if (argc == optind + 3)
r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
else {
log_error("Too many arguments.");
r = -EINVAL;
goto finish;
}
break;
case MODE_STATISTICS:
if (argc > optind) {
log_error("Too many arguments.");
r = -EINVAL;
goto finish;
}
r = show_statistics(bus);
break;
case MODE_RESET_STATISTICS:
if (argc > optind) {
log_error("Too many arguments.");
r = -EINVAL;
goto finish;
}
r = reset_statistics(bus);
break;
}
finish:
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}