| /* vi: set sw=4 ts=4: */ |
| /* |
| * whois - tiny client for the whois directory service |
| * |
| * Copyright (c) 2011 Pere Orga <gotrunks@gmail.com> |
| * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
| */ |
| /* TODO |
| * Add ipv6 support |
| * Add proxy support |
| */ |
| //config:config WHOIS |
| //config: bool "whois (6.3 kb)" |
| //config: default y |
| //config: help |
| //config: whois is a client for the whois directory service |
| |
| //applet:IF_WHOIS(APPLET(whois, BB_DIR_USR_BIN, BB_SUID_DROP)) |
| |
| //kbuild:lib-$(CONFIG_WHOIS) += whois.o |
| |
| //usage:#define whois_trivial_usage |
| //usage: "[-i] [-h SERVER] [-p PORT] NAME..." |
| //usage:#define whois_full_usage "\n\n" |
| //usage: "Query WHOIS info about NAME\n" |
| //usage: "\n -i Show redirect results too" |
| //usage: "\n -h,-p Server to query" |
| |
| #include "libbb.h" |
| |
| enum { |
| OPT_i = (1 << 0), |
| }; |
| |
| static char *query(const char *host, int port, const char *domain) |
| { |
| int fd; |
| FILE *fp; |
| bool success; |
| char *redir = NULL; |
| const char *pfx = ""; |
| /* some .io domains reported to have very long strings in whois |
| * responses, 1k was not enough: |
| */ |
| char linebuf[2 * 1024]; |
| char *buf = NULL; |
| unsigned bufpos = 0; |
| |
| again: |
| printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain); |
| fd = create_and_connect_stream_or_die(host, port); |
| fdprintf(fd, "%s%s\r\n", pfx, domain); |
| fp = xfdopen_for_read(fd); |
| |
| success = 0; |
| while (bufpos < 32*1024 /* paranoia */ |
| && fgets(linebuf, sizeof(linebuf)-1, fp) |
| ) { |
| unsigned len; |
| |
| len = strcspn(linebuf, "\r\n"); |
| linebuf[len++] = '\n'; |
| linebuf[len] = '\0'; |
| |
| buf = xrealloc(buf, bufpos + len + 1); |
| memcpy(buf + bufpos, linebuf, len); |
| bufpos += len; |
| buf[bufpos] = '\0'; |
| |
| if (!redir || !success) { |
| trim(linebuf); |
| str_tolower(linebuf); |
| if (!success) { |
| success = is_prefixed_with(linebuf, "domain:") |
| || is_prefixed_with(linebuf, "domain name:"); |
| } |
| else if (!redir) { |
| char *p = is_prefixed_with(linebuf, "whois server:"); |
| if (!p) |
| p = is_prefixed_with(linebuf, "whois:"); |
| if (p) |
| redir = xstrdup(skip_whitespace(p)); |
| } |
| } |
| } |
| fclose(fp); /* closes fd too */ |
| if (!success && !pfx[0]) { |
| /* |
| * Looking at /etc/jwhois.conf, some whois servers use |
| * "domain = DOMAIN", "DOMAIN ID <DOMAIN>" |
| * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT" |
| * formats, but those are rare. |
| * (There are a few even more contrived ones.) |
| * We are trying only "domain DOMAIN", the typical one. |
| */ |
| pfx = "domain "; |
| bufpos = 0; |
| goto again; |
| } |
| |
| /* Success */ |
| if (redir && strcmp(redir, host) == 0) { |
| /* Redirect to self does not count */ |
| free(redir); |
| redir = NULL; |
| } |
| if (!redir || (option_mask32 & OPT_i)) { |
| /* Output saved text */ |
| printf("[%s]\n%s", host, buf ? buf : ""); |
| } |
| free(buf); |
| return redir; |
| } |
| |
| static void recursive_query(const char *host, int port, const char *domain) |
| { |
| char *free_me = NULL; |
| char *redir; |
| again: |
| redir = query(host, port, domain); |
| free(free_me); |
| if (redir) { |
| printf("[Redirected to %s]\n", redir); |
| host = free_me = redir; |
| port = 43; |
| goto again; |
| } |
| } |
| |
| /* One of "big" whois implementations has these options: |
| * |
| * $ whois --help |
| * jwhois version 4.0, Copyright (C) 1999-2007 Free Software Foundation, Inc. |
| * -v, --verbose verbose debug output |
| * -c FILE, --config=FILE use FILE as configuration file |
| * -h HOST, --host=HOST explicitly query HOST |
| * -n, --no-redirect disable content redirection |
| * -s, --no-whoisservers disable whois-servers.net service support |
| * -a, --raw disable reformatting of the query |
| * -i, --display-redirections display all redirects instead of hiding them |
| * -p PORT, --port=PORT use port number PORT (in conjunction with HOST) |
| * -r, --rwhois force an rwhois query to be made |
| * --rwhois-display=DISPLAY sets the display option in rwhois queries |
| * --rwhois-limit=LIMIT sets the maximum number of matches to return |
| * |
| * Example of its output: |
| * $ whois cnn.com |
| * [Querying whois.verisign-grs.com] |
| * [Redirected to whois.corporatedomains.com] |
| * [Querying whois.corporatedomains.com] |
| * [whois.corporatedomains.com] |
| * ...text of the reply... |
| * |
| * With -i, reply from each server is printed, after all redirects are done: |
| * [Querying whois.verisign-grs.com] |
| * [Redirected to whois.corporatedomains.com] |
| * [Querying whois.corporatedomains.com] |
| * [whois.verisign-grs.com] |
| * ...text of the reply... |
| * [whois.corporatedomains.com] |
| * ...text of the reply... |
| * |
| * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted. |
| |
| * With -n, the first reply is shown, redirects are not followed: |
| * [Querying whois.verisign-grs.com] |
| * [whois.verisign-grs.com] |
| * ...text of the reply... |
| */ |
| |
| int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int whois_main(int argc UNUSED_PARAM, char **argv) |
| { |
| int port = 43; |
| const char *host = "whois.iana.org"; |
| |
| getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port); |
| argv += optind; |
| |
| do { |
| recursive_query(host, port, *argv); |
| } |
| while (*++argv); |
| |
| return EXIT_SUCCESS; |
| } |