nslookup.c 5.9 KB

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