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 return bus_log_create_error(r);
61 r = sd_bus_message_set_auto_start(req, false);
63 return bus_log_create_error(r);
65 r = sd_bus_message_append(req, "si", name, AF_UNSPEC);
67 return bus_log_create_error(r);
69 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
71 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
75 r = sd_bus_message_enter_container(reply, 'a', "(iayi)");
77 return bus_log_parse_error(r);
79 while ((r = sd_bus_message_enter_container(reply, 'r', "iayi")) > 0) {
83 _cleanup_free_ char *pretty = NULL;
84 char ifname[IF_NAMESIZE] = "";
86 r = sd_bus_message_read(reply, "i", &family);
88 return bus_log_parse_error(r);
90 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
92 return bus_log_parse_error(r);
94 r = sd_bus_message_read(reply, "i", &ifindex);
96 return bus_log_parse_error(r);
98 r = sd_bus_message_exit_container(reply);
100 return bus_log_parse_error(r);
102 if ((_family != AF_UNSPEC && family != _family) ||
103 !IN_SET(family, AF_INET, AF_INET6)) {
104 log_debug("%s: skipping entry with family %hu (%s)",
105 name, family, af_to_name(family) ?: "unknown");
109 if (sz != FAMILY_ADDRESS_SIZE(family)) {
110 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s",
111 name, sz, af_to_name(family) ?: "unknown");
116 log_error("%s: systemd-resolved returned invalid interface index %i",
124 t = if_indextoname(ifindex, ifname);
126 log_error("Failed to resolve interface name for index %i", ifindex);
131 if (_ifindex > 0 && ifindex > 0 && ifindex != _ifindex) {
132 log_debug("%s: skipping entry with ifindex %i (%s)",
133 name, ifindex, ifname);
137 r = in_addr_to_string(family, a, &pretty);
139 log_error("%s: failed to print address: %s", name, strerror(-r));
143 log_info("%*s%s %s%s%.*s",
144 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
146 *ifname ? "%" : "", (int) sizeof(ifname), *ifname ? ifname: "");
152 log_error("%s: no addresses found", name);
156 r = sd_bus_message_exit_container(reply);
158 return bus_log_parse_error(r);
163 static void help(void) {
164 printf("%s [OPTIONS...]\n\n"
165 "Resolve IPv4 or IPv6 addresses.\n\n"
167 " -4 Resolve IPv4 addresses\n"
168 " -6 Resolve IPv6 addresses\n"
169 " -i INTERFACE Filter by interface\n"
170 " -h --help Show this help and exit\n"
171 " --version Print version string and exit\n"
172 , program_invocation_short_name
176 static int parse_argv(int argc, char *argv[]) {
181 static const struct option options[] = {
182 { "help", no_argument, NULL, 'h' },
183 { "version", no_argument, NULL, ARG_VERSION },
192 while ((c = getopt_long(argc, argv, "h46i:", options, NULL)) >= 0)
197 return 0; /* done */;
200 puts(PACKAGE_STRING);
201 puts(SYSTEMD_FEATURES);
205 arg_family = AF_INET;
209 arg_family = AF_INET6;
213 arg_ifindex = if_nametoindex(optarg);
214 if (arg_ifindex <= 0) {
215 log_error("Unknown interfaces %s: %m", optarg);
224 assert_not_reached("Unhandled option");
227 return 1 /* work to do */;
230 int main(int argc, char **argv) {
231 _cleanup_bus_unref_ sd_bus *bus = NULL;
234 log_parse_environment();
237 r = parse_argv(argc, argv);
241 r = sd_bus_open_system(&bus);
243 log_error("sd_bus_open_system: %s", strerror(-r));
247 while (argv[optind]) {
250 k = resolve_host(bus, argv[optind++], arg_family, arg_ifindex);
256 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;