13cddd28eSXin LI /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes * are met:
109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes * without specific prior written permission.
189b50d902SRodney W. Grimes *
199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes * SUCH DAMAGE.
309b50d902SRodney W. Grimes */
319b50d902SRodney W. Grimes
329b50d902SRodney W. Grimes #include <sys/types.h>
339b50d902SRodney W. Grimes #include <sys/socket.h>
343cddd28eSXin LI #include <sys/poll.h>
359b50d902SRodney W. Grimes #include <netinet/in.h>
36a60c62a3SPeter Wemm #include <arpa/inet.h>
37861c52f1SPoul-Henning Kamp #include <ctype.h>
38741d304eSPhilippe Charnier #include <err.h>
399b50d902SRodney W. Grimes #include <netdb.h>
40197bca2cSMike Barcroft #include <stdarg.h>
419b50d902SRodney W. Grimes #include <stdio.h>
422053e9a3SAndrey A. Chernov #include <stdlib.h>
43741d304eSPhilippe Charnier #include <string.h>
44a00fe97dSGarrett Wollman #include <sysexits.h>
45741d304eSPhilippe Charnier #include <unistd.h>
463cddd28eSXin LI #include <fcntl.h>
473cddd28eSXin LI #include <errno.h>
489b50d902SRodney W. Grimes
49fb6dad91SBruce M Simpson #define ABUSEHOST "whois.abuse.net"
50a00fe97dSGarrett Wollman #define ANICHOST "whois.arin.net"
51f537d420STony Finch #define DENICHOST "whois.denic.de"
52f537d420STony Finch #define DKNICHOST "whois.dk-hostmaster.dk"
53dfef6b15STony Finch #define FNICHOST "whois.afrinic.net"
54dfef6b15STony Finch #define GNICHOST "whois.nic.gov"
55dfef6b15STony Finch #define IANAHOST "whois.iana.org"
566f4d88dfSTony Finch #define INICHOST "whois.internic.net"
57876b0a88SCeri Davies #define KNICHOST "whois.krnic.net"
58dfef6b15STony Finch #define LNICHOST "whois.lacnic.net"
592053e9a3SAndrey A. Chernov #define MNICHOST "whois.ra.net"
6060214b7fSTony Finch #define PDBHOST "whois.peeringdb.com"
61dfef6b15STony Finch #define PNICHOST "whois.apnic.net"
622053e9a3SAndrey A. Chernov #define QNICHOST_TAIL ".whois-servers.net"
63dfef6b15STony Finch #define RNICHOST "whois.ripe.net"
6452517c0aSTony Finch #define VNICHOST "whois.verisign-grs.com"
65dfef6b15STony Finch
66eade81c9SMike Barcroft #define DEFAULT_PORT "whois"
67dfef6b15STony Finch
682053e9a3SAndrey A. Chernov #define WHOIS_RECURSE 0x01
6942ab40e5SMike Barcroft #define WHOIS_QUICK 0x02
7052517c0aSTony Finch #define WHOIS_SPAM_ME 0x04
7142ab40e5SMike Barcroft
726f4d88dfSTony Finch #define CHOPSPAM ">>> Last update of WHOIS database:"
736f4d88dfSTony Finch
7442ab40e5SMike Barcroft #define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
752053e9a3SAndrey A. Chernov
766f4d88dfSTony Finch #define SCAN(p, end, check) \
776f4d88dfSTony Finch while ((p) < (end)) \
786f4d88dfSTony Finch if (check) ++(p); \
796f4d88dfSTony Finch else break
806f4d88dfSTony Finch
81c343f061STony Finch static struct {
82c343f061STony Finch const char *suffix, *server;
83c343f061STony Finch } whoiswhere[] = {
84c343f061STony Finch /* Various handles */
85c343f061STony Finch { "-ARIN", ANICHOST },
86c343f061STony Finch { "-NICAT", "at" QNICHOST_TAIL },
87c343f061STony Finch { "-NORID", "no" QNICHOST_TAIL },
88c343f061STony Finch { "-RIPE", RNICHOST },
89c343f061STony Finch /* Nominet's whois server doesn't return referrals to JANET */
90c343f061STony Finch { ".ac.uk", "ac.uk" QNICHOST_TAIL },
91751af43eSTony Finch { ".gov.uk", "ac.uk" QNICHOST_TAIL },
926f4d88dfSTony Finch { "", IANAHOST }, /* default */
936f4d88dfSTony Finch { NULL, NULL } /* safety belt */
94c343f061STony Finch };
95c343f061STony Finch
9652517c0aSTony Finch #define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
9752517c0aSTony Finch static struct {
9852517c0aSTony Finch const char *prefix;
9952517c0aSTony Finch size_t len;
10052517c0aSTony Finch } whois_referral[] = {
1016f4d88dfSTony Finch WHOIS_REFERRAL("whois:"), /* IANA */
10252517c0aSTony Finch WHOIS_REFERRAL("Whois Server:"),
1036f4d88dfSTony Finch WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
1046f4d88dfSTony Finch WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
105aa949e8aSMark Johnston WHOIS_REFERRAL("ReferralServer: rwhois://"), /* ARIN */
10642e88fe6STony Finch WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
10752517c0aSTony Finch { NULL, 0 }
10852517c0aSTony Finch };
10952517c0aSTony Finch
1103997df0cSTony Finch /*
1113997df0cSTony Finch * We have a list of patterns for RIRs that assert ignorance rather than
1123997df0cSTony Finch * providing referrals. If that happens, we guess that ARIN will be more
1133997df0cSTony Finch * helpful. But, before following a referral to an RIR, we check if we have
1143997df0cSTony Finch * asked that RIR already, and if so we make another guess.
1153997df0cSTony Finch */
11642e88fe6STony Finch static const char *actually_arin[] = {
11742e88fe6STony Finch "netname: ERX-NETBLOCK\n", /* APNIC */
11842e88fe6STony Finch "netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
11942e88fe6STony Finch NULL
12042e88fe6STony Finch };
12142e88fe6STony Finch
1223997df0cSTony Finch static struct {
1233997df0cSTony Finch int loop;
1243997df0cSTony Finch const char *host;
1253997df0cSTony Finch } try_rir[] = {
1263997df0cSTony Finch { 0, ANICHOST },
1273997df0cSTony Finch { 0, RNICHOST },
1283997df0cSTony Finch { 0, PNICHOST },
1293997df0cSTony Finch { 0, FNICHOST },
1303997df0cSTony Finch { 0, LNICHOST },
1313997df0cSTony Finch { 0, NULL }
1323997df0cSTony Finch };
1333997df0cSTony Finch
1343997df0cSTony Finch static void
reset_rir(void)1353997df0cSTony Finch reset_rir(void) {
1363997df0cSTony Finch int i;
1373997df0cSTony Finch
1383997df0cSTony Finch for (i = 0; try_rir[i].host != NULL; i++)
1393997df0cSTony Finch try_rir[i].loop = 0;
1403997df0cSTony Finch }
1413997df0cSTony Finch
142e5ec9055SEd Schouten static const char *port = DEFAULT_PORT;
14340682beaSDima Dorfman
1446f4d88dfSTony Finch static const char *choose_server(char *);
145aa949e8aSMark Johnston static struct addrinfo *gethostinfo(const char *, const char *, int);
14601d71924SKris Kennaway static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3);
147*cccdaf50SAlfonso Gregory static void usage(void) __dead2;
148aa949e8aSMark Johnston static void whois(const char *, const char *, const char *, int);
149741d304eSPhilippe Charnier
150741d304eSPhilippe Charnier int
main(int argc,char * argv[])1519b07a066SDag-Erling Smørgrav main(int argc, char *argv[])
1529b50d902SRodney W. Grimes {
153eade81c9SMike Barcroft const char *country, *host;
1546f4d88dfSTony Finch int ch, flags;
1559b50d902SRodney W. Grimes
156d9fd44ddSPaul Traina #ifdef SOCKS
157d9fd44ddSPaul Traina SOCKSinit(argv[0]);
158d9fd44ddSPaul Traina #endif
159d9fd44ddSPaul Traina
1606f4d88dfSTony Finch country = host = NULL;
1616f4d88dfSTony Finch flags = 0;
16252517c0aSTony Finch while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
1639b07a066SDag-Erling Smørgrav switch (ch) {
164a00fe97dSGarrett Wollman case 'a':
165a00fe97dSGarrett Wollman host = ANICHOST;
166a00fe97dSGarrett Wollman break;
167eade81c9SMike Barcroft case 'A':
168eade81c9SMike Barcroft host = PNICHOST;
169eade81c9SMike Barcroft break;
170fb6dad91SBruce M Simpson case 'b':
171fb6dad91SBruce M Simpson host = ABUSEHOST;
172fb6dad91SBruce M Simpson break;
173eade81c9SMike Barcroft case 'c':
174eade81c9SMike Barcroft country = optarg;
175eade81c9SMike Barcroft break;
17623639a23SJohn Hay case 'f':
17723639a23SJohn Hay host = FNICHOST;
17823639a23SJohn Hay break;
1792712c396SGarrett Wollman case 'g':
1802712c396SGarrett Wollman host = GNICHOST;
1812712c396SGarrett Wollman break;
1829b50d902SRodney W. Grimes case 'h':
1839b50d902SRodney W. Grimes host = optarg;
1849b50d902SRodney W. Grimes break;
185036cc89fSAndrey A. Chernov case 'i':
186036cc89fSAndrey A. Chernov host = INICHOST;
187036cc89fSAndrey A. Chernov break;
1887138e3feSBruce M Simpson case 'I':
1897138e3feSBruce M Simpson host = IANAHOST;
1907138e3feSBruce M Simpson break;
191876b0a88SCeri Davies case 'k':
192876b0a88SCeri Davies host = KNICHOST;
193876b0a88SCeri Davies break;
194a5d96e6dSMike Barcroft case 'l':
195a5d96e6dSMike Barcroft host = LNICHOST;
196a5d96e6dSMike Barcroft break;
1972053e9a3SAndrey A. Chernov case 'm':
1982053e9a3SAndrey A. Chernov host = MNICHOST;
1992053e9a3SAndrey A. Chernov break;
200a00fe97dSGarrett Wollman case 'p':
201eade81c9SMike Barcroft port = optarg;
202a00fe97dSGarrett Wollman break;
20360214b7fSTony Finch case 'P':
20460214b7fSTony Finch host = PDBHOST;
20560214b7fSTony Finch break;
2062053e9a3SAndrey A. Chernov case 'Q':
2072053e9a3SAndrey A. Chernov flags |= WHOIS_QUICK;
2082053e9a3SAndrey A. Chernov break;
209a00fe97dSGarrett Wollman case 'r':
210a00fe97dSGarrett Wollman host = RNICHOST;
211a00fe97dSGarrett Wollman break;
21252517c0aSTony Finch case 'R':
21352517c0aSTony Finch flags |= WHOIS_RECURSE;
21452517c0aSTony Finch break;
21552517c0aSTony Finch case 'S':
21652517c0aSTony Finch flags |= WHOIS_SPAM_ME;
21752517c0aSTony Finch break;
2189b50d902SRodney W. Grimes case '?':
2199b50d902SRodney W. Grimes default:
2209b50d902SRodney W. Grimes usage();
2219b07a066SDag-Erling Smørgrav /* NOTREACHED */
2229b50d902SRodney W. Grimes }
2234fb37726SJosef Karthauser }
2249b50d902SRodney W. Grimes argc -= optind;
2259b50d902SRodney W. Grimes argv += optind;
2269b50d902SRodney W. Grimes
227eade81c9SMike Barcroft if (!argc || (country != NULL && host != NULL))
2289b50d902SRodney W. Grimes usage();
2299b50d902SRodney W. Grimes
2302053e9a3SAndrey A. Chernov /*
2316f4d88dfSTony Finch * If no host or country is specified, rely on referrals from IANA.
2322053e9a3SAndrey A. Chernov */
233eade81c9SMike Barcroft if (host == NULL && country == NULL) {
2340279f129STony Finch if ((host = getenv("WHOIS_SERVER")) == NULL &&
2350279f129STony Finch (host = getenv("RA_SERVER")) == NULL) {
2369b07a066SDag-Erling Smørgrav if (!(flags & WHOIS_QUICK))
23742ab40e5SMike Barcroft flags |= WHOIS_RECURSE;
2382053e9a3SAndrey A. Chernov }
239f35f40c5SHajimu UMEMOTO }
240f971bd06SMike Barcroft while (argc-- > 0) {
241eade81c9SMike Barcroft if (country != NULL) {
2426f4d88dfSTony Finch char *qnichost;
243eade81c9SMike Barcroft s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
244aa949e8aSMark Johnston whois(*argv, qnichost, port, flags);
2459b07a066SDag-Erling Smørgrav free(qnichost);
2466f4d88dfSTony Finch } else
2476f4d88dfSTony Finch whois(*argv, host != NULL ? host :
248aa949e8aSMark Johnston choose_server(*argv), port, flags);
2493997df0cSTony Finch reset_rir();
250f971bd06SMike Barcroft argv++;
2512053e9a3SAndrey A. Chernov }
2522053e9a3SAndrey A. Chernov exit(0);
2532053e9a3SAndrey A. Chernov }
2542053e9a3SAndrey A. Chernov
2556f4d88dfSTony Finch static const char *
choose_server(char * domain)2566c56da4aSMike Barcroft choose_server(char *domain)
2576c56da4aSMike Barcroft {
2586f4d88dfSTony Finch size_t len = strlen(domain);
259c343f061STony Finch int i;
2606c56da4aSMike Barcroft
261c343f061STony Finch for (i = 0; whoiswhere[i].suffix != NULL; i++) {
262c343f061STony Finch size_t suffix_len = strlen(whoiswhere[i].suffix);
2636f4d88dfSTony Finch if (len > suffix_len &&
2646f4d88dfSTony Finch strcasecmp(domain + len - suffix_len,
2656f4d88dfSTony Finch whoiswhere[i].suffix) == 0)
2666f4d88dfSTony Finch return (whoiswhere[i].server);
26705854331SEivind Eklund }
2686f4d88dfSTony Finch errx(EX_SOFTWARE, "no default whois server");
2691326bf51STony Finch }
2706c56da4aSMike Barcroft
271197bca2cSMike Barcroft static struct addrinfo *
gethostinfo(const char * host,const char * hport,int exit_on_noname)272aa949e8aSMark Johnston gethostinfo(const char *host, const char *hport, int exit_on_noname)
273197bca2cSMike Barcroft {
274197bca2cSMike Barcroft struct addrinfo hints, *res;
275197bca2cSMike Barcroft int error;
276197bca2cSMike Barcroft
277197bca2cSMike Barcroft memset(&hints, 0, sizeof(hints));
27852517c0aSTony Finch hints.ai_flags = AI_CANONNAME;
279197bca2cSMike Barcroft hints.ai_family = AF_UNSPEC;
280197bca2cSMike Barcroft hints.ai_socktype = SOCK_STREAM;
2811326bf51STony Finch res = NULL;
282aa949e8aSMark Johnston error = getaddrinfo(host, hport, &hints, &res);
2831326bf51STony Finch if (error && (exit_on_noname || error != EAI_NONAME))
2841326bf51STony Finch err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
285197bca2cSMike Barcroft return (res);
286197bca2cSMike Barcroft }
287197bca2cSMike Barcroft
288197bca2cSMike Barcroft /*
289197bca2cSMike Barcroft * Wrapper for asprintf(3) that exits on error.
290197bca2cSMike Barcroft */
291197bca2cSMike Barcroft static void
s_asprintf(char ** ret,const char * format,...)292197bca2cSMike Barcroft s_asprintf(char **ret, const char *format, ...)
293197bca2cSMike Barcroft {
294197bca2cSMike Barcroft va_list ap;
295197bca2cSMike Barcroft
296197bca2cSMike Barcroft va_start(ap, format);
297197bca2cSMike Barcroft if (vasprintf(ret, format, ap) == -1) {
298197bca2cSMike Barcroft va_end(ap);
299197bca2cSMike Barcroft err(EX_OSERR, "vasprintf()");
300197bca2cSMike Barcroft }
301197bca2cSMike Barcroft va_end(ap);
302197bca2cSMike Barcroft }
303197bca2cSMike Barcroft
30468c47fcfSConrad Meyer static int
connect_to_any_host(struct addrinfo * hostres)30568c47fcfSConrad Meyer connect_to_any_host(struct addrinfo *hostres)
3062053e9a3SAndrey A. Chernov {
30768c47fcfSConrad Meyer struct addrinfo *res;
308298383b0STony Finch nfds_t i, j;
30968c47fcfSConrad Meyer size_t count;
3103cddd28eSXin LI struct pollfd *fds;
31168c47fcfSConrad Meyer int timeout = 180, s = -1;
3122053e9a3SAndrey A. Chernov
3133cddd28eSXin LI for (res = hostres, count = 0; res; res = res->ai_next)
3143cddd28eSXin LI count++;
3153cddd28eSXin LI fds = calloc(count, sizeof(*fds));
3163cddd28eSXin LI if (fds == NULL)
3173cddd28eSXin LI err(EX_OSERR, "calloc()");
3183cddd28eSXin LI
3193cddd28eSXin LI /*
3203cddd28eSXin LI * Traverse the result list elements and make non-block
3213cddd28eSXin LI * connection attempts.
3223cddd28eSXin LI */
3233cddd28eSXin LI count = i = 0;
3243cddd28eSXin LI for (res = hostres; res != NULL; res = res->ai_next) {
3253cddd28eSXin LI s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
3263cddd28eSXin LI res->ai_protocol);
3279b07a066SDag-Erling Smørgrav if (s < 0)
3282c5958aaSHajimu UMEMOTO continue;
3293cddd28eSXin LI if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
3303cddd28eSXin LI if (errno == EINPROGRESS) {
3313cddd28eSXin LI /* Add the socket to poll list */
3323cddd28eSXin LI fds[i].fd = s;
3333cddd28eSXin LI fds[i].events = POLLERR | POLLHUP |
3343cddd28eSXin LI POLLIN | POLLOUT;
335c24375a7SConrad Meyer /*
336c24375a7SConrad Meyer * From here until a socket connects, the
337c24375a7SConrad Meyer * socket fd is owned by the fds[] poll array.
338c24375a7SConrad Meyer */
339c24375a7SConrad Meyer s = -1;
3403cddd28eSXin LI count++;
3413cddd28eSXin LI i++;
3423cddd28eSXin LI } else {
3432c5958aaSHajimu UMEMOTO close(s);
3443cddd28eSXin LI s = -1;
3453cddd28eSXin LI
3463cddd28eSXin LI /*
3473cddd28eSXin LI * Poll only if we have something to poll,
3483cddd28eSXin LI * otherwise just go ahead and try next
3493cddd28eSXin LI * address
3503cddd28eSXin LI */
3513cddd28eSXin LI if (count == 0)
3523cddd28eSXin LI continue;
3532c5958aaSHajimu UMEMOTO }
3543cddd28eSXin LI } else
3553cddd28eSXin LI goto done;
3563cddd28eSXin LI
3573cddd28eSXin LI /*
3583cddd28eSXin LI * If we are at the last address, poll until a connection is
3593cddd28eSXin LI * established or we failed all connection attempts.
3603cddd28eSXin LI */
3613cddd28eSXin LI if (res->ai_next == NULL)
3623cddd28eSXin LI timeout = INFTIM;
3633cddd28eSXin LI
3643cddd28eSXin LI /*
3653cddd28eSXin LI * Poll the watched descriptors for successful connections:
3663cddd28eSXin LI * if we still have more untried resolved addresses, poll only
3673cddd28eSXin LI * once; otherwise, poll until all descriptors have errors,
3683cddd28eSXin LI * which will be considered as ETIMEDOUT later.
3693cddd28eSXin LI */
3703cddd28eSXin LI do {
3713cddd28eSXin LI int n;
3723cddd28eSXin LI
3733cddd28eSXin LI n = poll(fds, i, timeout);
3743cddd28eSXin LI if (n == 0) {
3753cddd28eSXin LI /*
3763cddd28eSXin LI * No event reported in time. Try with a
3773cddd28eSXin LI * smaller timeout (but cap at 2-3ms)
3783cddd28eSXin LI * after a new host have been added.
3793cddd28eSXin LI */
3803cddd28eSXin LI if (timeout >= 3)
381c24375a7SConrad Meyer timeout >>= 1;
3823cddd28eSXin LI
3833cddd28eSXin LI break;
3843cddd28eSXin LI } else if (n < 0) {
3853cddd28eSXin LI /*
3866f4d88dfSTony Finch * errno here can only be EINTR which we would
3876f4d88dfSTony Finch * want to clean up and bail out.
3883cddd28eSXin LI */
3893cddd28eSXin LI s = -1;
3903cddd28eSXin LI goto done;
3913cddd28eSXin LI }
3923cddd28eSXin LI
3933cddd28eSXin LI /*
3943cddd28eSXin LI * Check for the event(s) we have seen.
3953cddd28eSXin LI */
3963cddd28eSXin LI for (j = 0; j < i; j++) {
3973cddd28eSXin LI if (fds[j].fd == -1 || fds[j].events == 0 ||
3983cddd28eSXin LI fds[j].revents == 0)
3993cddd28eSXin LI continue;
4003cddd28eSXin LI if (fds[j].revents & ~(POLLIN | POLLOUT)) {
401c24375a7SConrad Meyer close(fds[j].fd);
4023cddd28eSXin LI fds[j].fd = -1;
4033cddd28eSXin LI fds[j].events = 0;
4043cddd28eSXin LI count--;
4053cddd28eSXin LI continue;
4063cddd28eSXin LI } else if (fds[j].revents & (POLLIN | POLLOUT)) {
4073cddd28eSXin LI /* Connect succeeded. */
4083cddd28eSXin LI s = fds[j].fd;
409c24375a7SConrad Meyer fds[j].fd = -1;
4103cddd28eSXin LI
4113cddd28eSXin LI goto done;
4123cddd28eSXin LI }
4133cddd28eSXin LI
4143cddd28eSXin LI }
4153cddd28eSXin LI } while (timeout == INFTIM && count != 0);
4163cddd28eSXin LI }
4173cddd28eSXin LI
4183cddd28eSXin LI /* All attempts were failed */
4193cddd28eSXin LI s = -1;
4203cddd28eSXin LI if (count == 0)
4213cddd28eSXin LI errno = ETIMEDOUT;
4226f4d88dfSTony Finch
42368c47fcfSConrad Meyer done:
4243cddd28eSXin LI /* Close all watched fds except the succeeded one */
4253cddd28eSXin LI for (j = 0; j < i; j++)
426c24375a7SConrad Meyer if (fds[j].fd != -1)
4273cddd28eSXin LI close(fds[j].fd);
4286f4d88dfSTony Finch free(fds);
42968c47fcfSConrad Meyer return (s);
43068c47fcfSConrad Meyer }
43168c47fcfSConrad Meyer
43268c47fcfSConrad Meyer static void
whois(const char * query,const char * hostname,const char * hostport,int flags)433aa949e8aSMark Johnston whois(const char *query, const char *hostname, const char *hostport, int flags)
43468c47fcfSConrad Meyer {
43568c47fcfSConrad Meyer FILE *fp;
43668c47fcfSConrad Meyer struct addrinfo *hostres;
437aa949e8aSMark Johnston char *buf, *host, *nhost, *nport, *p;
4383997df0cSTony Finch int comment, s, f;
43968c47fcfSConrad Meyer size_t len, i;
44068c47fcfSConrad Meyer
441aa949e8aSMark Johnston hostres = gethostinfo(hostname, hostport, 1);
44268c47fcfSConrad Meyer s = connect_to_any_host(hostres);
44368c47fcfSConrad Meyer if (s == -1)
44468c47fcfSConrad Meyer err(EX_OSERR, "connect()");
4453cddd28eSXin LI
4463cddd28eSXin LI /* Restore default blocking behavior. */
4476f4d88dfSTony Finch if ((f = fcntl(s, F_GETFL)) == -1)
4486f4d88dfSTony Finch err(EX_OSERR, "fcntl()");
44935859f3aSTony Finch f &= ~O_NONBLOCK;
45035859f3aSTony Finch if (fcntl(s, F_SETFL, f) == -1)
4513cddd28eSXin LI err(EX_OSERR, "fcntl()");
452a00fe97dSGarrett Wollman
453372ab06eSKevin Lo fp = fdopen(s, "r+");
454372ab06eSKevin Lo if (fp == NULL)
4559b07a066SDag-Erling Smørgrav err(EX_OSERR, "fdopen()");
4566f4d88dfSTony Finch
4576f4d88dfSTony Finch if (!(flags & WHOIS_SPAM_ME) &&
458f537d420STony Finch (strcasecmp(hostname, DENICHOST) == 0 ||
459f537d420STony Finch strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
460f537d420STony Finch const char *q;
461f537d420STony Finch int idn = 0;
462f537d420STony Finch for (q = query; *q != '\0'; q++)
463f537d420STony Finch if (!isascii(*q))
464f537d420STony Finch idn = 1;
465f537d420STony Finch fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
466f537d420STony Finch } else if (!(flags & WHOIS_SPAM_ME) &&
467f537d420STony Finch (strcasecmp(hostname, DKNICHOST) == 0 ||
468f537d420STony Finch strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
469372ab06eSKevin Lo fprintf(fp, "--show-handles %s\r\n", query);
4706f4d88dfSTony Finch else if ((flags & WHOIS_SPAM_ME) ||
4716f4d88dfSTony Finch strchr(query, ' ') != NULL)
472372ab06eSKevin Lo fprintf(fp, "%s\r\n", query);
4738efb5aa1STony Finch else if (strcasecmp(hostname, ANICHOST) == 0) {
4748efb5aa1STony Finch if (strncasecmp(query, "AS", 2) == 0 &&
4758efb5aa1STony Finch strspn(query+2, "0123456789") == strlen(query+2))
4768efb5aa1STony Finch fprintf(fp, "+ a %s\r\n", query+2);
4778efb5aa1STony Finch else
4786f4d88dfSTony Finch fprintf(fp, "+ %s\r\n", query);
4798efb5aa1STony Finch } else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
4806f4d88dfSTony Finch fprintf(fp, "domain %s\r\n", query);
4816f4d88dfSTony Finch else
4826f4d88dfSTony Finch fprintf(fp, "%s\r\n", query);
483372ab06eSKevin Lo fflush(fp);
4846f4d88dfSTony Finch
4853997df0cSTony Finch comment = 0;
4863997df0cSTony Finch if (!(flags & WHOIS_SPAM_ME) &&
4873997df0cSTony Finch (strcasecmp(hostname, ANICHOST) == 0 ||
4883997df0cSTony Finch strcasecmp(hostname, RNICHOST) == 0)) {
4893997df0cSTony Finch comment = 2;
4903997df0cSTony Finch }
4913997df0cSTony Finch
4922053e9a3SAndrey A. Chernov nhost = NULL;
493372ab06eSKevin Lo while ((buf = fgetln(fp, &len)) != NULL) {
4946f4d88dfSTony Finch /* Nominet */
4956f4d88dfSTony Finch if (!(flags & WHOIS_SPAM_ME) &&
4966f4d88dfSTony Finch len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
4976f4d88dfSTony Finch break;
4983997df0cSTony Finch /* RIRs */
4993997df0cSTony Finch if (comment == 1 && buf[0] == '#')
5003997df0cSTony Finch break;
5013997df0cSTony Finch else if (comment == 2) {
5023997df0cSTony Finch if (strchr("#%\r\n", buf[0]) != NULL)
5033997df0cSTony Finch continue;
5043997df0cSTony Finch else
5053997df0cSTony Finch comment = 1;
5063997df0cSTony Finch }
5076f4d88dfSTony Finch
5086f4d88dfSTony Finch printf("%.*s", (int)len, buf);
5099b07a066SDag-Erling Smørgrav
51040682beaSDima Dorfman if ((flags & WHOIS_RECURSE) && nhost == NULL) {
51152517c0aSTony Finch for (i = 0; whois_referral[i].prefix != NULL; i++) {
5126f4d88dfSTony Finch p = buf;
5136f4d88dfSTony Finch SCAN(p, buf+len, *p == ' ');
5146f4d88dfSTony Finch if (strncasecmp(p, whois_referral[i].prefix,
51552517c0aSTony Finch whois_referral[i].len) != 0)
51652517c0aSTony Finch continue;
5176f4d88dfSTony Finch p += whois_referral[i].len;
5186f4d88dfSTony Finch SCAN(p, buf+len, *p == ' ');
5196f4d88dfSTony Finch host = p;
5206f4d88dfSTony Finch SCAN(p, buf+len, ishost(*p));
521aa949e8aSMark Johnston if (p > host) {
522aa949e8aSMark Johnston char *pstr;
523aa949e8aSMark Johnston
52442ab40e5SMike Barcroft s_asprintf(&nhost, "%.*s",
52552517c0aSTony Finch (int)(p - host), host);
526aa949e8aSMark Johnston
527aa949e8aSMark Johnston if (*p != ':') {
528aa949e8aSMark Johnston s_asprintf(&nport, "%s", port);
529aa949e8aSMark Johnston break;
530aa949e8aSMark Johnston }
531aa949e8aSMark Johnston
532aa949e8aSMark Johnston pstr = ++p;
533aa949e8aSMark Johnston SCAN(p, buf+len, isdigit(*p));
534aa949e8aSMark Johnston if (p > pstr && (p - pstr) < 6) {
535aa949e8aSMark Johnston s_asprintf(&nport, "%.*s",
536aa949e8aSMark Johnston (int)(p - pstr), pstr);
537aa949e8aSMark Johnston break;
538aa949e8aSMark Johnston }
539aa949e8aSMark Johnston
540aa949e8aSMark Johnston /* Invalid port; don't recurse */
541aa949e8aSMark Johnston free(nhost);
542aa949e8aSMark Johnston nhost = NULL;
543aa949e8aSMark Johnston }
54496db1251SOllivier Robert break;
54596db1251SOllivier Robert }
54642e88fe6STony Finch for (i = 0; actually_arin[i] != NULL; i++) {
54742e88fe6STony Finch if (strncmp(buf, actually_arin[i], len) == 0) {
54842e88fe6STony Finch s_asprintf(&nhost, "%s", ANICHOST);
549aa949e8aSMark Johnston s_asprintf(&nport, "%s", port);
55042e88fe6STony Finch break;
55142e88fe6STony Finch }
55242e88fe6STony Finch }
55396db1251SOllivier Robert }
5546f4d88dfSTony Finch /* Verisign etc. */
5556f4d88dfSTony Finch if (!(flags & WHOIS_SPAM_ME) &&
5566f4d88dfSTony Finch len >= sizeof(CHOPSPAM)-1 &&
5576f4d88dfSTony Finch (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
5586f4d88dfSTony Finch strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
5596f4d88dfSTony Finch printf("\n");
5606f4d88dfSTony Finch break;
5616f4d88dfSTony Finch }
5622053e9a3SAndrey A. Chernov }
563372ab06eSKevin Lo fclose(fp);
5646f4d88dfSTony Finch freeaddrinfo(hostres);
5653997df0cSTony Finch
5663997df0cSTony Finch f = 0;
5673997df0cSTony Finch for (i = 0; try_rir[i].host != NULL; i++) {
5683997df0cSTony Finch /* Remember visits to RIRs */
5693997df0cSTony Finch if (try_rir[i].loop == 0 &&
5703997df0cSTony Finch strcasecmp(try_rir[i].host, hostname) == 0)
5713997df0cSTony Finch try_rir[i].loop = 1;
5723997df0cSTony Finch /* Do we need to find an alternative RIR? */
5733997df0cSTony Finch if (try_rir[i].loop != 0 && nhost != NULL &&
5743997df0cSTony Finch strcasecmp(try_rir[i].host, nhost) == 0) {
5753997df0cSTony Finch free(nhost);
5763997df0cSTony Finch nhost = NULL;
577aa949e8aSMark Johnston free(nport);
578aa949e8aSMark Johnston nport = NULL;
5793997df0cSTony Finch f = 1;
5803997df0cSTony Finch }
5813997df0cSTony Finch }
5823997df0cSTony Finch if (f) {
5833997df0cSTony Finch /* Find a replacement RIR */
5843997df0cSTony Finch for (i = 0; try_rir[i].host != NULL; i++) {
5853997df0cSTony Finch if (try_rir[i].loop == 0) {
586aa949e8aSMark Johnston s_asprintf(&nhost, "%s", try_rir[i].host);
587aa949e8aSMark Johnston s_asprintf(&nport, "%s", port);
5883997df0cSTony Finch break;
5893997df0cSTony Finch }
5903997df0cSTony Finch }
5913997df0cSTony Finch }
5929b07a066SDag-Erling Smørgrav if (nhost != NULL) {
5933997df0cSTony Finch /* Ignore self-referrals */
5943997df0cSTony Finch if (strcasecmp(hostname, nhost) != 0) {
5953997df0cSTony Finch printf("# %s\n\n", nhost);
596aa949e8aSMark Johnston whois(query, nhost, nport, flags);
5973997df0cSTony Finch }
5989b07a066SDag-Erling Smørgrav free(nhost);
599aa949e8aSMark Johnston free(nport);
6002053e9a3SAndrey A. Chernov }
6019b50d902SRodney W. Grimes }
6029b50d902SRodney W. Grimes
603741d304eSPhilippe Charnier static void
usage(void)6049b07a066SDag-Erling Smørgrav usage(void)
6059b50d902SRodney W. Grimes {
6069b07a066SDag-Erling Smørgrav fprintf(stderr,
607de80c945STony Finch "usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
608eade81c9SMike Barcroft "[-p port] name ...\n");
609a00fe97dSGarrett Wollman exit(EX_USAGE);
6109b50d902SRodney W. Grimes }
611