A few whois usability improvements

Look up AS numbers at ARIN.

Handle more referral formats.

Suppress spammy nameserver objects when querying the .com and .net
whois servers by explicitly querying for domain names by default.
This commit is contained in:
fanf 2016-01-22 16:43:49 +00:00
parent a75e74c454
commit 8ba35e7674
2 changed files with 80 additions and 56 deletions

View File

@ -59,18 +59,10 @@ and
.Qq Li whois.nic. Ns Va TLD
and if neither host exists it falls back to its default server.
.Pp
If an IP address is specified, the whois server will default to
If an IP address or AS number is specified,
the whois server will default to
the American Registry for Internet Numbers
.Pq Tn ARIN .
If a query to
.Tn ARIN
references
.Tn APNIC , AfriNIC , LACNIC ,
or
.Tn RIPE ,
that server will be queried also, provided that the
.Fl Q
option is not specified.
.Pp
If
.Nm
@ -164,18 +156,42 @@ Use the PeeringDB database of AS numbers.
It contains details about presence at internet peering points
for many network operators.
.It Fl Q
Do a quick lookup.
This means that
Do a quick lookup;
.Nm
will not attempt to lookup the name in the authoritative whois
server (if one is listed).
This option has no effect when combined with any other options.
will not attempt to follow referrals to other whois servers.
This is the default if a server is explicitly specified
using one of the other options.
See also the
.Fl R
option.
.It Fl r
Use the R\(aaeseaux IP Europ\(aaeens
.Pq Tn RIPE
database.
It contains network numbers and domain contact information
for Europe.
.It Fl R
Do a recursive lookup;
.Nm
will attempt to follow referrals to other whois servers.
This is the default if no server is explicitly specified.
See also the
.Fl Q
option.
.It Fl S
By default, if the whois server is
.Pa whois.verisign-grs.com
(or a CNAME alias pointing at that name)
then
.Nm
will query for
.Dl domain Ar name
The
.Fl S
option suppresses this behaviour,
allowing you to make a loose-matching query,
or query for host objects using the syntax
.Dl nameserver Ar name
.El
.Pp
The operands specified to

View File

@ -63,7 +63,7 @@ __FBSDID("$FreeBSD$");
#define ANICHOST "whois.arin.net"
#define BNICHOST "whois.registro.br"
#define FNICHOST "whois.afrinic.net"
#define GERMNICHOST "de.whois-servers.net"
#define GERMNICHOST "de" QNICHOST_TAIL
#define GNICHOST "whois.nic.gov"
#define IANAHOST "whois.iana.org"
#define INICHOST "whois.networksolutions.com"
@ -76,14 +76,13 @@ __FBSDID("$FreeBSD$");
#define QNICHOST_HEAD "whois.nic."
#define QNICHOST_TAIL ".whois-servers.net"
#define RNICHOST "whois.ripe.net"
#define VNICHOST "whois.verisign-grs.com"
#define DEFAULT_PORT "whois"
#define WHOIS_SERVER_ID "Whois Server: "
#define WHOIS_ORG_SERVER_ID "Registrant Street1:Whois Server:"
#define WHOIS_RECURSE 0x01
#define WHOIS_QUICK 0x02
#define WHOIS_SPAM_ME 0x04
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
@ -100,8 +99,20 @@ static struct {
{ NULL, NULL }
};
static const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST,
FNICHOST, NULL };
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
static struct {
const char *prefix;
size_t len;
} whois_referral[] = {
WHOIS_REFERRAL("Whois Server: "),
WHOIS_REFERRAL("WHOIS Server: "),
WHOIS_REFERRAL(" Whois Server: "),
WHOIS_REFERRAL("refer: "),
WHOIS_REFERRAL("Registrant Street1:Whois Server:"),
WHOIS_REFERRAL("ReferralServer: whois://"),
{ NULL, 0 }
};
static const char *port = DEFAULT_PORT;
static char *choose_server(char *);
@ -123,7 +134,7 @@ main(int argc, char *argv[])
country = host = qnichost = NULL;
flags = use_qnichost = 0;
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQr")) != -1) {
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
switch (ch) {
case 'a':
host = ANICHOST;
@ -173,6 +184,12 @@ main(int argc, char *argv[])
case 'r':
host = RNICHOST;
break;
case 'R':
flags |= WHOIS_RECURSE;
break;
case 'S':
flags |= WHOIS_SPAM_ME;
break;
case '?':
default:
usage();
@ -235,6 +252,13 @@ choose_server(char *domain)
s_asprintf(&retval, "%s", ANICHOST);
return (retval);
}
if (strncasecmp(domain, "AS", 2) == 0) {
size_t len = strspn(domain + 2, "0123456789");
if (domain[len + 2] == '\0') {
s_asprintf(&retval, "%s", ANICHOST);
return (retval);
}
}
for (pos = strchr(domain, '\0'); pos > domain && pos[-1] == '.';)
*--pos = '\0';
if (*domain == '\0')
@ -285,7 +309,7 @@ gethostinfo(char const *host, int exit_on_noname)
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = 0;
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
res = NULL;
@ -317,9 +341,9 @@ whois(const char *query, const char *hostname, int flags)
FILE *fp;
struct addrinfo *hostres, *res;
char *buf, *host, *nhost, *p;
int s = -1, f;
int s = -1, f, antispam;
nfds_t i, j;
size_t c, len, count;
size_t len, count;
struct pollfd *fds;
int timeout = 180;
@ -327,6 +351,9 @@ whois(const char *query, const char *hostname, int flags)
for (res = hostres, count = 0; res; res = res->ai_next)
count++;
antispam = (flags & WHOIS_SPAM_ME) == 0 &&
strcmp(hostres->ai_canonname, VNICHOST) == 0;
fds = calloc(count, sizeof(*fds));
if (fds == NULL)
err(EX_OSERR, "calloc()");
@ -457,6 +484,8 @@ whois(const char *query, const char *hostname, int flags)
fprintf(fp, "-T dn,ace -C ISO-8859-1 %s\r\n", query);
} else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) {
fprintf(fp, "--show-handles %s\r\n", query);
} else if (antispam) {
fprintf(fp, "domain %s\r\n", query);
} else {
fprintf(fp, "%s\r\n", query);
}
@ -468,39 +497,18 @@ whois(const char *query, const char *hostname, int flags)
printf("%.*s\n", (int)len, buf);
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
host = strnstr(buf, WHOIS_SERVER_ID, len);
if (host != NULL) {
host += sizeof(WHOIS_SERVER_ID) - 1;
for (p = host; p < buf + len; p++) {
if (!ishost(*p)) {
*p = '\0';
for (i = 0; whois_referral[i].prefix != NULL; i++) {
if (strncmp(buf,
whois_referral[i].prefix,
whois_referral[i].len) != 0)
continue;
host = buf + whois_referral[i].len;
for (p = host; p < buf + len; p++)
if (!ishost(*p))
break;
}
}
s_asprintf(&nhost, "%.*s",
(int)(buf + len - host), host);
} else if ((host =
strnstr(buf, WHOIS_ORG_SERVER_ID, len)) != NULL) {
host += sizeof(WHOIS_ORG_SERVER_ID) - 1;
for (p = host; p < buf + len; p++) {
if (!ishost(*p)) {
*p = '\0';
break;
}
}
s_asprintf(&nhost, "%.*s",
(int)(buf + len - host), host);
} else if (strcmp(hostname, ANICHOST) == 0) {
for (c = 0; c <= len; c++)
buf[c] = tolower((unsigned char)buf[c]);
for (i = 0; ip_whois[i] != NULL; i++) {
if (strnstr(buf, ip_whois[i], len) !=
NULL) {
s_asprintf(&nhost, "%s",
ip_whois[i]);
break;
}
}
(int)(p - host), host);
break;
}
}
}