summaryrefslogtreecommitdiff
path: root/usr.bin/whois
diff options
context:
space:
mode:
authorTony Finch <fanf@FreeBSD.org>2016-01-23 00:28:18 +0000
committerTony Finch <fanf@FreeBSD.org>2016-01-23 00:28:18 +0000
commit6f4d88df9f3f272c006118386a158bb2bf5a3c08 (patch)
tree486fc05e8661a7b55f37b3b17da110128cfc5fbc /usr.bin/whois
parent097f289f251c350b2ed8dccdfc642631ba25a144 (diff)
downloadsrc-test-6f4d88df9f3f272c006118386a158bb2bf5a3c08.tar.gz
src-test-6f4d88df9f3f272c006118386a158bb2bf5a3c08.zip
A lot of the cleverness in whois is no longer needed!
The IANA whois server has the right referral information for domain names, IP addresses, and AS numbers, so whois does not need to be able to choose servers itself (except for a few cases where referrals do not work). We can delete a chunk of code, which is always fun. This change improves the referral handling to be less sensitive to all the various formats, and to allow multi-hop referral chains, such as IANA -> registry -> registrar. ARIN queries have the "+" flag added if no flags are present, so we get full details if the query matches multiple objects. The Verisign anti-spam logic is also now suppressed if the user provided a non- trivial query string. Uninformative rubric is now trimmed by default. The -S option turns off trimming, and disables query fettling. The -i option is back to its traditional pre-1999 hostname, since whois.internic.net is more useful than whois.networksolutions.com. Note that the old fallback/default server whois.crsnic.net is an alias for whois.internic.net. The manual is more informative about query syntax.
Notes
Notes: svn path=/head/; revision=294611
Diffstat (limited to 'usr.bin/whois')
-rw-r--r--usr.bin/whois/whois.1106
-rw-r--r--usr.bin/whois/whois.c222
2 files changed, 139 insertions, 189 deletions
diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1
index bcc770ce96246..0b74cc5bcf781 100644
--- a/usr.bin/whois/whois.1
+++ b/usr.bin/whois/whois.1
@@ -28,7 +28,7 @@
.\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd January 22, 2016
+.Dd January 23, 2016
.Dt WHOIS 1
.Os
.Sh NAME
@@ -49,31 +49,22 @@ Network Information Centers
.Pp
By default
.Nm
-automatically discovers the name of a whois server to use
-from the top-level domain
-.Pq Tn TLD
-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.
+starts by querying the Internet Assigned Numbers Authority (IANA) whois server,
+and follows referrals to whois servers
+that have more specific details about the query
+.Ar name .
+The IANA whois server knows about
+IP address and AS numbers
+as well as domain names.
.Pp
-If an IP address or AS number is specified,
-the whois server will default to
-the American Registry for Internet Numbers
-.Pq Tn ARIN .
-.Pp
-If
+There are a few special cases where referrals do not work, so
.Nm
-cannot automatically discover a server,
-it will fall back to
-the host specified in the
-.Ev WHOIS_SERVER
-or
-.Ev RA_SERVER
-environment variables, or if those are not set, it will use
-.Pa whois.crsnic.net .
+goes directly to the appropriate server.
+These include point-of-contact handles for ARIN,
+.Pa nic.at ,
+NORID, and RIPE,
+and domain names under
+.Pa ac.uk .
.Pp
The options are as follows:
.Bl -tag -width indent
@@ -85,17 +76,16 @@ It contains network numbers used in those parts of the world covered neither by
.Tn APNIC , AfriNIC , LACNIC ,
nor by
.Tn RIPE .
-.Pp
-(Hint: All point of contact handles in the
-.Tn ARIN
-whois database end with
-.Qq Li -ARIN . )
+The query syntax is documented at
+.Pa https://www.arin.net/resources/whoisrws/whois_api.html#nicname
.It Fl A
Use the Asia/Pacific Network Information Center
.Pq Tn APNIC
database.
It contains network numbers used in East Asia, Australia,
New Zealand, and the Pacific islands.
+Get query syntax documentation using
+.Ic whois -A help
.It Fl b
Use the Network Abuse Clearinghouse database.
It contains addresses to which network abuse should be reported,
@@ -111,6 +101,8 @@ Use the African Network Information Centre
database.
It contains network numbers used in Africa and the islands of the
western Indian Ocean.
+Get query syntax documentation using
+.Ic whois -f help
.It Fl g
Use the US non-military federal government database, which contains points of
contact for subdomains of
@@ -119,14 +111,28 @@ contact for subdomains of
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
-.Pq Pa whois.networksolutions.com
+Use the traditional Network Information Center (InterNIC)
+.Pq Pa whois.internic.net
database.
+This now contains only registrations for domain names under
+.Pa .COM ,
+.Pa .NET ,
+.Pa .EDU .
+You can specify the type of object to search for like
+.Ic whois -i ' Ns Ar type Ar name Ns Ic '
+where
+.Ar type
+can be
+.Nm domain , nameserver , registrar .
+The
+.Ar name
+can contain
+.Li *
+wildcards.
.It Fl I
Use the Internet Assigned Numbers Authority
.Pq Tn IANA
database.
-It contains network information for top-level domains.
.It Fl k
Use the National Internet Development Agency of Korea's
.Pq Tn KRNIC
@@ -160,7 +166,7 @@ Do a quick lookup;
.Nm
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.
+using one of the other options or in an environment variable.
See also the
.Fl R
option.
@@ -170,6 +176,8 @@ Use the R\(aaeseaux IP Europ\(aaeens
database.
It contains network numbers and domain contact information
for Europe.
+Get query syntax documentation using
+.Ic whois -r help
.It Fl R
Do a recursive lookup;
.Nm
@@ -179,19 +187,16 @@ 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
+By default
.Nm
-will query for
-.Dl domain Ar name
-The
+adjusts simple queries (without spaces) to produce more useful output
+from certain whois servers,
+and it suppresses some uninformative output.
+With 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
+option,
+.Nm
+sends the query and prints the output verbatim.
.El
.Pp
The operands specified to
@@ -212,22 +217,11 @@ The secondary default whois server.
If this is unset,
.Nm
will use
-.Pa whois.crsnic.net .
+.Pa whois.iana.org .
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
-Most types of data, such as domain names and
-.Tn IP
-addresses, can be used as arguments to
-.Nm
-without any options, and
-.Nm
-will choose the correct whois server to query.
-Some exceptions, where
-.Nm
-will not be able to handle data correctly, are detailed below.
-.Pp
To obtain contact information about an
administrator located in the Russian
.Tn TLD
diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c
index 6be6c401c079d..e7bf94fc81634 100644
--- a/usr.bin/whois/whois.c
+++ b/usr.bin/whois/whois.c
@@ -61,31 +61,35 @@ __FBSDID("$FreeBSD$");
#define ABUSEHOST "whois.abuse.net"
#define ANICHOST "whois.arin.net"
-#define BNICHOST "whois.registro.br"
+#define DENICHOST "de" QNICHOST_TAIL
#define FNICHOST "whois.afrinic.net"
-#define GERMNICHOST "de" QNICHOST_TAIL
#define GNICHOST "whois.nic.gov"
#define IANAHOST "whois.iana.org"
-#define INICHOST "whois.networksolutions.com"
+#define INICHOST "whois.internic.net"
#define KNICHOST "whois.krnic.net"
#define LNICHOST "whois.lacnic.net"
#define MNICHOST "whois.ra.net"
-#define NICHOST "whois.crsnic.net"
#define PDBHOST "whois.peeringdb.com"
#define PNICHOST "whois.apnic.net"
-#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_RECURSE 0x01
-#define WHOIS_QUICK 0x02
-#define WHOIS_SPAM_ME 0x04
+#define WHOIS_RECURSE 0x01
+#define WHOIS_QUICK 0x02
+#define WHOIS_SPAM_ME 0x04
+
+#define CHOPSPAM ">>> Last update of WHOIS database:"
#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
+#define SCAN(p, end, check) \
+ while ((p) < (end)) \
+ if (check) ++(p); \
+ else break
+
static struct {
const char *suffix, *server;
} whoiswhere[] = {
@@ -96,7 +100,8 @@ static struct {
{ "-RIPE", RNICHOST },
/* Nominet's whois server doesn't return referrals to JANET */
{ ".ac.uk", "ac.uk" QNICHOST_TAIL },
- { NULL, NULL }
+ { "", IANAHOST }, /* default */
+ { NULL, NULL } /* safety belt */
};
#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
@@ -104,18 +109,16 @@ 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://"),
+ WHOIS_REFERRAL("whois:"), /* IANA */
+ WHOIS_REFERRAL("Whois Server:"),
+ WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
+ WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
{ NULL, 0 }
};
static const char *port = DEFAULT_PORT;
-static char *choose_server(char *);
+static const char *choose_server(char *);
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);
@@ -125,15 +128,14 @@ int
main(int argc, char *argv[])
{
const char *country, *host;
- char *qnichost;
- int ch, flags, use_qnichost;
+ int ch, flags;
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif
- country = host = qnichost = NULL;
- flags = use_qnichost = 0;
+ country = host = NULL;
+ flags = 0;
while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
switch (ch) {
case 'a':
@@ -203,103 +205,43 @@ main(int argc, char *argv[])
usage();
/*
- * If no host or country is specified, try to determine the top
- * level domain from the query, or fall back to NICHOST.
+ * If no host or country is specified, rely on referrals from IANA.
*/
if (host == NULL && country == NULL) {
if ((host = getenv("WHOIS_SERVER")) == NULL &&
(host = getenv("RA_SERVER")) == NULL) {
- use_qnichost = 1;
- host = NICHOST;
if (!(flags & WHOIS_QUICK))
flags |= WHOIS_RECURSE;
}
}
while (argc-- > 0) {
if (country != NULL) {
+ char *qnichost;
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)
- whois(*argv, host, flags);
- free(qnichost);
- qnichost = NULL;
+ free(qnichost);
+ } else
+ whois(*argv, host != NULL ? host :
+ choose_server(*argv), flags);
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.
- *
- * 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 try a couple of
- * formulaic server names. Fail if the domain does not contain '.'.
- */
-static char *
+static const char *
choose_server(char *domain)
{
- char *pos, *retval;
+ size_t len = strlen(domain);
int i;
- struct addrinfo *res;
- if (strchr(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')
- errx(EX_USAGE, "can't search for a null string");
for (i = 0; whoiswhere[i].suffix != NULL; i++) {
size_t suffix_len = strlen(whoiswhere[i].suffix);
- if (domain + suffix_len < pos &&
- strcasecmp(pos - suffix_len, whoiswhere[i].suffix) == 0) {
- s_asprintf(&retval, "%s", whoiswhere[i].server);
- return (retval);
- }
- }
- while (pos > domain && *pos != '.')
- --pos;
- if (pos <= domain)
- return (NULL);
- if (isdigit((unsigned char)*++pos)) {
- s_asprintf(&retval, "%s", ANICHOST);
- 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;
- }
+ if (len > suffix_len &&
+ strcasecmp(domain + len - suffix_len,
+ whoiswhere[i].suffix) == 0)
+ return (whoiswhere[i].server);
}
+ errx(EX_SOFTWARE, "no default whois server");
}
static struct addrinfo *
@@ -341,7 +283,7 @@ whois(const char *query, const char *hostname, int flags)
FILE *fp;
struct addrinfo *hostres, *res;
char *buf, *host, *nhost, *p;
- int s = -1, f, antispam;
+ int s = -1, f;
nfds_t i, j;
size_t len, count;
struct pollfd *fds;
@@ -350,10 +292,6 @@ whois(const char *query, const char *hostname, int flags)
hostres = gethostinfo(hostname, 1);
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()");
@@ -420,8 +358,8 @@ whois(const char *query, const char *hostname, int flags)
break;
} else if (n < 0) {
/*
- * errno here can only be EINTR which we would want
- * to clean up and bail out.
+ * errno here can only be EINTR which we would
+ * want to clean up and bail out.
*/
s = -1;
goto done;
@@ -455,66 +393,84 @@ whois(const char *query, const char *hostname, int flags)
s = -1;
if (count == 0)
errno = ETIMEDOUT;
-
done:
+ if (s == -1)
+ err(EX_OSERR, "connect()");
+
/* Close all watched fds except the succeeded one */
for (j = 0; j < i; j++)
if (fds[j].fd != s && fds[j].fd != -1)
close(fds[j].fd);
-
- if (s != -1) {
- /* Restore default blocking behavior. */
- if ((f = fcntl(s, F_GETFL)) != -1) {
- f &= ~O_NONBLOCK;
- if (fcntl(s, F_SETFL, f) == -1)
- err(EX_OSERR, "fcntl()");
- } else
- err(EX_OSERR, "fcntl()");
- }
-
free(fds);
- freeaddrinfo(hostres);
- if (s == -1)
- err(EX_OSERR, "connect()");
+
+ /* Restore default blocking behavior. */
+ if ((f = fcntl(s, F_GETFL)) == -1)
+ err(EX_OSERR, "fcntl()");
+ f &= ~O_NONBLOCK;
+ if (fcntl(s, F_SETFL, f) == -1)
+ err(EX_OSERR, "fcntl()");
fp = fdopen(s, "r+");
if (fp == NULL)
err(EX_OSERR, "fdopen()");
- if (strcmp(hostname, GERMNICHOST) == 0) {
+
+ if (!(flags & WHOIS_SPAM_ME) &&
+ strcmp(hostname, DENICHOST) == 0)
fprintf(fp, "-T dn,ace -C ISO-8859-1 %s\r\n", query);
- } else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) {
+ else if (!(flags & WHOIS_SPAM_ME) &&
+ strcmp(hostname, "dk" QNICHOST_TAIL) == 0)
fprintf(fp, "--show-handles %s\r\n", query);
- } else if (antispam) {
+ else if ((flags & WHOIS_SPAM_ME) ||
+ strchr(query, ' ') != NULL)
+ fprintf(fp, "%s\r\n", query);
+ else if (strcmp(hostname, ANICHOST) == 0)
+ fprintf(fp, "+ %s\r\n", query);
+ else if (strcmp(hostres->ai_canonname, VNICHOST) == 0)
fprintf(fp, "domain %s\r\n", query);
- } else {
+ else
fprintf(fp, "%s\r\n", query);
- }
fflush(fp);
+
nhost = NULL;
while ((buf = fgetln(fp, &len)) != NULL) {
- while (len > 0 && isspace((unsigned char)buf[len - 1]))
- buf[--len] = '\0';
- printf("%.*s\n", (int)len, buf);
+ /* Nominet */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
+ break;
+
+ printf("%.*s", (int)len, buf);
if ((flags & WHOIS_RECURSE) && nhost == NULL) {
for (i = 0; whois_referral[i].prefix != NULL; i++) {
- if (strncmp(buf,
- whois_referral[i].prefix,
- whois_referral[i].len) != 0)
+ p = buf;
+ SCAN(p, buf+len, *p == ' ');
+ if (strncasecmp(p, 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)(p - host), host);
+ p += whois_referral[i].len;
+ SCAN(p, buf+len, *p == ' ');
+ host = p;
+ SCAN(p, buf+len, ishost(*p));
+ /* avoid loops */
+ if (strncmp(hostname, host, p - host) != 0)
+ s_asprintf(&nhost, "%.*s",
+ (int)(p - host), host);
break;
}
}
+ /* Verisign etc. */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len >= sizeof(CHOPSPAM)-1 &&
+ (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
+ strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
+ printf("\n");
+ break;
+ }
}
fclose(fp);
+ freeaddrinfo(hostres);
if (nhost != NULL) {
- whois(query, nhost, 0);
+ whois(query, nhost, flags);
free(nhost);
}
}