whois: make it actually work
No binary (build failed)
—
(log yok)
| @@ -28,36 +28,147 @@ | |
| #include "libbb.h" | |
| - | static void pipe_out(int fd) |
| + | static char *query(const char *host, int port, const char *domain) |
| { | |
| + | int fd; |
| FILE *fp; | |
| - | char buf[1024]; |
| + | bool success; |
| + | char *redir = NULL; |
| + | const char *pfx = ""; |
| + | char linebuf[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); |
| + | success = 0; |
| + | fdprintf(fd, "%s%s\r\n", pfx, domain); |
| fp = xfdopen_for_read(fd); | |
| - | while (fgets(buf, sizeof(buf), fp)) { |
| - | char *p = strpbrk(buf, "\r\n"); |
| - | if (p) |
| - | *p = '\0'; |
| - | puts(buf); |
| - | } |
| + | while (fgets(linebuf, sizeof(linebuf), fp)) { |
| + | unsigned len = strcspn(linebuf, "\r\n"); |
| + | linebuf[len++] = '\n'; |
| + | |
| + | buf = xrealloc(buf, bufpos + len + 1); |
| + | memcpy(buf + bufpos, linebuf, len); |
| + | bufpos += len; |
| + | |
| + | 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 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) { |
| + | /* Output saved text */ |
| + | printf("[%s]\n", host); |
| + | buf[bufpos] = '\0'; |
| + | fputs(buf, stdout); |
| + | } |
| + | 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-servers.net"; |
| + | const char *host = "whois.iana.org"; |
| opt_complementary = "-1:p+"; | |
| getopt32(argv, "h:p:", &host, &port); | |
| - | |
| argv += optind; | |
| + | |
| do { | |
| - | int fd = create_and_connect_stream_or_die(host, port); |
| - | fdprintf(fd, "%s\r\n", *argv); |
| - | pipe_out(fd); |
| + | recursive_query(host, port, *argv); |
| } | |
| while (*++argv); | |