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 74 #define WHOIS_RECURSE 0x01 75 #define WHOIS_INIC_FALLBACK 0x02 76 #define WHOIS_QUICK 0x04 77 78 static void usage __P((void)); 79 static void whois __P((char *, struct addrinfo *, int)); 80 81 int 82 main(argc, argv) 83 int argc; 84 char **argv; 85 { 86 int ch, i, j, error; 87 int use_qnichost, flags; 88 char *host; 89 char *qnichost; 90 struct addrinfo hints, *res; 91 92 #ifdef SOCKS 93 SOCKSinit(argv[0]); 94 #endif 95 96 host = NULL; 97 qnichost = NULL; 98 flags = 0; 99 use_qnichost = 0; 100 while ((ch = getopt(argc, argv, "adgh:impQrR6")) != -1) { 101 switch((char)ch) { 102 case 'a': 103 host = ANICHOST; 104 break; 105 case 'd': 106 host = DNICHOST; 107 break; 108 case 'g': 109 host = GNICHOST; 110 break; 111 case 'h': 112 host = optarg; 113 break; 114 case 'i': 115 host = INICHOST; 116 break; 117 case 'm': 118 host = MNICHOST; 119 break; 120 case 'p': 121 host = PNICHOST; 122 break; 123 case 'Q': 124 flags |= WHOIS_QUICK; 125 break; 126 case 'r': 127 host = RNICHOST; 128 break; 129 case 'R': 130 host = RUNICHOST; 131 break; 132 case '6': 133 host = SNICHOST; 134 break; 135 case '?': 136 default: 137 usage(); 138 } 139 } 140 argc -= optind; 141 argv += optind; 142 143 if (!argc) { 144 usage(); 145 } 146 147 /* 148 * If no nic host is specified, use whois-servers.net 149 * if there is a '.' in the name, else fall back to NICHOST. 150 */ 151 if (host == NULL) { 152 use_qnichost = 1; 153 host = NICHOST; 154 if (!(flags & WHOIS_QUICK)) { 155 flags |= WHOIS_INIC_FALLBACK | WHOIS_RECURSE; 156 } 157 } 158 while (argc--) { 159 if (use_qnichost) { 160 if (qnichost) { 161 free(qnichost); 162 qnichost = NULL; 163 } 164 for (i = j = 0; (*argv)[i]; i++) { 165 if ((*argv)[i] == '.') { 166 j = i; 167 } 168 } 169 if (j != 0) { 170 if (isdigit(*(*argv + j + 1))) { 171 (void) asprintf(&qnichost, "%s", 172 ANICHOST); 173 } else { 174 qnichost = (char *) calloc(i - j 175 + 1 + strlen(QNICHOST_TAIL), 176 sizeof(char)); 177 if (!qnichost) { 178 err(1, "calloc"); 179 } 180 strcpy(qnichost, *argv + j + 1); 181 strcat(qnichost, QNICHOST_TAIL); 182 } 183 184 memset(&hints, 0, sizeof(hints)); 185 hints.ai_flags = 0; 186 hints.ai_family = AF_UNSPEC; 187 hints.ai_socktype = SOCK_STREAM; 188 error = getaddrinfo(qnichost, "whois", 189 &hints, &res); 190 if (error != 0) 191 errx(EX_NOHOST, "%s: %s", qnichost, 192 gai_strerror(error)); 193 } 194 } 195 if (!qnichost) { 196 memset(&hints, 0, sizeof(hints)); 197 hints.ai_flags = 0; 198 hints.ai_family = AF_UNSPEC; 199 hints.ai_socktype = SOCK_STREAM; 200 error = getaddrinfo(host, "whois", &hints, &res); 201 if (error != 0) 202 errx(EX_NOHOST, "%s: %s", host, 203 gai_strerror(error)); 204 } 205 206 whois(*argv++, res, flags); 207 freeaddrinfo(res); 208 } 209 exit(0); 210 } 211 212 static void 213 whois(name, res, flags) 214 char *name; 215 struct addrinfo *res; 216 int flags; 217 { 218 FILE *sfi, *sfo; 219 char *buf, *p, *nhost; 220 size_t len; 221 int s, nomatch; 222 223 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 224 if (s < 0) { 225 err(EX_OSERR, "socket"); 226 } 227 228 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 229 err(EX_OSERR, "connect"); 230 } 231 232 sfi = fdopen(s, "r"); 233 sfo = fdopen(s, "w"); 234 if (sfi == NULL || sfo == NULL) { 235 err(EX_OSERR, "fdopen"); 236 } 237 (void)fprintf(sfo, "%s\r\n", name); 238 (void)fflush(sfo); 239 nhost = NULL; 240 nomatch = 0; 241 while ((buf = fgetln(sfi, &len))) { 242 if (buf[len - 2] == '\r') { 243 buf[len - 2] = '\0'; 244 } else { 245 buf[len - 1] = '\0'; 246 } 247 248 if ((flags & WHOIS_RECURSE) && !nhost && 249 (p = strstr(buf, "Whois Server: "))) { 250 p += sizeof("Whois Server: ") - 1; 251 if ((len = strcspn(p, " \t\n\r"))) { 252 if ((nhost = malloc(len + 1)) == NULL) { 253 err(1, "malloc"); 254 } 255 memcpy(nhost, p, len); 256 nhost[len] = '\0'; 257 } 258 } 259 if ((flags & WHOIS_INIC_FALLBACK) && !nhost && !nomatch && 260 (p = strstr(buf, "No match for \""))) { 261 p += sizeof("No match for \"") - 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 } 269 (void)puts(buf); 270 } 271 272 /* Do second lookup as needed */ 273 if (nomatch && !nhost) { 274 (void)printf("Looking up %s at %s.\n\n", name, INICHOST); 275 nhost = INICHOST; 276 } 277 if (nhost) { 278 struct addrinfo hints, *res2; 279 int error; 280 281 memset(&hints, 0, sizeof(hints)); 282 hints.ai_flags = 0; 283 hints.ai_family = AF_UNSPEC; 284 hints.ai_socktype = SOCK_STREAM; 285 error = getaddrinfo(nhost, "whois", &hints, &res2); 286 if (error != 0) { 287 warnx("%s: %s", nhost, gai_strerror(error)); 288 return; 289 } 290 if (!nomatch) { 291 free(nhost); 292 } 293 whois(name, res2, 0); 294 freeaddrinfo(res2); 295 } 296 } 297 298 static void 299 usage() 300 { 301 (void)fprintf(stderr, 302 "usage: whois [-adgimpQrR6] [-h hostname] name ...\n"); 303 exit(EX_USAGE); 304 } 305