ahost.c (8314B)
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 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 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 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 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 */ 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 }