bin/133227: Add support for SLD whois server lookups and IPv6 address lookups

Aragon Gouveia aragon at phat.za.net
Mon Mar 30 16:00:10 PDT 2009


>Number:         133227
>Category:       bin
>Synopsis:       Add support for SLD whois server lookups and IPv6 address lookups
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Mar 30 23:00:09 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Aragon Gouveia
>Release:        7.1-STABLE
>Organization:
>Environment:
FreeBSD igor.geek.sh 7.1-STABLE FreeBSD 7.1-STABLE #3: Wed Mar 11 14:24:50 SAST 2009     root at igor.geek.sh:/usr/src/sys/amd64/compile/IGOR  amd64
>Description:
When performing a domain name whois lookup, whois(1) performs a DNS lookup on <tld>.whois-servers.net to discover the authoritative whois server address.  This does not cater for some TLD registries that do not operate a TLD whois server, but operate one or many SLD whois servers below said TLD.  For example:

domain test.co.za
$ host za.whois-servers.net
Host za.whois-servers.net not found: 3(NXDOMAIN)
$ host co.za.whois-servers.net
co.za.whois-servers.net is an alias for whois.coza.net.za.
$ whois test.co.za
whois: za.whois-servers.net: hostname nor servname provided, or not known

The attached patch resolves this by first attempting to resolve co.za.whois-servers.net and using it if it resolves.  If not found, it will attempt za.whois-servers.net as normal.

In addition I have also integrated PR bin/128725 into my patch so that whois treats IPv6 address lookups the same as IPv4 addresses (sending the query to ARIN's whois server).

>How-To-Repeat:

>Fix:


Patch attached with submission follows:

--- whois.c.orig	2007-04-14 16:32:48.000000000 +0200
+++ whois.c	2009-03-31 00:42:33.000000000 +0200
@@ -91,7 +91,7 @@
 			   FNICHOST, NULL };
 const char *port = DEFAULT_PORT;
 
-static char *choose_server(char *);
+static struct addrinfo *choose_hostinfo(const char *domain, char const **hostname);
 static struct addrinfo *gethostinfo(char const *host, int exit_on_error);
 static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3);
 static void usage(void);
@@ -187,7 +187,6 @@
 	 */
 	if (host == NULL && country == NULL) {
 		use_qnichost = 1;
-		host = NICHOST;
 		if (!(flags & WHOIS_QUICK))
 			flags |= WHOIS_RECURSE;
 	}
@@ -195,29 +194,41 @@
 		if (country != NULL) {
 			s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
 			whois(*argv, qnichost, flags);
-		} else if (use_qnichost)
-			if ((qnichost = choose_server(*argv)) != NULL)
-				whois(*argv, qnichost, flags);
-		if (qnichost == NULL)
+			free(qnichost);
+			qnichost = NULL;
+		} else if (use_qnichost) {
+			whois(*argv, NULL, flags);
+		} else {
 			whois(*argv, host, flags);
-		free(qnichost);
-		qnichost = NULL;
+		}
 		argv++;
 	}
 	exit(0);
 }
 
 /*
- * This function will remove any trailing periods from domain, after which it
- * returns a pointer to newly allocated memory containing the whois server to
- * be queried, or a NULL if the correct server couldn't be determined.  The
- * caller must remember to free(3) the allocated memory.
+ * This function takes the trailing subdomains of a domain
+ * prepends them to .whois-servers.net and attempts to resolve
+ * them.  Starting from the highest it removes more subdomain
+ * parts until a successful resolution is found, or exits
+ * if none are found.
+ *
+ * However, before doing so it checks if we're doing a NORID,
+ * IP address, or non-hostname lookup.  If so, it resolves
+ * the relevant hostname.
  */
-static char *
-choose_server(char *domain)
+static struct addrinfo *
+choose_hostinfo(const char *domain, char const **hostname)
 {
-	char *pos, *retval;
+	char *pos, *last, *lookup;
+	struct addrinfo *res;
 
+	if (strchr(domain, ':')) {
+		s_asprintf(&lookup, "%s", ANICHOST);
+		res = gethostinfo(lookup, 1);
+		*hostname = lookup;
+		return res;
+	}
 	for (pos = strchr(domain, '\0'); pos > domain && *--pos == '.';)
 		*pos = '\0';
 	if (*domain == '\0')
@@ -225,18 +236,35 @@
 	if (strlen(domain) > sizeof("-NORID")-1 &&
 	    strcasecmp(domain + strlen(domain) - sizeof("-NORID") + 1,
 		"-NORID") == 0) {
-		s_asprintf(&retval, "%s", NORIDHOST);
-		return (retval);
+		s_asprintf(&lookup, "%s", NORIDHOST);
+		res = gethostinfo(lookup, 1);
+		*hostname = lookup;
+		return res;
 	}
-	while (pos > domain && *pos != '.')
-		--pos;
-	if (pos <= domain)
-		return (NULL);
-	if (isdigit((unsigned char)*++pos))
-		s_asprintf(&retval, "%s", ANICHOST);
-	else
-		s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL);
-	return (retval);
+	if (!(last = strrchr(domain, '.'))) {
+		s_asprintf(&lookup, "%s", NICHOST);
+		res = gethostinfo(lookup, 1);
+		*hostname = lookup;
+		return res;
+	}
+	pos = last+1;
+	if (isdigit((unsigned char)*pos)) {
+		s_asprintf(&lookup, "%s", ANICHOST);
+		res = gethostinfo(lookup, 1);
+		*hostname = lookup;
+		return res;
+	}
+	while (pos = strchr(domain, '.')) {
+		domain = ++pos;
+		s_asprintf(&lookup, "%s%s", pos, QNICHOST_TAIL);
+		res = gethostinfo(lookup, pos>last?1:0);
+		if (res) {
+			*hostname = lookup;
+			break;
+		} else
+			free(lookup);
+	}
+	return res;
 }
 
 static struct addrinfo *
@@ -251,9 +279,10 @@
 	hints.ai_socktype = SOCK_STREAM;
 	error = getaddrinfo(host, port, &hints, &res);
 	if (error) {
-		warnx("%s: %s", host, gai_strerror(error));
-		if (exit_on_error)
+		if (exit_on_error) {
+			warnx("%s: %s", host, gai_strerror(error));
 			exit(EX_NOHOST);
+		}
 		return (NULL);
 	}
 	return (res);
@@ -280,12 +309,17 @@
 {
 	FILE *sfi, *sfo;
 	struct addrinfo *hostres, *res;
-	char *buf, *host, *nhost, *p;
+	char *fhost, *buf, *host, *nhost, *p;
 	int i, s;
 	size_t c, len;
 
 	s = -1;
-	hostres = gethostinfo(hostname, 1);
+	fhost = NULL;
+	if (hostname == NULL) {
+		hostres = choose_hostinfo(query, &hostname);
+		fhost = (char *)hostname;
+	} else
+		hostres = gethostinfo(hostname, 1);
 	for (res = hostres; res; res = res->ai_next) {
 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 		if (s < 0)
@@ -353,6 +387,7 @@
 			}
 		}
 	}
+	if (fhost) free(fhost);
 	if (nhost != NULL) {
 		whois(query, nhost, 0);
 		free(nhost);


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list