summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 bcc770c..0b74cc5 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 6be6c40..e7bf94f 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);
}
}
OpenPOWER on IntegriCloud