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