resolve-host.c revision dad29dff1925a114e20d4eb7b47fca23c4f25fd7
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/***
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen This file is part of systemd.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Copyright 2014 Zbigniew Jędrzejewski-Szmek
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is free software; you can redistribute it and/or modify it
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen under the terms of the GNU Lesser General Public License as published by
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen (at your option) any later version.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is distributed in the hope that it will be useful, but
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Lesser General Public License for more details.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen You should have received a copy of the GNU Lesser General Public License
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen***/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include <arpa/inet.h>
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen#include <net/if.h>
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include <getopt.h>
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include "sd-bus.h"
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen#include "bus-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "bus-error.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "bus-errors.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#include "in-addr-util.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#include "af-list.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#include "build.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#include "resolved-dns-packet.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#include "resolved-def.h"
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int arg_family = AF_UNSPEC;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int arg_ifindex = 0;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int arg_type = 0;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic uint16_t arg_class = 0;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_legend = true;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic uint64_t arg_flags = 0;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void print_source(int ifindex, uint64_t flags) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (!arg_legend)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (ifindex <= 0 && flags == 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen fputs("\n-- Information acquired via", stdout);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (flags != 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen printf(" protocol%s%s%s",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen flags & SD_RESOLVED_DNS ? " DNS" :"",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (ifindex > 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen char ifname[IF_NAMESIZE] = "";
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen printf(" interface %s", strna(if_indextoname(ifindex, ifname)));
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen fputc('.', stdout);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen fputc('\n', stdout);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen}
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int resolve_host(sd_bus *bus, const char *name) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen const char *canonical = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen unsigned c = 0;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen int r, ifindex;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen uint64_t flags;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen assert(name);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_debug("Resolving %s (family %s, ifindex %i).", name, af_to_name(arg_family) ?: "*", arg_ifindex);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_new_method_call(
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen bus,
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen &req,
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "org.freedesktop.resolve1",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "/org/freedesktop/resolve1",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "org.freedesktop.resolve1.Manager",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "ResolveHostname");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_create_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_set_auto_start(req, false);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_create_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_create_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return r;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_read(reply, "i", &ifindex);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_enter_container(reply, 'a', "(iay)");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen const void *a;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen int family;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen size_t sz;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_free_ char *pretty = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen char ifname[IF_NAMESIZE] = "";
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_read(reply, "i", &family);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_read_array(reply, 'y', &a, &sz);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_exit_container(reply);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (!IN_SET(family, AF_INET, AF_INET6)) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen continue;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (sz != FAMILY_ADDRESS_SIZE(family)) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_error("%s: systemd-resolved returned address of invalid size %zu for family %s",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen name, sz, af_to_name(family) ?: "unknown");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen continue;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (ifindex > 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen char *t;
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen t = if_indextoname(ifindex, ifname);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (!t) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen log_error("Failed to resolve interface name for index %i", ifindex);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen continue;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen }
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen }
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = in_addr_to_string(family, a, &pretty);
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen if (r < 0) {
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen log_error("%s: failed to print address: %s", name, strerror(-r));
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen continue;
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen }
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen printf("%*s%s %s%s%s\n",
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen pretty,
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen isempty(ifname) ? "" : "%", ifname);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen c++;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_exit_container(reply);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen r = sd_bus_message_read(reply, "st", &canonical, &flags);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_parse_error(r);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (!streq(name, canonical)) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen printf("%*s%s (%s)\n",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen canonical);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (c == 0) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen log_error("%s: no addresses found", name);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return -ESRCH;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen }
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen print_source(ifindex, flags);
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return 0;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen}
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersenstatic int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen _cleanup_free_ char *pretty = NULL;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen char ifname[IF_NAMESIZE] = "";
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen uint64_t flags;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen unsigned c = 0;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen const char *n;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen int r;
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen assert(bus);
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen assert(IN_SET(family, AF_INET, AF_INET6));
63348d13fae61fefcb29133bfae8371b33cf4b6dTom Gundersen assert(address);
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = in_addr_to_string(family, address, &pretty);
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (r < 0)
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen return log_oom();
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen if (ifindex > 0) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen char *t;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen t = if_indextoname(ifindex, ifname);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (!t) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen log_error("Failed to resolve interface name for index %i", ifindex);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return -errno;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen }
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen }
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_bus_message_new_method_call(
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen bus,
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen &req,
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "org.freedesktop.resolve1",
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "/org/freedesktop/resolve1",
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "org.freedesktop.resolve1.Manager",
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "ResolveAddress");
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return bus_log_create_error(r);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen r = sd_bus_message_set_auto_start(req, false);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return bus_log_create_error(r);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen r = sd_bus_message_append(req, "ii", ifindex, family);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen if (r < 0)
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen return bus_log_create_error(r);
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (r < 0)
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen return bus_log_create_error(r);
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen
r = sd_bus_message_append(req, "t", arg_flags);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
if (r < 0) {
log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
return r;
}
r = sd_bus_message_read(reply, "i", &ifindex);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_enter_container(reply, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
printf("%*s%s%s%s %s\n",
(int) strlen(pretty), c == 0 ? pretty : "",
isempty(ifname) ? "" : "%", ifname,
c == 0 ? ":" : " ",
n);
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, "t", &flags);
if (r < 0)
return bus_log_parse_error(r);
if (c == 0) {
log_error("%s: no names found", pretty);
return -ESRCH;
}
print_source(ifindex, flags);
return 0;
}
static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) {
const char *percent, *a;
int ifi = 0;
int r;
percent = strchr(s, '%');
if (percent) {
r = safe_atoi(percent+1, &ifi);
if (r < 0 || ifi <= 0) {
ifi = if_nametoindex(percent+1);
if (ifi <= 0)
return -EINVAL;
}
a = strndupa(s, percent - s);
} else
a = s;
r = in_addr_from_string_auto(a, family, address);
if (r < 0)
return r;
*ifindex = ifi;
return 0;
}
static int resolve_record(sd_bus *bus, const char *name) {
_cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
unsigned n = 0;
uint64_t flags;
int r, ifindex;
assert(name);
log_debug("Resolving %s %s %s.", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type));
r = sd_bus_message_new_method_call(
bus,
&req,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
"ResolveRecord");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_set_auto_start(req, false);
if (r < 0)
return bus_log_create_error(r);
assert((uint16_t) arg_type == arg_type);
r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, arg_flags);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
if (r < 0) {
log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
return r;
}
r = sd_bus_message_read(reply, "i", &ifindex);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_enter_container(reply, 'a', "(qqay)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_enter_container(reply, 'r', "qqay")) > 0) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
_cleanup_free_ char *s = NULL;
uint16_t c, t;
const void *d;
size_t l;
r = sd_bus_message_read(reply, "qq", &c, &t);
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_read_array(reply, 'y', &d, &l);
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 = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
if (r < 0)
return log_oom();
r = dns_packet_append_blob(p, d, l, NULL);
if (r < 0)
return log_oom();
r = dns_packet_read_rr(p, &rr, NULL);
if (r < 0) {
log_error("Failed to parse RR.");
return r;
}
r = dns_resource_record_to_string(rr, &s);
if (r < 0) {
log_error("Failed to format RR.");
return r;
}
printf("%s\n", s);
n++;
}
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, "t", &flags);
if (r < 0)
return bus_log_parse_error(r);
if (n == 0) {
log_error("%s: no records found", name);
return -ESRCH;
}
print_source(ifindex, flags);
return 0;
}
static void help_dns_types(void) {
int i;
const char *t;
if (arg_legend)
puts("Known dns 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 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...]\n\n"
"Resolve IPv4 or IPv6 addresses.\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 Look on interface\n"
" -p --protocol=PROTOCOL Look via protocol\n"
" -t --type=TYPE Query RR with DNS type\n"
" -c --class=CLASS Query RR with DNS class\n"
" --legend[=BOOL] Do [not] print column headers\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_LEGEND,
};
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", optional_argument, NULL, ARG_LEGEND },
{ "protocol", required_argument, NULL, 'p' },
{}
};
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:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0 /* done */;
case '4':
arg_family = AF_INET;
break;
case '6':
arg_family = AF_INET6;
break;
case 'i':
arg_ifindex = if_nametoindex(optarg);
if (arg_ifindex <= 0) {
log_error("Unknown interfaces %s: %m", optarg);
return -errno;
}
break;
case 't':
if (streq(optarg, "help")) {
help_dns_types();
return 0;
}
arg_type = dns_type_from_string(optarg);
if (arg_type < 0) {
log_error("Failed to parse RR record type %s", optarg);
return arg_type;
}
assert(arg_type > 0 && (uint16_t) arg_type == arg_type);
break;
case 'c':
if (streq(optarg, "help")) {
help_dns_classes();
return 0;
}
r = dns_class_from_string(optarg, &arg_class);
if (r < 0) {
log_error("Failed to parse RR record class %s", optarg);
return r;
}
break;
case ARG_LEGEND:
if (optarg) {
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --legend= argument");
return r;
}
arg_legend = !!r;
} else
arg_legend = false;
break;
case 'p':
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 '?':
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_class == 0)
arg_class = DNS_CLASS_IN;
return 1 /* work to do */;
}
int main(int argc, char **argv) {
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
int r;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
if (optind >= argc) {
log_error("No arguments passed");
r = -EINVAL;
goto finish;
}
r = sd_bus_open_system(&bus);
if (r < 0) {
log_error("sd_bus_open_system: %s", strerror(-r));
goto finish;
}
while (argv[optind]) {
int family, ifindex, k;
union in_addr_union a;
if (arg_type != 0)
k = resolve_record(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++;
}
finish:
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}