nslookup.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. #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. server = xmalloc_sockaddr2dotted_noport((struct sockaddr*)&_res.nsaddr_list[0]);
  98. /* I honestly don't know what to do if DNS server has _IPv6 address_.
  99. * Probably it is listed in
  100. * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each)
  101. * but how to find out whether resolver uses
  102. * _res.nsaddr_list[] or _res._u._ext_.nsaddrs[], or both?
  103. * Looks like classic design from hell, BIND-grade. Hard to surpass. */
  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(char *server)
  112. {
  113. struct in_addr server_in_addr;
  114. if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
  115. _res.nscount = 1;
  116. _res.nsaddr_list[0].sin_addr = server_in_addr;
  117. }
  118. }
  119. int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  120. int nslookup_main(int argc, char **argv)
  121. {
  122. /* We allow 1 or 2 arguments.
  123. * The first is the name to be looked up and the second is an
  124. * optional DNS server with which to do the lookup.
  125. * More than 3 arguments is an error to follow the pattern of the
  126. * standard nslookup */
  127. if (!argv[1] || argv[1][0] == '-' || argc > 3)
  128. bb_show_usage();
  129. /* initialize DNS structure _res used in printing the default
  130. * name server and in the explicit name server option feature. */
  131. res_init();
  132. /* rfc2133 says this enables IPv6 lookups */
  133. /* (but it also says "may be enabled in /etc/resolv.conf") */
  134. /*_res.options |= RES_USE_INET6;*/
  135. if (argv[2])
  136. set_default_dns(argv[2]);
  137. server_print();
  138. return print_host(argv[1], "Name:");
  139. }