17c478bd9Sstevel@tonic-gate /*
21dd3983cSYuri Pankov  * Copyright (c) 1980, 1993
31dd3983cSYuri Pankov  *	The Regents of the University of California.  All rights reserved.
47c478bd9Sstevel@tonic-gate  *
51dd3983cSYuri Pankov  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
67c478bd9Sstevel@tonic-gate  *
7*deeb0f36SJohann 'Myrkraverk' Oskarsson  * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.com>
8*deeb0f36SJohann 'Myrkraverk' Oskarsson  *
91dd3983cSYuri Pankov  * Redistribution and use in source and binary forms, with or without
101dd3983cSYuri Pankov  * modification, are permitted provided that the following conditions
111dd3983cSYuri Pankov  * are met:
121dd3983cSYuri Pankov  * 1. Redistributions of source code must retain the above copyright
131dd3983cSYuri Pankov  *    notice, this list of conditions and the following disclaimer.
141dd3983cSYuri Pankov  * 2. Redistributions in binary form must reproduce the above copyright
151dd3983cSYuri Pankov  *    notice, this list of conditions and the following disclaimer in the
161dd3983cSYuri Pankov  *    documentation and/or other materials provided with the distribution.
171dd3983cSYuri Pankov  * 4. Neither the name of the University nor the names of its contributors
181dd3983cSYuri Pankov  *    may be used to endorse or promote products derived from this software
191dd3983cSYuri Pankov  *    without specific prior written permission.
207c478bd9Sstevel@tonic-gate  *
211dd3983cSYuri Pankov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221dd3983cSYuri Pankov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231dd3983cSYuri Pankov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241dd3983cSYuri Pankov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251dd3983cSYuri Pankov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261dd3983cSYuri Pankov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271dd3983cSYuri Pankov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281dd3983cSYuri Pankov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291dd3983cSYuri Pankov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301dd3983cSYuri Pankov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311dd3983cSYuri Pankov  * SUCH DAMAGE.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/socket.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <netinet/in.h>
381dd3983cSYuri Pankov #include <arpa/inet.h>
391dd3983cSYuri Pankov #include <ctype.h>
401dd3983cSYuri Pankov #include <err.h>
411dd3983cSYuri Pankov #include <limits.h>
427c478bd9Sstevel@tonic-gate #include <netdb.h>
431dd3983cSYuri Pankov #include <stdarg.h>
441dd3983cSYuri Pankov #include <stdio.h>
45f098c48bSDerek Morr #include <stdlib.h>
461dd3983cSYuri Pankov #include <string.h>
471dd3983cSYuri Pankov #include <sysexits.h>
48f098c48bSDerek Morr #include <unistd.h>
497c478bd9Sstevel@tonic-gate 
501dd3983cSYuri Pankov #define	ABUSEHOST	"whois.abuse.net"
511dd3983cSYuri Pankov #define	NICHOST		"whois.crsnic.net"
521dd3983cSYuri Pankov #define	INICHOST	"whois.networksolutions.com"
531dd3983cSYuri Pankov #define	GNICHOST	"whois.nic.gov"
541dd3983cSYuri Pankov #define	ANICHOST	"whois.arin.net"
551dd3983cSYuri Pankov #define	LNICHOST	"whois.lacnic.net"
561dd3983cSYuri Pankov #define	KNICHOST	"whois.krnic.net"
571dd3983cSYuri Pankov #define	RNICHOST	"whois.ripe.net"
581dd3983cSYuri Pankov #define	PNICHOST	"whois.apnic.net"
591dd3983cSYuri Pankov #define	MNICHOST	"whois.ra.net"
601dd3983cSYuri Pankov #define	QNICHOST_TAIL	".whois-servers.net"
611dd3983cSYuri Pankov #define	BNICHOST	"whois.registro.br"
621dd3983cSYuri Pankov #define	NORIDHOST	"whois.norid.no"
631dd3983cSYuri Pankov #define	IANAHOST	"whois.iana.org"
641dd3983cSYuri Pankov #define	GERMNICHOST	"de.whois-servers.net"
651dd3983cSYuri Pankov #define	FNICHOST	"whois.afrinic.net"
661dd3983cSYuri Pankov #define	DEFAULT_PORT	"whois"
671dd3983cSYuri Pankov #define	WHOIS_SERVER_ID	"Whois Server: "
681dd3983cSYuri Pankov #define	WHOIS_ORG_SERVER_ID	"Registrant Street1:Whois Server:"
691dd3983cSYuri Pankov 
701dd3983cSYuri Pankov #define	WHOIS_RECURSE		0x01
711dd3983cSYuri Pankov #define	WHOIS_QUICK		0x02
721dd3983cSYuri Pankov 
731dd3983cSYuri Pankov #define	ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
741dd3983cSYuri Pankov 
751dd3983cSYuri Pankov const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST,
761dd3983cSYuri Pankov     FNICHOST, NULL };
771dd3983cSYuri Pankov const char *port = DEFAULT_PORT;
781dd3983cSYuri Pankov 
791dd3983cSYuri Pankov static char *choose_server(char *);
801dd3983cSYuri Pankov static struct addrinfo *gethostinfo(char const *host, int exit_on_error);
811dd3983cSYuri Pankov static void s_asprintf(char **ret, const char *format, ...);
821dd3983cSYuri Pankov static void usage(void);
831dd3983cSYuri Pankov static void whois(const char *, const char *, int);
847c478bd9Sstevel@tonic-gate 
85740638c8Sbw int
main(int argc,char * argv[])86f098c48bSDerek Morr main(int argc, char *argv[])
877c478bd9Sstevel@tonic-gate {
881dd3983cSYuri Pankov 	const char *country, *host;
891dd3983cSYuri Pankov 	char *qnichost;
901dd3983cSYuri Pankov 	int ch, flags, use_qnichost;
911dd3983cSYuri Pankov 
921dd3983cSYuri Pankov 	country = host = qnichost = NULL;
931dd3983cSYuri Pankov 	flags = use_qnichost = 0;
941dd3983cSYuri Pankov 	while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:Qr")) != -1) {
951dd3983cSYuri Pankov 		switch (ch) {
961dd3983cSYuri Pankov 		case 'a':
971dd3983cSYuri Pankov 			host = ANICHOST;
981dd3983cSYuri Pankov 			break;
991dd3983cSYuri Pankov 		case 'A':
1001dd3983cSYuri Pankov 			host = PNICHOST;
1011dd3983cSYuri Pankov 			break;
1021dd3983cSYuri Pankov 		case 'b':
1031dd3983cSYuri Pankov 			host = ABUSEHOST;
1041dd3983cSYuri Pankov 			break;
1051dd3983cSYuri Pankov 		case 'c':
1061dd3983cSYuri Pankov 			country = optarg;
1071dd3983cSYuri Pankov 			break;
1081dd3983cSYuri Pankov 		case 'f':
1091dd3983cSYuri Pankov 			host = FNICHOST;
1101dd3983cSYuri Pankov 			break;
1111dd3983cSYuri Pankov 		case 'g':
1121dd3983cSYuri Pankov 			host = GNICHOST;
1131dd3983cSYuri Pankov 			break;
1141dd3983cSYuri Pankov 		case 'h':
1151dd3983cSYuri Pankov 			host = optarg;
1161dd3983cSYuri Pankov 			break;
1171dd3983cSYuri Pankov 		case 'i':
1181dd3983cSYuri Pankov 			host = INICHOST;
1191dd3983cSYuri Pankov 			break;
1201dd3983cSYuri Pankov 		case 'I':
1211dd3983cSYuri Pankov 			host = IANAHOST;
1221dd3983cSYuri Pankov 			break;
1231dd3983cSYuri Pankov 		case 'k':
1241dd3983cSYuri Pankov 			host = KNICHOST;
1251dd3983cSYuri Pankov 			break;
1261dd3983cSYuri Pankov 		case 'l':
1271dd3983cSYuri Pankov 			host = LNICHOST;
1281dd3983cSYuri Pankov 			break;
1291dd3983cSYuri Pankov 		case 'm':
1301dd3983cSYuri Pankov 			host = MNICHOST;
1311dd3983cSYuri Pankov 			break;
1321dd3983cSYuri Pankov 		case 'p':
1331dd3983cSYuri Pankov 			port = optarg;
1341dd3983cSYuri Pankov 			break;
1351dd3983cSYuri Pankov 		case 'Q':
1361dd3983cSYuri Pankov 			flags |= WHOIS_QUICK;
1371dd3983cSYuri Pankov 			break;
1381dd3983cSYuri Pankov 		case 'r':
1391dd3983cSYuri Pankov 			host = RNICHOST;
1401dd3983cSYuri Pankov 			break;
1411dd3983cSYuri Pankov 		case '?':
1421dd3983cSYuri Pankov 		default:
1431dd3983cSYuri Pankov 			usage();
1441dd3983cSYuri Pankov 			/* NOTREACHED */
1451dd3983cSYuri Pankov 		}
1467c478bd9Sstevel@tonic-gate 	}
1471dd3983cSYuri Pankov 	argc -= optind;
1481dd3983cSYuri Pankov 	argv += optind;
1491dd3983cSYuri Pankov 
1501dd3983cSYuri Pankov 	if (!argc || (country != NULL && host != NULL))
1511dd3983cSYuri Pankov 		usage();
1521dd3983cSYuri Pankov 
1531dd3983cSYuri Pankov 	/*
1541dd3983cSYuri Pankov 	 * If no host or country is specified determine the top level domain
1551dd3983cSYuri Pankov 	 * from the query.  If the TLD is a number, query ARIN.  Otherwise, use
1561dd3983cSYuri Pankov 	 * TLD.whois-server.net.  If the domain does not contain '.', fall
1571dd3983cSYuri Pankov 	 * back to NICHOST.
1581dd3983cSYuri Pankov 	 */
1591dd3983cSYuri Pankov 	if (host == NULL && country == NULL) {
1601dd3983cSYuri Pankov 		use_qnichost = 1;
1611dd3983cSYuri Pankov 		host = NICHOST;
1621dd3983cSYuri Pankov 		if (!(flags & WHOIS_QUICK))
1631dd3983cSYuri Pankov 			flags |= WHOIS_RECURSE;
1647c478bd9Sstevel@tonic-gate 	}
1651dd3983cSYuri Pankov 	while (argc-- > 0) {
1661dd3983cSYuri Pankov 		if (country != NULL) {
1671dd3983cSYuri Pankov 			s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
1681dd3983cSYuri Pankov 			whois(*argv, qnichost, flags);
1691dd3983cSYuri Pankov 		} else if (use_qnichost)
1701dd3983cSYuri Pankov 			if ((qnichost = choose_server(*argv)) != NULL)
1711dd3983cSYuri Pankov 				whois(*argv, qnichost, flags);
1721dd3983cSYuri Pankov 		if (qnichost == NULL)
1731dd3983cSYuri Pankov 			whois(*argv, host, flags);
1741dd3983cSYuri Pankov 		free(qnichost);
1751dd3983cSYuri Pankov 		qnichost = NULL;
1761dd3983cSYuri Pankov 		argv++;
1771dd3983cSYuri Pankov 	}
1781dd3983cSYuri Pankov 
1791dd3983cSYuri Pankov 	return (0);
1801dd3983cSYuri Pankov }
1811dd3983cSYuri Pankov 
1821dd3983cSYuri Pankov /*
1831dd3983cSYuri Pankov  * This function will remove any trailing periods from domain, after which it
1841dd3983cSYuri Pankov  * returns a pointer to newly allocated memory containing the whois server to
1851dd3983cSYuri Pankov  * be queried, or a NULL if the correct server couldn't be determined.  The
1861dd3983cSYuri Pankov  * caller must remember to free(3) the allocated memory.
1871dd3983cSYuri Pankov  */
1881dd3983cSYuri Pankov static char *
choose_server(char * domain)1891dd3983cSYuri Pankov choose_server(char *domain)
1901dd3983cSYuri Pankov {
1911dd3983cSYuri Pankov 	char *pos, *retval;
1921dd3983cSYuri Pankov 
1931dd3983cSYuri Pankov 	if (strchr(domain, ':')) {
1941dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", ANICHOST);
1951dd3983cSYuri Pankov 		return (retval);
1961dd3983cSYuri Pankov 	}
1971dd3983cSYuri Pankov 	for (pos = strchr(domain, '\0'); pos > domain && *--pos == '.'; )
1981dd3983cSYuri Pankov 		*pos = '\0';
1991dd3983cSYuri Pankov 	if (*domain == '\0')
2001dd3983cSYuri Pankov 		errx(EX_USAGE, "can't search for a null string");
2011dd3983cSYuri Pankov 	if (strlen(domain) > sizeof ("-NORID")-1 &&
2021dd3983cSYuri Pankov 	    strcasecmp(domain + strlen(domain) - sizeof ("-NORID") + 1,
2031dd3983cSYuri Pankov 	    "-NORID") == 0) {
2041dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", NORIDHOST);
2051dd3983cSYuri Pankov 		return (retval);
2061dd3983cSYuri Pankov 	}
2071dd3983cSYuri Pankov 	while (pos > domain && *pos != '.')
2081dd3983cSYuri Pankov 		--pos;
2091dd3983cSYuri Pankov 	if (pos <= domain)
2101dd3983cSYuri Pankov 		return (NULL);
2111dd3983cSYuri Pankov 	if (isdigit((unsigned char)*++pos))
2121dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", ANICHOST);
2131dd3983cSYuri Pankov 	else
2141dd3983cSYuri Pankov 		s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL);
2151dd3983cSYuri Pankov 	return (retval);
2161dd3983cSYuri Pankov }
2171dd3983cSYuri Pankov 
2181dd3983cSYuri Pankov static struct addrinfo *
gethostinfo(char const * host,int exit_on_error)2191dd3983cSYuri Pankov gethostinfo(char const *host, int exit_on_error)
2201dd3983cSYuri Pankov {
2211dd3983cSYuri Pankov 	struct addrinfo hints, *res;
2221dd3983cSYuri Pankov 	int error;
223f098c48bSDerek Morr 
2241dd3983cSYuri Pankov 	(void) memset(&hints, 0, sizeof (hints));
2251dd3983cSYuri Pankov 	hints.ai_flags = 0;
2261dd3983cSYuri Pankov 	hints.ai_family = AF_UNSPEC;
227f098c48bSDerek Morr 	hints.ai_socktype = SOCK_STREAM;
2281dd3983cSYuri Pankov 	error = getaddrinfo(host, port, &hints, &res);
2291dd3983cSYuri Pankov 	if (error) {
2301dd3983cSYuri Pankov 		warnx("%s: %s", host, gai_strerror(error));
2311dd3983cSYuri Pankov 		if (exit_on_error)
2321dd3983cSYuri Pankov 			exit(EX_NOHOST);
2331dd3983cSYuri Pankov 		return (NULL);
234f098c48bSDerek Morr 	}
2351dd3983cSYuri Pankov 	return (res);
2361dd3983cSYuri Pankov }
237f098c48bSDerek Morr 
2381dd3983cSYuri Pankov /*
2391dd3983cSYuri Pankov  * Wrapper for asprintf(3) that exits on error.
2401dd3983cSYuri Pankov  */
2411dd3983cSYuri Pankov /* PRINTFLIKE2 */
2421dd3983cSYuri Pankov static void
s_asprintf(char ** ret,const char * format,...)2431dd3983cSYuri Pankov s_asprintf(char **ret, const char *format, ...)
2441dd3983cSYuri Pankov {
2451dd3983cSYuri Pankov 	va_list ap;
2461dd3983cSYuri Pankov 
2471dd3983cSYuri Pankov 	va_start(ap, format);
2481dd3983cSYuri Pankov 	if (vasprintf(ret, format, ap) == -1) {
2491dd3983cSYuri Pankov 		va_end(ap);
2501dd3983cSYuri Pankov 		err(EX_OSERR, "vasprintf()");
2517c478bd9Sstevel@tonic-gate 	}
2521dd3983cSYuri Pankov 	va_end(ap);
2531dd3983cSYuri Pankov }
2541dd3983cSYuri Pankov 
2551dd3983cSYuri Pankov static void
whois(const char * query,const char * hostname,int flags)2561dd3983cSYuri Pankov whois(const char *query, const char *hostname, int flags)
2571dd3983cSYuri Pankov {
2581dd3983cSYuri Pankov 	FILE *sfi, *sfo;
2591dd3983cSYuri Pankov 	struct addrinfo *hostres, *res;
260*deeb0f36SJohann 'Myrkraverk' Oskarsson 	/*
261*deeb0f36SJohann 'Myrkraverk' Oskarsson 	 * The variables buf and buflen are static so the buffer for
262*deeb0f36SJohann 'Myrkraverk' Oskarsson 	 * getline() is retained across calls.
263*deeb0f36SJohann 'Myrkraverk' Oskarsson 	 */
264*deeb0f36SJohann 'Myrkraverk' Oskarsson 	static char *buf = NULL;
265*deeb0f36SJohann 'Myrkraverk' Oskarsson 	static size_t buflen = 0;
266*deeb0f36SJohann 'Myrkraverk' Oskarsson 	char *host, *nhost, *p;
2671dd3983cSYuri Pankov 	int i, s;
268*deeb0f36SJohann 'Myrkraverk' Oskarsson 	ssize_t c, len;
2691dd3983cSYuri Pankov 
2701dd3983cSYuri Pankov 	s = -1;
2711dd3983cSYuri Pankov 	hostres = gethostinfo(hostname, 1);
2721dd3983cSYuri Pankov 	for (res = hostres; res; res = res->ai_next) {
2731dd3983cSYuri Pankov 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2741dd3983cSYuri Pankov 		if (s < 0)
2751dd3983cSYuri Pankov 			continue;
2761dd3983cSYuri Pankov 		if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
2771dd3983cSYuri Pankov 			break;
2781dd3983cSYuri Pankov 		(void) close(s);
2797c478bd9Sstevel@tonic-gate 	}
2801dd3983cSYuri Pankov 	freeaddrinfo(hostres);
2811dd3983cSYuri Pankov 	if (res == NULL)
2821dd3983cSYuri Pankov 		err(EX_OSERR, "connect()");
283f098c48bSDerek Morr 
2847c478bd9Sstevel@tonic-gate 	sfi = fdopen(s, "r");
2857c478bd9Sstevel@tonic-gate 	sfo = fdopen(s, "w");
2861dd3983cSYuri Pankov 	if (sfi == NULL || sfo == NULL)
2871dd3983cSYuri Pankov 		err(EX_OSERR, "fdopen()");
2881dd3983cSYuri Pankov 	if (strcmp(hostname, GERMNICHOST) == 0) {
2891dd3983cSYuri Pankov 		(void) fprintf(sfo, "-T dn,ace -C US-ASCII %s\r\n", query);
2901dd3983cSYuri Pankov 	} else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) {
2911dd3983cSYuri Pankov 		(void) fprintf(sfo, "--show-handles %s\r\n", query);
2921dd3983cSYuri Pankov 	} else {
2931dd3983cSYuri Pankov 		(void) fprintf(sfo, "%s\r\n", query);
2947c478bd9Sstevel@tonic-gate 	}
29543f842b8SMilan Jurik 	(void) fflush(sfo);
2961dd3983cSYuri Pankov 	nhost = NULL;
297*deeb0f36SJohann 'Myrkraverk' Oskarsson 	while ((len = getline(&buf, &buflen, sfi)) != -1) {
2981dd3983cSYuri Pankov 		while (len > 0 && isspace((unsigned char)buf[len - 1]))
2991dd3983cSYuri Pankov 			buf[--len] = '\0';
3001dd3983cSYuri Pankov 		(void) printf("%.*s\n", (int)len, buf);
3011dd3983cSYuri Pankov 
3021dd3983cSYuri Pankov 		if ((flags & WHOIS_RECURSE) && nhost == NULL) {
3031dd3983cSYuri Pankov 			host = strnstr(buf, WHOIS_SERVER_ID, len);
3041dd3983cSYuri Pankov 			if (host != NULL) {
3051dd3983cSYuri Pankov 				host += sizeof (WHOIS_SERVER_ID) - 1;
3061dd3983cSYuri Pankov 				for (p = host; p < buf + len; p++) {
3071dd3983cSYuri Pankov 					if (!ishost(*p)) {
3081dd3983cSYuri Pankov 						*p = '\0';
3091dd3983cSYuri Pankov 						break;
3101dd3983cSYuri Pankov 					}
3111dd3983cSYuri Pankov 				}
3121dd3983cSYuri Pankov 				s_asprintf(&nhost, "%.*s",
3131dd3983cSYuri Pankov 				    (int)(buf + len - host), host);
3141dd3983cSYuri Pankov 			} else if ((host =
3151dd3983cSYuri Pankov 			    strnstr(buf, WHOIS_ORG_SERVER_ID, len)) != NULL) {
3161dd3983cSYuri Pankov 				host += sizeof (WHOIS_ORG_SERVER_ID) - 1;
3171dd3983cSYuri Pankov 				for (p = host; p < buf + len; p++) {
3181dd3983cSYuri Pankov 					if (!ishost(*p)) {
3191dd3983cSYuri Pankov 						*p = '\0';
3201dd3983cSYuri Pankov 						break;
3211dd3983cSYuri Pankov 					}
3221dd3983cSYuri Pankov 				}
3231dd3983cSYuri Pankov 				s_asprintf(&nhost, "%.*s",
3241dd3983cSYuri Pankov 				    (int)(buf + len - host), host);
3251dd3983cSYuri Pankov 			} else if (strcmp(hostname, ANICHOST) == 0) {
3261dd3983cSYuri Pankov 				for (c = 0; c <= len; c++)
3271dd3983cSYuri Pankov 					buf[c] = tolower((unsigned char)buf[c]);
3281dd3983cSYuri Pankov 				for (i = 0; ip_whois[i] != NULL; i++) {
3291dd3983cSYuri Pankov 					if (strnstr(buf, ip_whois[i], len) !=
3301dd3983cSYuri Pankov 					    NULL) {
3311dd3983cSYuri Pankov 						s_asprintf(&nhost, "%s",
3321dd3983cSYuri Pankov 						    ip_whois[i]);
3331dd3983cSYuri Pankov 						break;
3341dd3983cSYuri Pankov 					}
3351dd3983cSYuri Pankov 				}
3361dd3983cSYuri Pankov 			}
3371dd3983cSYuri Pankov 		}
3381dd3983cSYuri Pankov 	}
3391dd3983cSYuri Pankov 	if (nhost != NULL) {
3401dd3983cSYuri Pankov 		whois(query, nhost, 0);
3411dd3983cSYuri Pankov 		free(nhost);
3421dd3983cSYuri Pankov 	}
3431dd3983cSYuri Pankov }
3441dd3983cSYuri Pankov 
3451dd3983cSYuri Pankov static void
usage(void)3461dd3983cSYuri Pankov usage(void)
3471dd3983cSYuri Pankov {
3481dd3983cSYuri Pankov 	(void) fprintf(stderr,
3491dd3983cSYuri Pankov 	    "usage: whois [-aAbfgiIklmQr] [-c country-code | -h hostname] "
3501dd3983cSYuri Pankov 	    "[-p port] name ...\n");
3511dd3983cSYuri Pankov 	exit(EX_USAGE);
3521dd3983cSYuri Pankov }
353