whois.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * whois - tiny client for the whois directory service
  4. *
  5. * Copyright (c) 2011 Pere Orga <gotrunks@gmail.com>
  6. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  7. */
  8. /* TODO
  9. * Add ipv6 support
  10. * Add proxy support
  11. */
  12. //config:config WHOIS
  13. //config: bool "whois (6.5 kb)"
  14. //config: default y
  15. //config: help
  16. //config: whois is a client for the whois directory service
  17. //applet:IF_WHOIS(APPLET(whois, BB_DIR_USR_BIN, BB_SUID_DROP))
  18. //kbuild:lib-$(CONFIG_WHOIS) += whois.o
  19. //usage:#define whois_trivial_usage
  20. //usage: "[-i] [-h SERVER] [-p PORT] NAME..."
  21. //usage:#define whois_full_usage "\n\n"
  22. //usage: "Query WHOIS info about NAME\n"
  23. //usage: "\n -i Show redirect results too"
  24. //usage: "\n -h,-p Server to query"
  25. #include "libbb.h"
  26. enum {
  27. OPT_i = (1 << 0),
  28. };
  29. static char *query(const char *host, int port, const char *domain)
  30. {
  31. int fd;
  32. FILE *fp;
  33. bool success;
  34. char *redir = NULL;
  35. const char *pfx = "";
  36. /* some .io domains reported to have very long strings in whois
  37. * responses, 1k was not enough:
  38. */
  39. char linebuf[2 * 1024];
  40. char *buf = NULL;
  41. unsigned bufpos = 0;
  42. again:
  43. printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain);
  44. fd = create_and_connect_stream_or_die(host, port);
  45. fdprintf(fd, "%s%s\r\n", pfx, domain);
  46. fp = xfdopen_for_read(fd);
  47. success = 0;
  48. while (bufpos < 32*1024 /* paranoia */
  49. && fgets(linebuf, sizeof(linebuf)-1, fp)
  50. ) {
  51. unsigned len;
  52. len = strcspn(linebuf, "\r\n");
  53. linebuf[len++] = '\n';
  54. linebuf[len] = '\0';
  55. buf = xrealloc(buf, bufpos + len + 1);
  56. memcpy(buf + bufpos, linebuf, len);
  57. bufpos += len;
  58. buf[bufpos] = '\0';
  59. if (!redir || !success) {
  60. trim(linebuf);
  61. str_tolower(linebuf);
  62. if (!success) {
  63. success = is_prefixed_with(linebuf, "domain:")
  64. || is_prefixed_with(linebuf, "domain name:");
  65. }
  66. else if (!redir) {
  67. char *p = is_prefixed_with(linebuf, "whois server:");
  68. if (!p)
  69. p = is_prefixed_with(linebuf, "whois:");
  70. if (p)
  71. redir = xstrdup(skip_whitespace(p));
  72. }
  73. }
  74. }
  75. fclose(fp); /* closes fd too */
  76. if (!success && !pfx[0]) {
  77. /*
  78. * Looking at /etc/jwhois.conf, some whois servers use
  79. * "domain = DOMAIN", "DOMAIN ID <DOMAIN>"
  80. * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT"
  81. * formats, but those are rare.
  82. * (There are a few even more contrived ones.)
  83. * We are trying only "domain DOMAIN", the typical one.
  84. */
  85. pfx = "domain ";
  86. bufpos = 0;
  87. goto again;
  88. }
  89. /* Success */
  90. if (redir && strcmp(redir, host) == 0) {
  91. /* Redirect to self does not count */
  92. free(redir);
  93. redir = NULL;
  94. }
  95. if (!redir || (option_mask32 & OPT_i)) {
  96. /* Output saved text */
  97. printf("[%s]\n%s", host, buf ? buf : "");
  98. }
  99. free(buf);
  100. return redir;
  101. }
  102. static void recursive_query(const char *host, int port, const char *domain)
  103. {
  104. char *free_me = NULL;
  105. char *redir;
  106. again:
  107. redir = query(host, port, domain);
  108. free(free_me);
  109. if (redir) {
  110. printf("[Redirected to %s]\n", redir);
  111. host = free_me = redir;
  112. port = 43;
  113. goto again;
  114. }
  115. }
  116. /* One of "big" whois implementations has these options:
  117. *
  118. * $ whois --help
  119. * jwhois version 4.0, Copyright (C) 1999-2007 Free Software Foundation, Inc.
  120. * -v, --verbose verbose debug output
  121. * -c FILE, --config=FILE use FILE as configuration file
  122. * -h HOST, --host=HOST explicitly query HOST
  123. * -n, --no-redirect disable content redirection
  124. * -s, --no-whoisservers disable whois-servers.net service support
  125. * -a, --raw disable reformatting of the query
  126. * -i, --display-redirections display all redirects instead of hiding them
  127. * -p PORT, --port=PORT use port number PORT (in conjunction with HOST)
  128. * -r, --rwhois force an rwhois query to be made
  129. * --rwhois-display=DISPLAY sets the display option in rwhois queries
  130. * --rwhois-limit=LIMIT sets the maximum number of matches to return
  131. *
  132. * Example of its output:
  133. * $ whois cnn.com
  134. * [Querying whois.verisign-grs.com]
  135. * [Redirected to whois.corporatedomains.com]
  136. * [Querying whois.corporatedomains.com]
  137. * [whois.corporatedomains.com]
  138. * ...text of the reply...
  139. *
  140. * With -i, reply from each server is printed, after all redirects are done:
  141. * [Querying whois.verisign-grs.com]
  142. * [Redirected to whois.corporatedomains.com]
  143. * [Querying whois.corporatedomains.com]
  144. * [whois.verisign-grs.com]
  145. * ...text of the reply...
  146. * [whois.corporatedomains.com]
  147. * ...text of the reply...
  148. *
  149. * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted.
  150. * With -n, the first reply is shown, redirects are not followed:
  151. * [Querying whois.verisign-grs.com]
  152. * [whois.verisign-grs.com]
  153. * ...text of the reply...
  154. */
  155. int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  156. int whois_main(int argc UNUSED_PARAM, char **argv)
  157. {
  158. int port = 43;
  159. const char *host = "whois.iana.org";
  160. getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port);
  161. argv += optind;
  162. do {
  163. recursive_query(host, port, *argv);
  164. }
  165. while (*++argv);
  166. return EXIT_SUCCESS;
  167. }