nslookup.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 source tree.
  12. */
  13. //config:config NSLOOKUP
  14. //config: bool "nslookup (4.5 kb)"
  15. //config: default y
  16. //config: help
  17. //config: nslookup is a tool to query Internet name servers.
  18. //applet:IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
  19. //kbuild:lib-$(CONFIG_NSLOOKUP) += nslookup.o
  20. //usage:#define nslookup_trivial_usage
  21. //usage: "[HOST] [SERVER]"
  22. //usage:#define nslookup_full_usage "\n\n"
  23. //usage: "Query the nameserver for the IP address of the given HOST\n"
  24. //usage: "optionally using a specified DNS server"
  25. //usage:
  26. //usage:#define nslookup_example_usage
  27. //usage: "$ nslookup localhost\n"
  28. //usage: "Server: default\n"
  29. //usage: "Address: default\n"
  30. //usage: "\n"
  31. //usage: "Name: debian\n"
  32. //usage: "Address: 127.0.0.1\n"
  33. #include <resolv.h>
  34. #include "libbb.h"
  35. /*
  36. * I'm only implementing non-interactive mode;
  37. * I totally forgot nslookup even had an interactive mode.
  38. *
  39. * This applet is the only user of res_init(). Without it,
  40. * you may avoid pulling in _res global from libc.
  41. */
  42. /* Examples of 'standard' nslookup output
  43. * $ nslookup yahoo.com
  44. * Server: 128.193.0.10
  45. * Address: 128.193.0.10#53
  46. *
  47. * Non-authoritative answer:
  48. * Name: yahoo.com
  49. * Address: 216.109.112.135
  50. * Name: yahoo.com
  51. * Address: 66.94.234.13
  52. *
  53. * $ nslookup 204.152.191.37
  54. * Server: 128.193.4.20
  55. * Address: 128.193.4.20#53
  56. *
  57. * Non-authoritative answer:
  58. * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa.
  59. * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org.
  60. *
  61. * Authoritative answers can be found from:
  62. * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org.
  63. * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org.
  64. * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org.
  65. * ns1.kernel.org internet address = 140.211.167.34
  66. * ns2.kernel.org internet address = 204.152.191.4
  67. * ns3.kernel.org internet address = 204.152.191.36
  68. */
  69. static int print_host(const char *hostname, const char *header)
  70. {
  71. /* We can't use xhost2sockaddr() - we want to get ALL addresses,
  72. * not just one */
  73. struct addrinfo *result = NULL;
  74. int rc;
  75. struct addrinfo hint;
  76. memset(&hint, 0 , sizeof(hint));
  77. /* hint.ai_family = AF_UNSPEC; - zero anyway */
  78. /* Needed. Or else we will get each address thrice (or more)
  79. * for each possible socket type (tcp,udp,raw...): */
  80. hint.ai_socktype = SOCK_STREAM;
  81. // hint.ai_flags = AI_CANONNAME;
  82. rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
  83. if (rc == 0) {
  84. struct addrinfo *cur = result;
  85. unsigned cnt = 0;
  86. printf("%-10s %s\n", header, hostname);
  87. // puts(cur->ai_canonname); ?
  88. while (cur) {
  89. char *dotted, *revhost;
  90. dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr);
  91. revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr);
  92. printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n');
  93. if (revhost) {
  94. puts(revhost);
  95. if (ENABLE_FEATURE_CLEAN_UP)
  96. free(revhost);
  97. }
  98. if (ENABLE_FEATURE_CLEAN_UP)
  99. free(dotted);
  100. cur = cur->ai_next;
  101. }
  102. } else {
  103. #if ENABLE_VERBOSE_RESOLUTION_ERRORS
  104. bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc));
  105. #else
  106. bb_error_msg("can't resolve '%s'", hostname);
  107. #endif
  108. }
  109. if (ENABLE_FEATURE_CLEAN_UP && result)
  110. freeaddrinfo(result);
  111. return (rc != 0);
  112. }
  113. /* lookup the default nameserver and display it */
  114. static void server_print(void)
  115. {
  116. char *server;
  117. struct sockaddr *sa;
  118. #if ENABLE_FEATURE_IPV6
  119. sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
  120. if (!sa)
  121. #endif
  122. sa = (struct sockaddr*)&_res.nsaddr_list[0];
  123. server = xmalloc_sockaddr2dotted_noport(sa);
  124. print_host(server, "Server:");
  125. if (ENABLE_FEATURE_CLEAN_UP)
  126. free(server);
  127. bb_putchar('\n');
  128. }
  129. /* alter the global _res nameserver structure to use
  130. an explicit dns server instead of what is in /etc/resolv.conf */
  131. static void set_default_dns(const char *server)
  132. {
  133. len_and_sockaddr *lsa;
  134. if (!server)
  135. return;
  136. /* NB: this works even with, say, "[::1]:5353"! :) */
  137. lsa = xhost2sockaddr(server, 53);
  138. if (lsa->u.sa.sa_family == AF_INET) {
  139. _res.nscount = 1;
  140. /* struct copy */
  141. _res.nsaddr_list[0] = lsa->u.sin;
  142. }
  143. #if ENABLE_FEATURE_IPV6
  144. /* Hoped libc can cope with IPv4 address there too.
  145. * No such luck, glibc 2.4 segfaults even with IPv6,
  146. * maybe I misunderstand how to make glibc use IPv6 addr?
  147. * (uclibc 0.9.31+ should work) */
  148. if (lsa->u.sa.sa_family == AF_INET6) {
  149. // glibc neither SEGVs nor sends any dgrams with this
  150. // (strace shows no socket ops):
  151. //_res.nscount = 0;
  152. _res._u._ext.nscount = 1;
  153. /* store a pointer to part of malloc'ed lsa */
  154. _res._u._ext.nsaddrs[0] = &lsa->u.sin6;
  155. /* must not free(lsa)! */
  156. }
  157. #endif
  158. }
  159. int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  160. int nslookup_main(int argc, char **argv)
  161. {
  162. /* We allow 1 or 2 arguments.
  163. * The first is the name to be looked up and the second is an
  164. * optional DNS server with which to do the lookup.
  165. * More than 3 arguments is an error to follow the pattern of the
  166. * standard nslookup */
  167. if (!argv[1] || argv[1][0] == '-' || argc > 3)
  168. bb_show_usage();
  169. /* initialize DNS structure _res used in printing the default
  170. * name server and in the explicit name server option feature. */
  171. res_init();
  172. /* rfc2133 says this enables IPv6 lookups */
  173. /* (but it also says "may be enabled in /etc/resolv.conf") */
  174. /*_res.options |= RES_USE_INET6;*/
  175. set_default_dns(argv[2]);
  176. server_print();
  177. /* getaddrinfo and friends are free to request a resolver
  178. * reinitialization. Just in case, set_default_dns() again
  179. * after getaddrinfo (in server_print). This reportedly helps
  180. * with bug 675 "nslookup does not properly use second argument"
  181. * at least on Debian Wheezy and Openwrt AA (eglibc based).
  182. */
  183. set_default_dns(argv[2]);
  184. return print_host(argv[1], "Name:");
  185. }