diff options
author | Simon J. Gerraty <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
---|---|---|
committer | Simon J. Gerraty <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
commit | 98e0ffaefb0f241cda3a72395d3be04192ae0d47 (patch) | |
tree | 55c065b6730aaac2afb6c29933ee6ec5fa4c4249 /usr.bin/whois | |
parent | b17ff922d4072ae132ece458f5b5d74a236880ac (diff) | |
parent | e81032ad243db32b8fd615b2d55ee94b9f6a5b6a (diff) | |
download | src-98e0ffaefb0f241cda3a72395d3be04192ae0d47.tar.gz src-98e0ffaefb0f241cda3a72395d3be04192ae0d47.zip |
Notes
Diffstat (limited to 'usr.bin/whois')
-rw-r--r-- | usr.bin/whois/whois.1 | 130 | ||||
-rw-r--r-- | usr.bin/whois/whois.c | 265 |
2 files changed, 269 insertions, 126 deletions
diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1 index 0f0f17739937..a9ed50adfd50 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 October 2, 2009 +.Dd May 14, 2015 .Dt WHOIS 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Nd "Internet domain name and network number directory service" .Sh SYNOPSIS .Nm -.Op Fl aAbfgiIklmQrR +.Op Fl aAbfgiIklmPQr .Op Fl c Ar country-code | Fl h Ar host .Op Fl p Ar port .Ar name ... @@ -47,6 +47,42 @@ utility looks up records in the databases maintained by several Network Information Centers .Pq Tn NICs . .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. +.Pp +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 +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 +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 . +.Pp The options are as follows: .Bl -tag -width indent .It Fl a @@ -88,66 +124,12 @@ 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. -.Pp -By default -.Nm -constructs 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 . -.Pp -In the event that 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 -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 the query is not a domain name or IP address, -.Nm -will fall back to -.Pa whois.crsnic.net . .It Fl i -Use the Network Solutions Registry for Internet Numbers +Use the obsolete Network Solutions Registry for Internet Numbers .Pq Pa whois.networksolutions.com database. -It contains network numbers and domain contact information for most of -.Pa .COM , .NET , .ORG -and -.Pa .EDU -domains. -.Pp -.Sy NOTE ! -The registration of these domains is now done by a number of -independent and competing registrars and this database holds no information -on the domains registered by organizations other than Network Solutions, Inc. -Also, note that the -.Tn InterNIC -database -.Pq Pa whois.internic.net -is no longer handled by Network Solutions, Inc. -For details, see -.Pa http://www.internic.net/ . -.Pp -(Hint: Contact information, identified by the term -.Em handle , -can be looked up by prefixing -.Qq Li "handle " -to the -.Tn NIC -handle in the query.) .It Fl I Use the Internet Assigned Numbers Authority .Pq Tn IANA @@ -177,6 +159,10 @@ Connect to the whois server on If this option is not specified, .Nm defaults to port 43. +.It Fl P +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 @@ -190,24 +176,28 @@ Use the R\(aaeseaux IP Europ\(aaeens database. It contains network numbers and domain contact information for Europe. -.It Fl R -Use the Russia Network Information Center -.Pq Tn RIPN -database. -It contains network numbers and domain contact information -for subdomains of -.Pa .RU . -This option is deprecated; use the -.Fl c -option with an argument of -.Qq Li RU -instead. .El .Pp The operands specified to .Nm are treated independently and may be used as queries on different whois servers. +.Sh ENVIRONMENT +.Bl -tag +.It Ev WHOIS_SERVER +The primary default whois server. +If this is unset, +.Nm +uses the +.Ev RA_SERVER +environment variable. +.It Ev RA_SERVER +The secondary default whois server. +If this is unset, +.Nm +will use +.Pa whois.crsnic.net . +.El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c index 3f6f93a8751f..6ad8826ce520 100644 --- a/usr.bin/whois/whois.c +++ b/usr.bin/whois/whois.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> +#include <sys/poll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> @@ -55,24 +56,29 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <sysexits.h> #include <unistd.h> +#include <fcntl.h> +#include <errno.h> #define ABUSEHOST "whois.abuse.net" -#define NICHOST "whois.crsnic.net" -#define INICHOST "whois.networksolutions.com" -#define GNICHOST "whois.nic.gov" #define ANICHOST "whois.arin.net" -#define LNICHOST "whois.lacnic.net" +#define BNICHOST "whois.registro.br" +#define FNICHOST "whois.afrinic.net" +#define GERMNICHOST "de.whois-servers.net" +#define GNICHOST "whois.nic.gov" +#define IANAHOST "whois.iana.org" +#define INICHOST "whois.networksolutions.com" #define KNICHOST "whois.krnic.net" -#define RNICHOST "whois.ripe.net" -#define PNICHOST "whois.apnic.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 BNICHOST "whois.registro.br" -#define NORIDHOST "whois.norid.no" -#define IANAHOST "whois.iana.org" -#define GERMNICHOST "de.whois-servers.net" -#define FNICHOST "whois.afrinic.net" +#define RNICHOST "whois.ripe.net" + #define DEFAULT_PORT "whois" + #define WHOIS_SERVER_ID "Whois Server: " #define WHOIS_ORG_SERVER_ID "Registrant Street1:Whois Server:" @@ -81,12 +87,25 @@ __FBSDID("$FreeBSD$"); #define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-') +static struct { + const char *suffix, *server; +} whoiswhere[] = { + /* Various handles */ + { "-ARIN", ANICHOST }, + { "-NICAT", "at" QNICHOST_TAIL }, + { "-NORID", "no" QNICHOST_TAIL }, + { "-RIPE", RNICHOST }, + /* Nominet's whois server doesn't return referrals to JANET */ + { ".ac.uk", "ac.uk" QNICHOST_TAIL }, + { NULL, NULL } +}; + static const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST, FNICHOST, NULL }; 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); @@ -104,7 +123,7 @@ main(int argc, char *argv[]) country = host = qnichost = NULL; flags = use_qnichost = 0; - while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:QrR6")) != -1) { + while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQr")) != -1) { switch (ch) { case 'a': host = ANICHOST; @@ -145,21 +164,15 @@ main(int argc, char *argv[]) case 'p': port = optarg; break; + case 'P': + host = PDBHOST; + break; case 'Q': flags |= WHOIS_QUICK; break; case 'r': host = RNICHOST; break; - case 'R': - warnx("-R is deprecated; use '-c ru' instead"); - country = "ru"; - break; - /* Remove in FreeBSD 10 */ - case '6': - errx(EX_USAGE, - "-6 is deprecated; use -[aAflr] instead"); - break; case '?': default: usage(); @@ -173,13 +186,12 @@ main(int argc, char *argv[]) usage(); /* - * If no host or country is specified determine the top level domain - * from the query. If the TLD is a number, query ARIN. Otherwise, use - * TLD.whois-server.net. If the domain does not contain '.', fall - * back to NICHOST. + * If no host or country is specified, try to determine the top + * level domain from the query, or fall back to NICHOST. */ if (host == NULL && country == NULL) { - if ((host = getenv("RA_SERVER")) == NULL) { + if ((host = getenv("WHOIS_SERVER")) == NULL && + (host = getenv("RA_SERVER")) == NULL) { use_qnichost = 1; host = NICHOST; if (!(flags & WHOIS_QUICK)) @@ -207,39 +219,67 @@ main(int argc, char *argv[]) * 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 * choose_server(char *domain) { char *pos, *retval; + int i; + struct addrinfo *res; if (strchr(domain, ':')) { s_asprintf(&retval, "%s", ANICHOST); return (retval); } - for (pos = strchr(domain, '\0'); pos > domain && *--pos == '.';) - *pos = '\0'; + for (pos = strchr(domain, '\0'); pos > domain && pos[-1] == '.';) + *--pos = '\0'; if (*domain == '\0') errx(EX_USAGE, "can't search for a null string"); - if (strlen(domain) > sizeof("-NORID")-1 && - strcasecmp(domain + strlen(domain) - sizeof("-NORID") + 1, - "-NORID") == 0) { - s_asprintf(&retval, "%s", NORIDHOST); - return (retval); + 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)) + 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; @@ -248,13 +288,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); } @@ -280,21 +317,137 @@ whois(const char *query, const char *hostname, int flags) FILE *fp; struct addrinfo *hostres, *res; char *buf, *host, *nhost, *p; - int i, s; - size_t c, len; + int s = -1, f; + nfds_t i, j; + size_t c, len, count; + struct pollfd *fds; + int timeout = 180; - s = -1; hostres = gethostinfo(hostname, 1); - for (res = hostres; res; res = res->ai_next) { - s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + for (res = hostres, count = 0; res; res = res->ai_next) + count++; + + fds = calloc(count, sizeof(*fds)); + if (fds == NULL) + err(EX_OSERR, "calloc()"); + + /* + * Traverse the result list elements and make non-block + * connection attempts. + */ + count = i = 0; + for (res = hostres; res != NULL; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, + res->ai_protocol); if (s < 0) continue; - if (connect(s, res->ai_addr, res->ai_addrlen) == 0) - break; - close(s); + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (errno == EINPROGRESS) { + /* Add the socket to poll list */ + fds[i].fd = s; + fds[i].events = POLLERR | POLLHUP | + POLLIN | POLLOUT; + count++; + i++; + } else { + close(s); + s = -1; + + /* + * Poll only if we have something to poll, + * otherwise just go ahead and try next + * address + */ + if (count == 0) + continue; + } + } else + goto done; + + /* + * If we are at the last address, poll until a connection is + * established or we failed all connection attempts. + */ + if (res->ai_next == NULL) + timeout = INFTIM; + + /* + * Poll the watched descriptors for successful connections: + * if we still have more untried resolved addresses, poll only + * once; otherwise, poll until all descriptors have errors, + * which will be considered as ETIMEDOUT later. + */ + do { + int n; + + n = poll(fds, i, timeout); + if (n == 0) { + /* + * No event reported in time. Try with a + * smaller timeout (but cap at 2-3ms) + * after a new host have been added. + */ + if (timeout >= 3) + timeout <<= 1; + + break; + } else if (n < 0) { + /* + * errno here can only be EINTR which we would want + * to clean up and bail out. + */ + s = -1; + goto done; + } + + /* + * Check for the event(s) we have seen. + */ + for (j = 0; j < i; j++) { + if (fds[j].fd == -1 || fds[j].events == 0 || + fds[j].revents == 0) + continue; + if (fds[j].revents & ~(POLLIN | POLLOUT)) { + close(s); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } else if (fds[j].revents & (POLLIN | POLLOUT)) { + /* Connect succeeded. */ + s = fds[j].fd; + + goto done; + } + + } + } while (timeout == INFTIM && count != 0); } + + /* All attempts were failed */ + s = -1; + if (count == 0) + errno = ETIMEDOUT; + +done: + /* 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 (res == NULL) + if (s == -1) err(EX_OSERR, "connect()"); fp = fdopen(s, "r+"); @@ -362,7 +515,7 @@ static void usage(void) { fprintf(stderr, - "usage: whois [-aAbfgiIklmQrR6] [-c country-code | -h hostname] " + "usage: whois [-aAbfgiIklmPQr] [-c country-code | -h hostname] " "[-p port] name ...\n"); exit(EX_USAGE); } |