whois: try whois.nic.TLD if TLD.whois-servers.net does not exist

Based on an idea from OpenBSD.
This commit is contained in:
fanf 2015-05-14 10:33:01 +00:00
parent da775e97f7
commit 8fd803db87
2 changed files with 47 additions and 26 deletions

View File

@ -49,17 +49,18 @@ Network Information Centers
.Pp
By default
.Nm
constructs the name of a whois server to use from the top-level domain
automatically discovers the name of a whois server to use
from the top-level domain
.Pq Tn TLD
of the supplied (single) argument, and appending
.Qq Li .whois-servers.net .
This effectively allows a suitable whois server to be selected
automatically for a large number of
.Tn TLDs .
of the supplied (single) argument.
It tries
.Qq Va TLD Ns Li .whois-servers.net
and
.Qq Li whois.nic. Ns Va TLD
and if neither host exists it falls back to its default server.
.Pp
In the event that an IP
address is specified, the whois server will default to the American
Registry for Internet Numbers
If an IP address is specified, the whois server will default to
the American Registry for Internet Numbers
.Pq Tn ARIN .
If a query to
.Tn ARIN
@ -71,9 +72,10 @@ that server will be queried also, provided that the
.Fl Q
option is not specified.
.Pp
If the query is not a domain name or IP address,
If
.Nm
will fall back to
cannot automatically discover a server,
it will fall back to
the host specified in the
.Ev WHOIS_SERVER
or
@ -122,7 +124,7 @@ Use the US non-military federal government database, which contains points of
contact for subdomains of
.Pa .GOV .
.It Fl h Ar host
Use the specified host instead of the default variant.
Use the specified host instead of the default.
Either a host name or an IP address may be specified.
.It Fl i
Use the obsolete Network Solutions Registry for Internet Numbers

View File

@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
#define RNICHOST "whois.ripe.net"
#define PNICHOST "whois.apnic.net"
#define MNICHOST "whois.ra.net"
#define QNICHOST_HEAD "whois.nic."
#define QNICHOST_TAIL ".whois-servers.net"
#define BNICHOST "whois.registro.br"
#define IANAHOST "whois.iana.org"
@ -101,7 +102,7 @@ static const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST,
static const char *port = DEFAULT_PORT;
static char *choose_server(char *);
static struct addrinfo *gethostinfo(char const *host, int exit_on_error);
static struct addrinfo *gethostinfo(char const *host, int exitnoname);
static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3);
static void usage(void);
static void whois(const char *, const char *, int);
@ -214,14 +215,15 @@ main(int argc, char *argv[])
* caller must remember to free(3) the allocated memory.
*
* If the domain is an IPv6 address or has a known suffix, that determines
* the server, else if the TLD is a number, query ARIN, else use
* TLD.whois-server.net. Fail if the domain does not contain '.'.
* the server, else if the TLD is a number, query ARIN, else try a couple of
* formulaic server names. Fail if the domain does not contain '.'.
*/
static char *
choose_server(char *domain)
{
char *pos, *retval;
int i;
struct addrinfo *res;
if (strchr(domain, ':')) {
s_asprintf(&retval, "%s", ANICHOST);
@ -243,15 +245,35 @@ choose_server(char *domain)
--pos;
if (pos <= domain)
return (NULL);
if (isdigit((unsigned char)*++pos))
if (isdigit((unsigned char)*++pos)) {
s_asprintf(&retval, "%s", ANICHOST);
else
s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL);
return (retval);
return (retval);
}
/* Try possible alternative whois server name formulae. */
for (i = 0; ; ++i) {
switch (i) {
case 0:
s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL);
break;
case 1:
s_asprintf(&retval, "%s%s", QNICHOST_HEAD, pos);
break;
default:
return (NULL);
}
res = gethostinfo(retval, 0);
if (res) {
freeaddrinfo(res);
return (retval);
} else {
free(retval);
continue;
}
}
}
static struct addrinfo *
gethostinfo(char const *host, int exit_on_error)
gethostinfo(char const *host, int exit_on_noname)
{
struct addrinfo hints, *res;
int error;
@ -260,13 +282,10 @@ gethostinfo(char const *host, int exit_on_error)
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
error = getaddrinfo(host, port, &hints, &res);
if (error) {
warnx("%s: %s", host, gai_strerror(error));
if (exit_on_error)
exit(EX_NOHOST);
return (NULL);
}
if (error && (exit_on_noname || error != EAI_NONAME))
err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
return (res);
}