xref: /freebsd/usr.bin/whois/whois.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1980, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)whois.c	8.1 (Berkeley) 6/6/93";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47 
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <ctype.h>
53 #include <err.h>
54 #include <netdb.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <sysexits.h>
59 #include <unistd.h>
60 
61 #define	NICHOST		"whois.crsnic.net"
62 #define	INICHOST	"whois.networksolutions.com"
63 #define	DNICHOST	"whois.nic.mil"
64 #define	GNICHOST	"whois.nic.gov"
65 #define	ANICHOST	"whois.arin.net"
66 #define	RNICHOST	"whois.ripe.net"
67 #define	PNICHOST	"whois.apnic.net"
68 #define	RUNICHOST	"whois.ripn.net"
69 #define	MNICHOST	"whois.ra.net"
70 #define	QNICHOST_TAIL	".whois-servers.net"
71 #define	SNICHOST	"whois.6bone.net"
72 #define	WHOIS_PORT	43
73 #define	WHOIS_SERVER_ID	"Whois Server: "
74 #define	NO_MATCH_ID	"No match for \""
75 
76 #define WHOIS_RECURSE		0x01
77 #define WHOIS_INIC_FALLBACK	0x02
78 #define WHOIS_QUICK		0x04
79 
80 const char *ip_whois[] = { RNICHOST, PNICHOST, NULL };
81 
82 static void usage(void);
83 static void whois(char *, struct addrinfo *, int);
84 
85 int
86 main(int argc, char *argv[])
87 {
88 	struct addrinfo hints, *res;
89 	const char *host;
90 	char *qnichost;
91 	int ch, error, flags, i, j, use_qnichost;
92 
93 #ifdef	SOCKS
94 	SOCKSinit(argv[0]);
95 #endif
96 
97 	host = NULL;
98 	qnichost = NULL;
99 	flags = 0;
100 	use_qnichost = 0;
101 	while ((ch = getopt(argc, argv, "adgh:impQrR6")) != -1) {
102 		switch (ch) {
103 		case 'a':
104 			host = ANICHOST;
105 			break;
106 		case 'd':
107 			host = DNICHOST;
108 			break;
109 		case 'g':
110 			host = GNICHOST;
111 			break;
112 		case 'h':
113 			host = optarg;
114 			break;
115 		case 'i':
116 			host = INICHOST;
117 			break;
118 		case 'm':
119 			host = MNICHOST;
120 			break;
121 		case 'p':
122 			host = PNICHOST;
123 			break;
124 		case 'Q':
125 			flags |= WHOIS_QUICK;
126 			break;
127 		case 'r':
128 			host = RNICHOST;
129 			break;
130 		case 'R':
131 			host = RUNICHOST;
132 			break;
133 		case '6':
134 			host = SNICHOST;
135 			break;
136 		case '?':
137 		default:
138 			usage();
139 			/* NOTREACHED */
140 		}
141 	}
142 	argc -= optind;
143 	argv += optind;
144 
145 	if (!argc)
146 		usage();
147 
148 	/*
149 	 * If no nic host is specified determine the top level domain from
150 	 * the query.  If the TLD is a number, query ARIN.  Otherwise, use
151 	 * TLD.whois-server.net.  If the domain does not contain '.', fall
152 	 * back to NICHOST.
153 	 */
154 	if (host == NULL) {
155 		use_qnichost = 1;
156 		host = NICHOST;
157 		if (!(flags & WHOIS_QUICK))
158 			flags |= WHOIS_INIC_FALLBACK | WHOIS_RECURSE;
159 	}
160 	while (argc--) {
161 		if (use_qnichost) {
162 			for (i = j = 0; (*argv)[i]; i++)
163 				if ((*argv)[i] == '.')
164 					j = i;
165 			if (j != 0) {
166 				if (isdigit(*(*argv + j + 1))) {
167 					asprintf(&qnichost, "%s", ANICHOST);
168 					if (qnichost == NULL)
169 						err(1, "asprintf()");
170 				} else {
171 					asprintf(&qnichost, "%s%s",
172 					    *argv + j + 1, QNICHOST_TAIL);
173 					if (qnichost == NULL)
174 						err(1, "asprintf()");
175 				}
176 
177 				memset(&hints, 0, sizeof(hints));
178 				hints.ai_flags = 0;
179 				hints.ai_family = AF_UNSPEC;
180 				hints.ai_socktype = SOCK_STREAM;
181 				error = getaddrinfo(qnichost, "whois",
182 				    &hints, &res);
183 				if (error != 0)
184 					errx(EX_NOHOST, "%s: %s", qnichost,
185 					    gai_strerror(error));
186 			}
187 		}
188 		if (qnichost == NULL) {
189 			memset(&hints, 0, sizeof(hints));
190 			hints.ai_flags = 0;
191 			hints.ai_family = AF_UNSPEC;
192 			hints.ai_socktype = SOCK_STREAM;
193 			error = getaddrinfo(host, "whois", &hints, &res);
194 			if (error != 0)
195 				errx(EX_NOHOST, "%s: %s", host,
196 				   gai_strerror(error));
197 		}
198 
199 		free(qnichost);
200 		qnichost = NULL;
201 		whois(*argv++, res, flags);
202 		freeaddrinfo(res);
203 	}
204 	exit(0);
205 }
206 
207 static void
208 whois(char *name, struct addrinfo *res, int flags)
209 {
210 	FILE *sfi, *sfo;
211 	struct addrinfo hints, *res2;
212 	char *buf, *nhost, *p;
213 	int i, nomatch, error, s;
214 	size_t len;
215 
216 	for (; res; res = res->ai_next) {
217 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
218 		if (s < 0)
219 			continue;
220 		if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
221 			break;
222 		close(s);
223 	}
224 	if (res == NULL)
225 		err(EX_OSERR, "connect()");
226 
227 	sfi = fdopen(s, "r");
228 	sfo = fdopen(s, "w");
229 	if (sfi == NULL || sfo == NULL)
230 		err(EX_OSERR, "fdopen()");
231 	fprintf(sfo, "%s\r\n", name);
232 	fflush(sfo);
233 	nhost = NULL;
234 	nomatch = 0;
235 	while ((buf = fgetln(sfi, &len)) != NULL) {
236 		while (len && isspace(buf[len - 1]))
237 			buf[--len] = '\0';
238 
239 		if ((flags & WHOIS_RECURSE) && nhost == NULL) {
240 			p = strstr(buf, WHOIS_SERVER_ID);
241 			if (p != NULL) {
242 				p += sizeof(WHOIS_SERVER_ID) - 1;
243 				if ((len = strcspn(p, " \t\n\r")) != 0) {
244 					asprintf(&nhost, "%s", p);
245 					if (nhost == NULL)
246 						err(1, "asprintf()");
247 				}
248 			} else {
249 				for (i = 0; ip_whois[i] != NULL; i++) {
250 					if (strstr(buf, ip_whois[i]) == NULL)
251 						continue;
252 					nhost = strdup(ip_whois[i]);
253 					if (nhost == NULL)
254 						err(1, "strdup()");
255 				}
256 			}
257 		}
258 
259 		if ((flags & WHOIS_INIC_FALLBACK) && nhost == NULL &&
260 		    !nomatch && (p = strstr(buf, NO_MATCH_ID)) != NULL) {
261 			p += sizeof(NO_MATCH_ID) - 1;
262 			if ((len = strcspn(p, "\"")) &&
263 			    strncasecmp(name, p, len) == 0 &&
264 			    name[len] == '\0' &&
265 			    strchr(name, '.') == NULL)
266 				nomatch = 1;
267 		}
268 		printf("%s\n", buf);
269 	}
270 
271 	/* Do second lookup as needed. */
272 	if (nomatch && nhost == NULL) {
273 		printf("Looking up %s at %s.\n\n", name, INICHOST);
274 		if ((nhost = strdup(INICHOST)) == NULL)
275 			err(1, "strdup()");
276 	}
277 
278 	if (nhost != NULL) {
279 		memset(&hints, 0, sizeof(hints));
280 		hints.ai_flags = 0;
281 		hints.ai_family = AF_UNSPEC;
282 		hints.ai_socktype = SOCK_STREAM;
283 		error = getaddrinfo(nhost, "whois", &hints, &res2);
284 		if (error != 0) {
285 			warnx("%s: %s", nhost, gai_strerror(error));
286 			free(nhost);
287 			return;
288 		}
289 		free(nhost);
290 		whois(name, res2, 0);
291 		freeaddrinfo(res2);
292 	}
293 }
294 
295 static void
296 usage(void)
297 {
298 	fprintf(stderr,
299 	    "usage: whois [-adgimpQrR6] [-h hostname] name ...\n");
300 	exit(EX_USAGE);
301 }
302