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