nslookup.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. /* Examples of 'standard' nslookup output
  20. * $ nslookup yahoo.com
  21. * Server: 128.193.0.10
  22. * Address: 128.193.0.10#53
  23. *
  24. * Non-authoritative answer:
  25. * Name: yahoo.com
  26. * Address: 216.109.112.135
  27. * Name: yahoo.com
  28. * Address: 66.94.234.13
  29. *
  30. * $ nslookup 204.152.191.37
  31. * Server: 128.193.4.20
  32. * Address: 128.193.4.20#53
  33. *
  34. * Non-authoritative answer:
  35. * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa.
  36. * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org.
  37. *
  38. * Authoritative answers can be found from:
  39. * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org.
  40. * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org.
  41. * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org.
  42. * ns1.kernel.org internet address = 140.211.167.34
  43. * ns2.kernel.org internet address = 204.152.191.4
  44. * ns3.kernel.org internet address = 204.152.191.36
  45. */
  46. static int print_host(const char *hostname, const char *header)
  47. {
  48. /* We can't use xhost2sockaddr() - we want to get ALL addresses,
  49. * not just one */
  50. struct addrinfo *result = NULL;
  51. int rc;
  52. struct addrinfo hint;
  53. memset(&hint, 0 , sizeof(hint));
  54. /* hint.ai_family = AF_UNSPEC; - zero anyway */
  55. /* Needed. Or else we will get each address thrice (or more)
  56. * for each possible socket type (tcp,udp,raw...): */
  57. hint.ai_socktype = SOCK_STREAM;
  58. // hint.ai_flags = AI_CANONNAME;
  59. rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
  60. if (!rc) {
  61. struct addrinfo *cur = result;
  62. unsigned cnt = 0;
  63. printf("%-10s %s\n", header, hostname);
  64. // puts(cur->ai_canonname); ?
  65. while (cur) {
  66. char *dotted, *revhost;
  67. dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr);
  68. revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr);
  69. printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n');
  70. if (revhost) {
  71. puts(revhost);
  72. if (ENABLE_FEATURE_CLEAN_UP)
  73. free(revhost);
  74. }
  75. if (ENABLE_FEATURE_CLEAN_UP)
  76. free(dotted);
  77. cur = cur->ai_next;
  78. }
  79. } else {
  80. #if ENABLE_VERBOSE_RESOLUTION_ERRORS
  81. bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc));
  82. #else
  83. bb_error_msg("can't resolve '%s'", hostname);
  84. #endif
  85. }
  86. if (ENABLE_FEATURE_CLEAN_UP)
  87. freeaddrinfo(result);
  88. return (rc != 0);
  89. }
  90. /* lookup the default nameserver and display it */
  91. static void server_print(void)
  92. {
  93. char *server;
  94. server = xmalloc_sockaddr2dotted_noport((struct sockaddr*)&_res.nsaddr_list[0]);
  95. /* I honestly don't know what to do if DNS server has _IPv6 address_.
  96. * Probably it is listed in
  97. * _res._u._ext_.nsaddrs[MAXNS] (of type "struct sockaddr_in6*" each)
  98. * but how to find out whether resolver uses
  99. * _res.nsaddr_list[] or _res._u._ext_.nsaddrs[], or both?
  100. * Looks like classic design from hell, BIND-grade. Hard to surpass. */
  101. print_host(server, "Server:");
  102. if (ENABLE_FEATURE_CLEAN_UP)
  103. free(server);
  104. bb_putchar('\n');
  105. }
  106. /* alter the global _res nameserver structure to use
  107. an explicit dns server instead of what is in /etc/resolv.h */
  108. static void set_default_dns(char *server)
  109. {
  110. struct in_addr server_in_addr;
  111. if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
  112. _res.nscount = 1;
  113. _res.nsaddr_list[0].sin_addr = server_in_addr;
  114. }
  115. }
  116. int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  117. int nslookup_main(int argc, char **argv)
  118. {
  119. /* We allow 1 or 2 arguments.
  120. * The first is the name to be looked up and the second is an
  121. * optional DNS server with which to do the lookup.
  122. * More than 3 arguments is an error to follow the pattern of the
  123. * standard nslookup */
  124. if (argc < 2 || *argv[1] == '-' || argc > 3)
  125. bb_show_usage();
  126. /* initialize DNS structure _res used in printing the default
  127. * name server and in the explicit name server option feature. */
  128. res_init();
  129. /* rfc2133 says this enables IPv6 lookups */
  130. /* (but it also says "may be enabled in /etc/resolv.conf|) */
  131. /*_res.options |= RES_USE_INET6;*/
  132. if (argc == 3)
  133. set_default_dns(argv[2]);
  134. server_print();
  135. return print_host(argv[1], "Name:");
  136. }