1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini nslookup implementation for busybox 4 * 5 * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu 6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> 7 * 8 * Correct default name server display and explicit name server option 9 * added by Ben Zeckel <bzeckel@hmc.edu> June 2001 10 * 11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 12 */ 13 14#include <resolv.h> 15#include "libbb.h" 16 17/* 18 * I'm only implementing non-interactive mode; 19 * I totally forgot nslookup even had an interactive mode. 20 * 21 * This applet is the only user of res_init(). Without it, 22 * you may avoid pulling in _res global from libc. 23 */ 24 25/* Examples of 'standard' nslookup output 26 * $ nslookup yahoo.com 27 * Server: 128.193.0.10 28 * Address: 128.193.0.10#53 29 * 30 * Non-authoritative answer: 31 * Name: yahoo.com 32 * Address: 216.109.112.135 33 * Name: yahoo.com 34 * Address: 66.94.234.13 35 * 36 * $ nslookup 204.152.191.37 37 * Server: 128.193.4.20 38 * Address: 128.193.4.20#53 39 * 40 * Non-authoritative answer: 41 * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa. 42 * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org. 43 * 44 * Authoritative answers can be found from: 45 * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org. 46 * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org. 47 * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org. 48 * ns1.kernel.org internet address = 140.211.167.34 49 * ns2.kernel.org internet address = 204.152.191.4 50 * ns3.kernel.org internet address = 204.152.191.36 51 */ 52 53static int print_host(const char *hostname, const char *header) 54{ 55 /* We can't use xhost2sockaddr() - we want to get ALL addresses, 56 * not just one */ 57 struct addrinfo *result = NULL; 58 int rc; 59 struct addrinfo hint; 60 61 memset(&hint, 0 , sizeof(hint)); 62 /* hint.ai_family = AF_UNSPEC; - zero anyway */ 63 /* Needed. Or else we will get each address thrice (or more) 64 * for each possible socket type (tcp,udp,raw...): */ 65 hint.ai_socktype = SOCK_STREAM; 66 // hint.ai_flags = AI_CANONNAME; 67 rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result); 68 69 if (!rc) { 70 struct addrinfo *cur = result; 71 unsigned cnt = 0; 72 73 printf("%-10s %s\n", header, hostname); 74 // puts(cur->ai_canonname); ? 75 while (cur) { 76 char *dotted, *revhost; 77 dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr); 78 revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr); 79 80 printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n'); 81 if (revhost) { 82 puts(revhost); 83 if (ENABLE_FEATURE_CLEAN_UP) 84 free(revhost); 85 } 86 if (ENABLE_FEATURE_CLEAN_UP) 87 free(dotted); 88 cur = cur->ai_next; 89 } 90 } else { 91#if ENABLE_VERBOSE_RESOLUTION_ERRORS 92 bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc)); 93#else 94 bb_error_msg("can't resolve '%s'", hostname); 95#endif 96 } 97 if (ENABLE_FEATURE_CLEAN_UP) 98 freeaddrinfo(result); 99 return (rc != 0); 100} 101 102/* lookup the default nameserver and display it */ 103static void server_print(void) 104{ 105 char *server; 106 struct sockaddr *sa; 107 108#if ENABLE_FEATURE_IPV6 109 sa = (struct sockaddr*)_res._u._ext.nsaddrs[0]; 110 if (!sa) 111#endif 112 sa = (struct sockaddr*)&_res.nsaddr_list[0]; 113 server = xmalloc_sockaddr2dotted_noport(sa); 114 115 print_host(server, "Server:"); 116 if (ENABLE_FEATURE_CLEAN_UP) 117 free(server); 118 bb_putchar('\n'); 119} 120 121/* alter the global _res nameserver structure to use 122 an explicit dns server instead of what is in /etc/resolv.conf */ 123static void set_default_dns(const char *server) 124{ 125 len_and_sockaddr *lsa; 126 127 /* NB: this works even with, say, "[::1]:5353"! :) */ 128 lsa = xhost2sockaddr(server, 53); 129 130 if (lsa->u.sa.sa_family == AF_INET) { 131 _res.nscount = 1; 132 /* struct copy */ 133 _res.nsaddr_list[0] = lsa->u.sin; 134 } 135#if ENABLE_FEATURE_IPV6 136 /* Hoped libc can cope with IPv4 address there too. 137 * No such luck, glibc 2.4 segfaults even with IPv6, 138 * maybe I misunderstand how to make glibc use IPv6 addr? 139 * (uclibc 0.9.31+ should work) */ 140 if (lsa->u.sa.sa_family == AF_INET6) { 141 // glibc neither SEGVs nor sends any dgrams with this 142 // (strace shows no socket ops): 143 //_res.nscount = 0; 144 _res._u._ext.nscount = 1; 145 /* store a pointer to part of malloc'ed lsa */ 146 _res._u._ext.nsaddrs[0] = &lsa->u.sin6; 147 /* must not free(lsa)! */ 148 } 149#endif 150} 151 152int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 153int nslookup_main(int argc, char **argv) 154{ 155 /* We allow 1 or 2 arguments. 156 * The first is the name to be looked up and the second is an 157 * optional DNS server with which to do the lookup. 158 * More than 3 arguments is an error to follow the pattern of the 159 * standard nslookup */ 160 if (!argv[1] || argv[1][0] == '-' || argc > 3) 161 bb_show_usage(); 162 163 /* initialize DNS structure _res used in printing the default 164 * name server and in the explicit name server option feature. */ 165 res_init(); 166 /* rfc2133 says this enables IPv6 lookups */ 167 /* (but it also says "may be enabled in /etc/resolv.conf") */ 168 /*_res.options |= RES_USE_INET6;*/ 169 170 if (argv[2]) 171 set_default_dns(argv[2]); 172 173 server_print(); 174 return print_host(argv[1], "Name:"); 175} 176