[git commit] whois: make it actually work

Denys Vlasenko vda.linux at googlemail.com
Wed Jul 6 13:45:41 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=1035c92e2d1c017eab7cb10badb7e3b407aeba2d
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

It was doing way too simplistic work of just querying the server,
no redirects, no query massaging. This required user to know a lot about whois,
and enter at least three queries for each host to get meaningful information.

function                                             old     new   delta
whois_main                                           209     646    +437

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/whois.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 124 insertions(+), 13 deletions(-)

diff --git a/networking/whois.c b/networking/whois.c
index bf33033..5ef8367 100644
--- a/networking/whois.c
+++ b/networking/whois.c
@@ -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);
 


More information about the busybox-cvs mailing list