1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
22 #include <arpa/inet.h>
28 #include "bus-error.h"
29 #include "bus-errors.h"
30 #include "in-addr-util.h"
34 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
36 static int arg_family = AF_UNSPEC;
37 static int arg_ifindex = 0;
39 static int resolve_host(sd_bus *bus, const char *name, int _family, int _ifindex) {
41 _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
42 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
48 log_debug("Resolving %s (family %s)",
49 name, af_to_name(_family));
51 r = sd_bus_message_new_method_call(
54 "org.freedesktop.resolve1",
55 "/org/freedesktop/resolve1",
56 "org.freedesktop.resolve1.Manager",
59 log_error("sd_bus_message_new_method_call: %s", strerror(-r));
63 r = sd_bus_message_set_auto_start(req, false);
65 log_error("sd_bus_message_set_auto_start: %s", strerror(-r));
69 r = sd_bus_message_append(req, "si", name, AF_UNSPEC);
71 log_error("sd_bus_message_append: %s", strerror(-r));
75 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
77 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
81 r = sd_bus_message_enter_container(reply, 'a', "(iayi)");
83 log_error("%s: failed to parse reply: %s", name, bus_error_message(&error, r));
87 while ((r = sd_bus_message_enter_container(reply, 'r', "iayi")) > 0) {
91 _cleanup_free_ char *pretty = NULL;
92 char ifname[IF_NAMESIZE] = "";
94 r = sd_bus_message_read(reply, "i", &family);
96 log_error("Cannot parse message, aborting.");
100 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
102 log_error("Cannot parse message, aborting.");
106 r = sd_bus_message_read(reply, "i", &ifindex);
108 log_error("Cannot parse message, aborting.");
112 r = sd_bus_message_exit_container(reply);
114 log_error("Cannot parse message, aborting.");
118 if ((_family != AF_UNSPEC && family != _family) ||
119 !IN_SET(family, AF_INET, AF_INET6)) {
120 log_debug("%s: skipping entry with family %hu (%s)",
121 name, family, af_to_name(family) ?: "unknown");
125 if (sz != FAMILY_ADDRESS_SIZE(family)) {
126 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s",
127 name, sz, af_to_name(family) ?: "unknown");
132 log_error("%s: systemd-resolved returned invalid interface index %i",
140 t = if_indextoname(ifindex, ifname);
142 log_error("Failed to resolve interface name for index %i", ifindex);
147 if (_ifindex > 0 && ifindex > 0 && ifindex != _ifindex) {
148 log_debug("%s: skipping entry with ifindex %i (%s)",
149 name, ifindex, ifname);
153 r = in_addr_to_string(family, a, &pretty);
155 log_error("%s: failed to print address: %s", name, strerror(-r));
159 log_info("%*s%s %s%s%.*s",
160 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
162 *ifname ? "%" : "", (int) sizeof(ifname), *ifname ? ifname: "");
168 log_error("%s: no addresses found", name);
172 return sd_bus_message_exit_container(reply);
175 static void help(void) {
176 printf("%s [OPTIONS...]\n\n"
177 "Resolve IPv4 or IPv6 addresses.\n\n"
179 " -4 Resolve IPv4 addresses\n"
180 " -6 Resolve IPv6 addresses\n"
181 " -i INTERFACE Filter by interface\n"
182 " -h --help Show this help and exit\n"
183 " --version Print version string and exit\n"
184 , program_invocation_short_name
188 static int parse_argv(int argc, char *argv[]) {
193 static const struct option options[] = {
194 { "help", no_argument, NULL, 'h' },
195 { "version", no_argument, NULL, ARG_VERSION },
204 while ((c = getopt_long(argc, argv, "h46i:", options, NULL)) >= 0)
209 return 0; /* done */;
212 puts(PACKAGE_STRING);
213 puts(SYSTEMD_FEATURES);
217 arg_family = AF_INET;
221 arg_family = AF_INET6;
225 arg_ifindex = if_nametoindex(optarg);
226 if (arg_ifindex <= 0) {
227 log_error("Unknown interfaces %s: %m", optarg);
236 assert_not_reached("Unhandled option");
239 return 1 /* work to do */;
243 int main(int argc, char **argv) {
244 _cleanup_bus_unref_ sd_bus *bus = NULL;
247 log_parse_environment();
250 r = parse_argv(argc, argv);
254 r = sd_bus_open_system(&bus);
256 log_error("sd_bus_open_system: %s", strerror(-r));
260 while (argv[optind]) {
263 k = resolve_host(bus, argv[optind++], arg_family, arg_ifindex);
269 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;