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