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 #if 0 41 #ifndef lint 42 static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93"; 43 #endif /* not lint */ 44 #endif 45 46 #include <sys/cdefs.h> 47 __FBSDID("$FreeBSD$"); 48 49 #include <sys/types.h> 50 #include <sys/socket.h> 51 #include <netinet/in.h> 52 #include <arpa/inet.h> 53 #include <ctype.h> 54 #include <err.h> 55 #include <netdb.h> 56 #include <stdarg.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <sysexits.h> 61 #include <unistd.h> 62 63 #define ABUSEHOST "whois.abuse.net" 64 #define NICHOST "whois.crsnic.net" 65 #define INICHOST "whois.networksolutions.com" 66 #define GNICHOST "whois.nic.gov" 67 #define ANICHOST "whois.arin.net" 68 #define LNICHOST "whois.lacnic.net" 69 #define KNICHOST "whois.krnic.net" 70 #define RNICHOST "whois.ripe.net" 71 #define PNICHOST "whois.apnic.net" 72 #define MNICHOST "whois.ra.net" 73 #define QNICHOST_TAIL ".whois-servers.net" 74 #define BNICHOST "whois.registro.br" 75 #define NORIDHOST "whois.norid.no" 76 #define IANAHOST "whois.iana.org" 77 #define GERMNICHOST "de.whois-servers.net" 78 #define FNICHOST "whois.afrinic.net" 79 #define DEFAULT_PORT "whois" 80 #define WHOIS_SERVER_ID "Whois Server: " 81 #define WHOIS_ORG_SERVER_ID "Registrant Street1:Whois Server:" 82 83 #define WHOIS_RECURSE 0x01 84 #define WHOIS_QUICK 0x02 85 86 #define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-') 87 88 const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST, 89 FNICHOST, NULL }; 90 const char *port = DEFAULT_PORT; 91 92 static char *choose_server(char *); 93 static struct addrinfo *gethostinfo(char const *host, int exit_on_error); 94 static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3); 95 static void usage(void); 96 static void whois(const char *, const char *, int); 97 98 int 99 main(int argc, char *argv[]) 100 { 101 const char *country, *host; 102 char *qnichost; 103 int ch, flags, use_qnichost; 104 105 #ifdef SOCKS 106 SOCKSinit(argv[0]); 107 #endif 108 109 country = host = qnichost = NULL; 110 flags = use_qnichost = 0; 111 while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:QrR6")) != -1) { 112 switch (ch) { 113 case 'a': 114 host = ANICHOST; 115 break; 116 case 'A': 117 host = PNICHOST; 118 break; 119 case 'b': 120 host = ABUSEHOST; 121 break; 122 case 'c': 123 country = optarg; 124 break; 125 case 'f': 126 host = FNICHOST; 127 break; 128 case 'g': 129 host = GNICHOST; 130 break; 131 case 'h': 132 host = optarg; 133 break; 134 case 'i': 135 host = INICHOST; 136 break; 137 case 'I': 138 host = IANAHOST; 139 break; 140 case 'k': 141 host = KNICHOST; 142 break; 143 case 'l': 144 host = LNICHOST; 145 break; 146 case 'm': 147 host = MNICHOST; 148 break; 149 case 'p': 150 port = optarg; 151 break; 152 case 'Q': 153 flags |= WHOIS_QUICK; 154 break; 155 case 'r': 156 host = RNICHOST; 157 break; 158 case 'R': 159 warnx("-R is deprecated; use '-c ru' instead"); 160 country = "ru"; 161 break; 162 /* Remove in FreeBSD 10 */ 163 case '6': 164 errx(EX_USAGE, 165 "-6 is deprecated; use -[aAflr] instead"); 166 break; 167 case '?': 168 default: 169 usage(); 170 /* NOTREACHED */ 171 } 172 } 173 argc -= optind; 174 argv += optind; 175 176 if (!argc || (country != NULL && host != NULL)) 177 usage(); 178 179 /* 180 * If no host or country is specified determine the top level domain 181 * from the query. If the TLD is a number, query ARIN. Otherwise, use 182 * TLD.whois-server.net. If the domain does not contain '.', fall 183 * back to NICHOST. 184 */ 185 if (host == NULL && country == NULL) { 186 use_qnichost = 1; 187 host = NICHOST; 188 if (!(flags & WHOIS_QUICK)) 189 flags |= WHOIS_RECURSE; 190 } 191 while (argc-- > 0) { 192 if (country != NULL) { 193 s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL); 194 whois(*argv, qnichost, flags); 195 } else if (use_qnichost) 196 if ((qnichost = choose_server(*argv)) != NULL) 197 whois(*argv, qnichost, flags); 198 if (qnichost == NULL) 199 whois(*argv, host, flags); 200 free(qnichost); 201 qnichost = NULL; 202 argv++; 203 } 204 exit(0); 205 } 206 207 /* 208 * This function will remove any trailing periods from domain, after which it 209 * returns a pointer to newly allocated memory containing the whois server to 210 * be queried, or a NULL if the correct server couldn't be determined. The 211 * caller must remember to free(3) the allocated memory. 212 */ 213 static char * 214 choose_server(char *domain) 215 { 216 char *pos, *retval; 217 218 if (strchr(domain, ':')) { 219 s_asprintf(&retval, "%s", ANICHOST); 220 return (retval); 221 } 222 for (pos = strchr(domain, '\0'); pos > domain && *--pos == '.';) 223 *pos = '\0'; 224 if (*domain == '\0') 225 errx(EX_USAGE, "can't search for a null string"); 226 if (strlen(domain) > sizeof("-NORID")-1 && 227 strcasecmp(domain + strlen(domain) - sizeof("-NORID") + 1, 228 "-NORID") == 0) { 229 s_asprintf(&retval, "%s", NORIDHOST); 230 return (retval); 231 } 232 while (pos > domain && *pos != '.') 233 --pos; 234 if (pos <= domain) 235 return (NULL); 236 if (isdigit((unsigned char)*++pos)) 237 s_asprintf(&retval, "%s", ANICHOST); 238 else 239 s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL); 240 return (retval); 241 } 242 243 static struct addrinfo * 244 gethostinfo(char const *host, int exit_on_error) 245 { 246 struct addrinfo hints, *res; 247 int error; 248 249 memset(&hints, 0, sizeof(hints)); 250 hints.ai_flags = 0; 251 hints.ai_family = AF_UNSPEC; 252 hints.ai_socktype = SOCK_STREAM; 253 error = getaddrinfo(host, port, &hints, &res); 254 if (error) { 255 warnx("%s: %s", host, gai_strerror(error)); 256 if (exit_on_error) 257 exit(EX_NOHOST); 258 return (NULL); 259 } 260 return (res); 261 } 262 263 /* 264 * Wrapper for asprintf(3) that exits on error. 265 */ 266 static void 267 s_asprintf(char **ret, const char *format, ...) 268 { 269 va_list ap; 270 271 va_start(ap, format); 272 if (vasprintf(ret, format, ap) == -1) { 273 va_end(ap); 274 err(EX_OSERR, "vasprintf()"); 275 } 276 va_end(ap); 277 } 278 279 static void 280 whois(const char *query, const char *hostname, int flags) 281 { 282 FILE *sfi, *sfo; 283 struct addrinfo *hostres, *res; 284 char *buf, *host, *nhost, *p; 285 int i, s; 286 size_t c, len; 287 288 s = -1; 289 hostres = gethostinfo(hostname, 1); 290 for (res = hostres; res; res = res->ai_next) { 291 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 292 if (s < 0) 293 continue; 294 if (connect(s, res->ai_addr, res->ai_addrlen) == 0) 295 break; 296 close(s); 297 } 298 freeaddrinfo(hostres); 299 if (res == NULL) 300 err(EX_OSERR, "connect()"); 301 302 sfi = fdopen(s, "r"); 303 sfo = fdopen(s, "w"); 304 if (sfi == NULL || sfo == NULL) 305 err(EX_OSERR, "fdopen()"); 306 if (strcmp(hostname, GERMNICHOST) == 0) { 307 fprintf(sfo, "-T dn,ace -C US-ASCII %s\r\n", query); 308 } else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) { 309 fprintf(sfo, "--show-handles %s\r\n", query); 310 } else { 311 fprintf(sfo, "%s\r\n", query); 312 } 313 fflush(sfo); 314 nhost = NULL; 315 while ((buf = fgetln(sfi, &len)) != NULL) { 316 while (len > 0 && isspace((unsigned char)buf[len - 1])) 317 buf[--len] = '\0'; 318 printf("%.*s\n", (int)len, buf); 319 320 if ((flags & WHOIS_RECURSE) && nhost == NULL) { 321 host = strnstr(buf, WHOIS_SERVER_ID, len); 322 if (host != NULL) { 323 host += sizeof(WHOIS_SERVER_ID) - 1; 324 for (p = host; p < buf + len; p++) { 325 if (!ishost(*p)) { 326 *p = '\0'; 327 break; 328 } 329 } 330 s_asprintf(&nhost, "%.*s", 331 (int)(buf + len - host), host); 332 } else if ((host = 333 strnstr(buf, WHOIS_ORG_SERVER_ID, len)) != NULL) { 334 host += sizeof(WHOIS_ORG_SERVER_ID) - 1; 335 for (p = host; p < buf + len; p++) { 336 if (!ishost(*p)) { 337 *p = '\0'; 338 break; 339 } 340 } 341 s_asprintf(&nhost, "%.*s", 342 (int)(buf + len - host), host); 343 } else if (strcmp(hostname, ANICHOST) == 0) { 344 for (c = 0; c <= len; c++) 345 buf[c] = tolower((unsigned char)buf[c]); 346 for (i = 0; ip_whois[i] != NULL; i++) { 347 if (strnstr(buf, ip_whois[i], len) != 348 NULL) { 349 s_asprintf(&nhost, "%s", 350 ip_whois[i]); 351 break; 352 } 353 } 354 } 355 } 356 } 357 if (nhost != NULL) { 358 whois(query, nhost, 0); 359 free(nhost); 360 } 361 } 362 363 static void 364 usage(void) 365 { 366 fprintf(stderr, 367 "usage: whois [-aAbfgiIklmQrR6] [-c country-code | -h hostname] " 368 "[-p port] name ...\n"); 369 exit(EX_USAGE); 370 } 371