• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 1998 Massachusetts Institute of Technology
4  * Copyright (c) The c-ares project and its contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * SPDX-License-Identifier: MIT
26  */
27 
28 #include "ares_setup.h"
29 
30 #if !defined(_WIN32) || defined(WATT32)
31 #  include <netinet/in.h>
32 #  include <arpa/inet.h>
33 #  include <netdb.h>
34 #endif
35 
36 #ifdef HAVE_STRINGS_H
37 #  include <strings.h>
38 #endif
39 
40 #include "ares.h"
41 #include "ares_dns.h"
42 #include "ares_getopt.h"
43 #include "ares_ipv6.h"
44 
45 #include "ares_str.h"
46 
47 static void callback(void *arg, int status, int timeouts, struct hostent *host);
48 static void ai_callback(void *arg, int status, int timeouts,
49                         struct ares_addrinfo *result);
50 static void usage(void);
51 static void print_help_info_ahost(void);
52 
main(int argc,char ** argv)53 int         main(int argc, char **argv)
54 {
55   struct ares_options  options;
56   int                  optmask = 0;
57   ares_channel_t      *channel;
58   int                  status;
59   int                  nfds;
60   int                  c;
61   int                  addr_family = AF_UNSPEC;
62   fd_set               read_fds;
63   fd_set               write_fds;
64   struct timeval      *tvp;
65   struct timeval       tv;
66   struct in_addr       addr4;
67   struct ares_in6_addr addr6;
68   ares_getopt_state_t  state;
69   char                *servers = NULL;
70 
71 #ifdef USE_WINSOCK
72   WORD    wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
73   WSADATA wsaData;
74   WSAStartup(wVersionRequested, &wsaData);
75 #endif
76 
77   memset(&options, 0, sizeof(options));
78 
79   status = ares_library_init(ARES_LIB_INIT_ALL);
80   if (status != ARES_SUCCESS) {
81     fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status));
82     return 1;
83   }
84 
85   ares_getopt_init(&state, argc, (const char * const *)argv);
86   while ((c = ares_getopt(&state, "dt:h?D:s:")) != -1) {
87     switch (c) {
88       case 'd':
89 #ifdef WATT32
90         dbug_init();
91 #endif
92         break;
93       case 'D':
94         optmask |= ARES_OPT_DOMAINS;
95         options.ndomains++;
96         options.domains = (char **)realloc(
97           options.domains, (size_t)options.ndomains * sizeof(char *));
98         options.domains[options.ndomains - 1] = strdup(state.optarg);
99         break;
100       case 't':
101         if (ares_strcaseeq(state.optarg, "a")) {
102           addr_family = AF_INET;
103         } else if (ares_strcaseeq(state.optarg, "aaaa")) {
104           addr_family = AF_INET6;
105         } else if (ares_strcaseeq(state.optarg, "u")) {
106           addr_family = AF_UNSPEC;
107         } else {
108           usage();
109         }
110         break;
111       case 's':
112         if (state.optarg == NULL) {
113           fprintf(stderr, "%s", "missing servers");
114           usage();
115           break;
116         }
117         if (servers) {
118           free(servers);
119         }
120         servers = strdup(state.optarg);
121         break;
122       case 'h':
123       case '?':
124         print_help_info_ahost();
125         break;
126       default:
127         usage();
128         break;
129     }
130   }
131 
132   argc -= state.optind;
133   argv += state.optind;
134   if (argc < 1) {
135     usage();
136   }
137 
138   status = ares_init_options(&channel, &options, optmask);
139   if (status != ARES_SUCCESS) {
140     free(servers);
141     fprintf(stderr, "ares_init: %s\n", ares_strerror(status));
142     return 1;
143   }
144 
145   if (servers) {
146     status = ares_set_servers_csv(channel, servers);
147     if (status != ARES_SUCCESS) {
148       fprintf(stderr, "ares_set_serveres_csv: %s\n", ares_strerror(status));
149       free(servers);
150       usage();
151       return 1;
152     }
153     free(servers);
154   }
155 
156   /* Initiate the queries, one per command-line argument. */
157   for (; *argv; argv++) {
158     if (ares_inet_pton(AF_INET, *argv, &addr4) == 1) {
159       ares_gethostbyaddr(channel, &addr4, sizeof(addr4), AF_INET, callback,
160                          *argv);
161     } else if (ares_inet_pton(AF_INET6, *argv, &addr6) == 1) {
162       ares_gethostbyaddr(channel, &addr6, sizeof(addr6), AF_INET6, callback,
163                          *argv);
164     } else {
165       struct ares_addrinfo_hints hints;
166       memset(&hints, 0, sizeof(hints));
167       hints.ai_family = addr_family;
168       ares_getaddrinfo(channel, *argv, NULL, &hints, ai_callback, *argv);
169     }
170   }
171 
172   /* Wait for all queries to complete. */
173   for (;;) {
174     int res;
175     FD_ZERO(&read_fds);
176     FD_ZERO(&write_fds);
177     nfds = ares_fds(channel, &read_fds, &write_fds);
178     if (nfds == 0) {
179       break;
180     }
181     tvp = ares_timeout(channel, NULL, &tv);
182     if (tvp == NULL) {
183       break;
184     }
185     res = select(nfds, &read_fds, &write_fds, NULL, tvp);
186     if (-1 == res) {
187       break;
188     }
189     ares_process(channel, &read_fds, &write_fds);
190   }
191 
192   ares_destroy(channel);
193 
194   ares_library_cleanup();
195 
196 #ifdef USE_WINSOCK
197   WSACleanup();
198 #endif
199 
200   return 0;
201 }
202 
callback(void * arg,int status,int timeouts,struct hostent * host)203 static void callback(void *arg, int status, int timeouts, struct hostent *host)
204 {
205   char **p;
206 
207   (void)timeouts;
208 
209   if (status != ARES_SUCCESS) {
210     fprintf(stderr, "%s: %s\n", (char *)arg, ares_strerror(status));
211     return;
212   }
213 
214   for (p = host->h_addr_list; *p; p++) {
215     char addr_buf[46] = "??";
216 
217     ares_inet_ntop(host->h_addrtype, *p, addr_buf, sizeof(addr_buf));
218     printf("%-32s\t%s", host->h_name, addr_buf);
219     puts("");
220   }
221 }
222 
ai_callback(void * arg,int status,int timeouts,struct ares_addrinfo * result)223 static void ai_callback(void *arg, int status, int timeouts,
224                         struct ares_addrinfo *result)
225 {
226   struct ares_addrinfo_node *node = NULL;
227   (void)timeouts;
228 
229 
230   if (status != ARES_SUCCESS) {
231     fprintf(stderr, "%s: %s\n", (char *)arg, ares_strerror(status));
232     return;
233   }
234 
235   for (node = result->nodes; node != NULL; node = node->ai_next) {
236     char        addr_buf[64] = "";
237     const void *ptr          = NULL;
238     if (node->ai_family == AF_INET) {
239       const struct sockaddr_in *in_addr =
240         (const struct sockaddr_in *)((void *)node->ai_addr);
241       ptr = &in_addr->sin_addr;
242     } else if (node->ai_family == AF_INET6) {
243       const struct sockaddr_in6 *in_addr =
244         (const struct sockaddr_in6 *)((void *)node->ai_addr);
245       ptr = &in_addr->sin6_addr;
246     } else {
247       continue;
248     }
249     ares_inet_ntop(node->ai_family, ptr, addr_buf, sizeof(addr_buf));
250     printf("%-32s\t%s\n", result->name, addr_buf);
251   }
252 
253   ares_freeaddrinfo(result);
254 }
255 
usage(void)256 static void usage(void)
257 {
258   fprintf(stderr, "usage: ahost [-h] [-d] [[-D {domain}] ...] [-s {server}] "
259                   "[-t {a|aaaa|u}] {host|addr} ...\n");
260   exit(1);
261 }
262 
263 /* Information from the man page. Formatting taken from man -h */
print_help_info_ahost(void)264 static void print_help_info_ahost(void)
265 {
266   /* Split due to maximum c89 string literal of 509 bytes */
267   printf("ahost, version %s\n\n", ARES_VERSION_STR);
268   printf(
269     "usage: ahost [-h] [-d] [-D domain] [-s server] [-t a|aaaa|u] host|addr "
270     "...\n\n");
271   printf(
272     "  -h : Display this help and exit.\n"
273     "  -d : Print some extra debugging output.\n\n"
274     "  -D domain : Specify the domain to search instead of using the default "
275     "values\n");
276   printf(
277     "  -s server : Connect to the specified DNS server, instead of the\n"
278     "              system's default one(s). Servers are tried in round-robin,\n"
279     "              if the previous one failed.\n"
280     "  -t type   : If type is \"a\", print the A record.\n");
281   printf(
282     "              If type is \"aaaa\", print the AAAA record.\n"
283     "              If type is \"u\" (default), print both A and AAAA records.\n"
284     "\n");
285   exit(0);
286 }
287