diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /adv_cmds/whois | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'adv_cmds/whois')
-rw-r--r-- | adv_cmds/whois/whois.1 | 287 | ||||
-rw-r--r-- | adv_cmds/whois/whois.c | 629 |
2 files changed, 916 insertions, 0 deletions
diff --git a/adv_cmds/whois/whois.1 b/adv_cmds/whois/whois.1 new file mode 100644 index 0000000..0177b48 --- /dev/null +++ b/adv_cmds/whois/whois.1 @@ -0,0 +1,287 @@ +.\" Copyright (c) 1985, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" +.Dd April 25, 2016 +.Dt WHOIS 1 +.Os +.Sh NAME +.Nm whois +.Nd "Internet domain name and network number directory service" +.Sh SYNOPSIS +.Nm +.Op Fl aAbfgiIklmPQrRS +.Op Fl c Ar TLD | Fl h Ar host +.Op Fl p Ar port +.Op Fl - +.Ar name ... +.Sh DESCRIPTION +The +.Nm +utility looks up records in the databases maintained by several +Network Information Centers +.Pq Tn NICs . +.Pp +By default +.Nm +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 +There are a few special cases where referrals do not work, so +.Nm +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 +.It Fl a +Use the American Registry for Internet Numbers +.Pq Tn ARIN +database. +It contains network numbers used in those parts of the world covered neither by +.Tn APNIC , AfriNIC , LACNIC , +nor by +.Tn RIPE . +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, +indexed by domain name. +.It Fl c Ar TLD +This is the equivalent of using the +.Fl h +option with an argument of +.Qq Ar TLD Ns Li .whois-servers.net . +This can be helpful for locating country-class TLD whois servers. +.It Fl f +Use the African Network Information Centre +.Pq Tn AfriNIC +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 +.Pa .GOV . +.It Fl h Ar host +Use the specified host instead of the default. +Either a host name or an IP address may be specified. +.It Fl i +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 Fl k +Use the National Internet Development Agency of Korea's +.Pq Tn KRNIC +database. +It contains network numbers and domain contact information +for Korea. +.It Fl l +Use the Latin American and Caribbean IP address Regional Registry +.Pq Tn LACNIC +database. +It contains network numbers used in much of Latin America and the +Caribbean. +.It Fl m +Use the Route Arbiter Database +.Pq Tn RADB +database. +It contains route policy specifications for a large +number of operators' networks. +.It Fl p Ar port +Connect to the whois server on +.Ar port . +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; +.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 or in an environment variable. +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. +Get query syntax documentation using +.Ic whois -r help +.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 +.Nm +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, +.Nm +sends the query and prints the output verbatim. +.El +.Pp +The operands specified to +.Nm +are treated independently and may be used +as queries on different whois servers. +.Sh ENVIRONMENT +.Bl -tag -width WHOIS_SERVER +.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.iana.org . +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +To obtain contact information about an +administrator located in the Russian +.Tn TLD +domain +.Qq Li RU , +use the +.Fl c +option as shown in the following example, where +.Ar CONTACT-ID +is substituted with the actual contact identifier. +.Pp +.Dl Ic whois -c RU CONTACT-ID +.Pp +(Note: This example is specific to the +.Tn TLD +.Qq Li RU , +but other +.Tn TLDs +can be queried by using a similar syntax.) +.Pp +The following example demonstrates how to query +a whois server using a non-standard port, where +.Dq Li query-data +is the query to be sent to +.Dq Li whois.example.com +on port +.Dq Li rwhois +(written numerically as 4321). +.Pp +.Dl Ic whois -h whois.example.com -p rwhois query-data +.Pp +Some whois servers support complex queries +with dash-letter options. +You can use the +.Fl - +option to separate +.Nm +command options from whois server query options. +A query containing spaces must be quoted as one +argument to the +.Nm +command. +The following example asks the RIPE whois server +to return a brief description of its +.Dq Li domain +object type: +.Pp +.Dl Ic whois -r -- '-t domain' +.Sh SEE ALSO +.Rs +.%A Ken Harrenstien +.%A Vic White +.%T NICNAME/WHOIS +.%D 1 March 1982 +.%O RFC 812 +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/adv_cmds/whois/whois.c b/adv_cmds/whois/whois.c new file mode 100644 index 0000000..a6c4f6c --- /dev/null +++ b/adv_cmds/whois/whois.c @@ -0,0 +1,629 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +__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> +#include <err.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#ifdef __APPLE__ +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK 0 +#endif +#ifndef INFTIM +#define INFTIM -1 +#endif +#endif + +#define ABUSEHOST "whois.abuse.net" +#define ANICHOST "whois.arin.net" +#define DENICHOST "whois.denic.de" +#define DKNICHOST "whois.dk-hostmaster.dk" +#define FNICHOST "whois.afrinic.net" +#define GNICHOST "whois.nic.gov" +#define IANAHOST "whois.iana.org" +#define INICHOST "whois.internic.net" +#define KNICHOST "whois.krnic.net" +#define LNICHOST "whois.lacnic.net" +#define MNICHOST "whois.ra.net" +#define PDBHOST "whois.peeringdb.com" +#define PNICHOST "whois.apnic.net" +#define QNICHOST_TAIL ".whois-servers.net" +#define RNICHOST "whois.ripe.net" +#define VNICHOST "whois.verisign-grs.com" + +#ifdef __APPLE__ +#define DEFAULT_PORT "nicname" +#else +#define DEFAULT_PORT "whois" +#endif + +#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[] = { + /* 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 }, + { ".gov.uk", "ac.uk" QNICHOST_TAIL }, + { "", IANAHOST }, /* default */ + { NULL, NULL } /* safety belt */ +}; + +#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 } +static struct { + const char *prefix; + size_t len; +} whois_referral[] = { + WHOIS_REFERRAL("whois:"), /* IANA */ + WHOIS_REFERRAL("Whois Server:"), + WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */ + WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */ + WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */ + { NULL, 0 } +}; + +/* + * We have a list of patterns for RIRs that assert ignorance rather than + * providing referrals. If that happens, we guess that ARIN will be more + * helpful. But, before following a referral to an RIR, we check if we have + * asked that RIR already, and if so we make another guess. + */ +static const char *actually_arin[] = { + "netname: ERX-NETBLOCK\n", /* APNIC */ + "netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n", + NULL +}; + +static struct { + int loop; + const char *host; +} try_rir[] = { + { 0, ANICHOST }, + { 0, RNICHOST }, + { 0, PNICHOST }, + { 0, FNICHOST }, + { 0, LNICHOST }, + { 0, NULL } +}; + +static void +reset_rir(void) { + int i; + + for (i = 0; try_rir[i].host != NULL; i++) + try_rir[i].loop = 0; +} + +static const char *port = DEFAULT_PORT; + +static const char *choose_server(char *); +static struct addrinfo *gethostinfo(char const *host, int exitnoname); +#ifdef __APPLE__ +static void s_asprintf(char **ret, const char *format, ...) __attribute__((__format__(printf, 2, 3))); +#else +static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3); +#endif +static void usage(void); +static void whois(const char *, const char *, int); + +int +main(int argc, char *argv[]) +{ + const char *country, *host; + int ch, flags; + +#ifdef SOCKS + SOCKSinit(argv[0]); +#endif + + country = host = NULL; + flags = 0; + while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) { + switch (ch) { + case 'a': + host = ANICHOST; + break; + case 'A': + host = PNICHOST; + break; + case 'b': + host = ABUSEHOST; + break; + case 'c': + country = optarg; + break; + case 'f': + host = FNICHOST; + break; + case 'g': + host = GNICHOST; + break; + case 'h': + host = optarg; + break; + case 'i': + host = INICHOST; + break; + case 'I': + host = IANAHOST; + break; + case 'k': + host = KNICHOST; + break; + case 'l': + host = LNICHOST; + break; + case 'm': + host = MNICHOST; + break; + case 'p': + port = optarg; + break; + case 'P': + host = PDBHOST; + break; + case 'Q': + flags |= WHOIS_QUICK; + break; + case 'r': + host = RNICHOST; + break; + case 'R': + flags |= WHOIS_RECURSE; + break; + case 'S': + flags |= WHOIS_SPAM_ME; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (!argc || (country != NULL && host != NULL)) + usage(); + + /* + * 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) { + 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); + free(qnichost); + } else + whois(*argv, host != NULL ? host : + choose_server(*argv), flags); + reset_rir(); + argv++; + } + exit(0); +} + +static const char * +choose_server(char *domain) +{ + size_t len = strlen(domain); + int i; + + for (i = 0; whoiswhere[i].suffix != NULL; i++) { + size_t suffix_len = strlen(whoiswhere[i].suffix); + 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 * +gethostinfo(char const *host, int exit_on_noname) +{ + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + res = NULL; + error = getaddrinfo(host, port, &hints, &res); + if (error && (exit_on_noname || error != EAI_NONAME)) + err(EX_NOHOST, "%s: %s", host, gai_strerror(error)); + return (res); +} + +/* + * Wrapper for asprintf(3) that exits on error. + */ +static void +s_asprintf(char **ret, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if (vasprintf(ret, format, ap) == -1) { + va_end(ap); + err(EX_OSERR, "vasprintf()"); + } + va_end(ap); +} + +static int +connect_to_any_host(struct addrinfo *hostres) +{ + struct addrinfo *res; + nfds_t i, j; + size_t count; + struct pollfd *fds; + int timeout = 180, s = -1; + + 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; +#ifdef __APPLE__ + int flags = fcntl(s, F_GETFL, 0); + if (flags < 0) { + close(s); + continue; + } + flags |= O_NONBLOCK; + if (fcntl(s, F_SETFL, flags) != 0) { + close(s); + continue; + } +#endif + 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; + /* + * From here until a socket connects, the + * socket fd is owned by the fds[] poll array. + */ + s = -1; + 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(fds[j].fd); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } else if (fds[j].revents & (POLLIN | POLLOUT)) { + /* Connect succeeded. */ + s = fds[j].fd; + fds[j].fd = -1; + + 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 != -1) + close(fds[j].fd); + free(fds); + return (s); +} + +static void +whois(const char *query, const char *hostname, int flags) +{ + FILE *fp; + struct addrinfo *hostres; + char *buf, *host, *nhost, *p; + int comment, s, f; + size_t len, i; + + hostres = gethostinfo(hostname, 1); + s = connect_to_any_host(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 (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DENICHOST) == 0 || + strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) { + const char *q; + int idn = 0; + for (q = query; *q != '\0'; q++) + if (!isascii(*q)) + idn = 1; + fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query); + } else if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DKNICHOST) == 0 || + strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0)) + fprintf(fp, "--show-handles %s\r\n", query); + else if ((flags & WHOIS_SPAM_ME) || + strchr(query, ' ') != NULL) + fprintf(fp, "%s\r\n", query); + else if (strcasecmp(hostname, ANICHOST) == 0) { + if (strncasecmp(query, "AS", 2) == 0 && + strspn(query+2, "0123456789") == strlen(query+2)) + fprintf(fp, "+ a %s\r\n", query+2); + else + fprintf(fp, "+ %s\r\n", query); + } else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0) + fprintf(fp, "domain %s\r\n", query); + else + fprintf(fp, "%s\r\n", query); + fflush(fp); + + comment = 0; + if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, ANICHOST) == 0 || + strcasecmp(hostname, RNICHOST) == 0)) { + comment = 2; + } + + nhost = NULL; + while ((buf = fgetln(fp, &len)) != NULL) { + /* Nominet */ + if (!(flags & WHOIS_SPAM_ME) && + len == 5 && strncmp(buf, "-- \r\n", 5) == 0) + break; + /* RIRs */ + if (comment == 1 && buf[0] == '#') + break; + else if (comment == 2) { + if (strchr("#%\r\n", buf[0]) != NULL) + continue; + else + comment = 1; + } + + printf("%.*s", (int)len, buf); + + if ((flags & WHOIS_RECURSE) && nhost == NULL) { + for (i = 0; whois_referral[i].prefix != NULL; i++) { + p = buf; + SCAN(p, buf+len, *p == ' '); + if (strncasecmp(p, whois_referral[i].prefix, + whois_referral[i].len) != 0) + continue; + p += whois_referral[i].len; + SCAN(p, buf+len, *p == ' '); + host = p; + SCAN(p, buf+len, ishost(*p)); + if (p > host) + s_asprintf(&nhost, "%.*s", + (int)(p - host), host); + break; + } + for (i = 0; actually_arin[i] != NULL; i++) { + if (strncmp(buf, actually_arin[i], len) == 0) { + s_asprintf(&nhost, "%s", ANICHOST); + 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); + + f = 0; + for (i = 0; try_rir[i].host != NULL; i++) { + /* Remember visits to RIRs */ + if (try_rir[i].loop == 0 && + strcasecmp(try_rir[i].host, hostname) == 0) + try_rir[i].loop = 1; + /* Do we need to find an alternative RIR? */ + if (try_rir[i].loop != 0 && nhost != NULL && + strcasecmp(try_rir[i].host, nhost) == 0) { + free(nhost); + nhost = NULL; + f = 1; + } + } + if (f) { + /* Find a replacement RIR */ + for (i = 0; try_rir[i].host != NULL; i++) { + if (try_rir[i].loop == 0) { + s_asprintf(&nhost, "%s", + try_rir[i].host); + break; + } + } + } + if (nhost != NULL) { + /* Ignore self-referrals */ + if (strcasecmp(hostname, nhost) != 0) { + printf("# %s\n\n", nhost); + whois(query, nhost, flags); + } + free(nhost); + } +} + +static void +usage(void) +{ + fprintf(stderr, + "usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] " + "[-p port] name ...\n"); + exit(EX_USAGE); +} |