nslookup.c 5.0 KB

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