1 /* 2 * Copyright (c) 1985, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #if defined(LIBC_SCCS) && !defined(lint) 14 static char sccsid[] = "@(#)gethostnamadr.c 6.30 (Berkeley) 03/14/88"; 15 #endif /* LIBC_SCCS and not lint */ 16 17 #include <sys/param.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <ctype.h> 21 #include <netdb.h> 22 #include <stdio.h> 23 #include <errno.h> 24 #include <arpa/inet.h> 25 #include <arpa/nameser.h> 26 #include <resolv.h> 27 28 #define MAXALIASES 35 29 #define MAXADDRS 35 30 31 static char *h_addr_ptrs[MAXADDRS + 1]; 32 33 static struct hostent host; 34 static char *host_aliases[MAXALIASES]; 35 static char hostbuf[BUFSIZ+1]; 36 static struct in_addr host_addr; 37 static char HOSTDB[] = "/etc/hosts"; 38 static FILE *hostf = NULL; 39 static char line[BUFSIZ+1]; 40 static char hostaddr[MAXADDRS]; 41 static char *host_addrs[2]; 42 static int stayopen = 0; 43 static char *any(); 44 45 #if PACKETSZ > 1024 46 #define MAXPACKET PACKETSZ 47 #else 48 #define MAXPACKET 1024 49 #endif 50 51 typedef union { 52 HEADER qb1; 53 char qb2[MAXPACKET]; 54 } querybuf; 55 56 static union { 57 long al; 58 char ac; 59 } align; 60 61 62 int h_errno; 63 extern errno; 64 65 static struct hostent * 66 getanswer(msg, msglen, iquery) 67 char *msg; 68 int msglen, iquery; 69 { 70 register HEADER *hp; 71 register char *cp; 72 register int n; 73 querybuf answer; 74 char *eom, *bp, **ap; 75 int type, class, buflen, ancount, qdcount; 76 int haveanswer, getclass = C_ANY; 77 char **hap; 78 79 n = res_send(msg, msglen, (char *)&answer, sizeof(answer)); 80 if (n < 0) { 81 #ifdef DEBUG 82 int terrno; 83 terrno = errno; 84 if (_res.options & RES_DEBUG) 85 printf("res_send failed\n"); 86 errno = terrno; 87 #endif 88 h_errno = TRY_AGAIN; 89 return ((struct hostent *) NULL); 90 } 91 eom = (char *)&answer + n; 92 /* 93 * find first satisfactory answer 94 */ 95 hp = (HEADER *) &answer; 96 ancount = ntohs(hp->ancount); 97 qdcount = ntohs(hp->qdcount); 98 if (hp->rcode != NOERROR || ancount == 0) { 99 #ifdef DEBUG 100 if (_res.options & RES_DEBUG) 101 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 102 #endif 103 switch (hp->rcode) { 104 case NXDOMAIN: 105 /* Check if it's an authoritive answer */ 106 if (hp->aa) 107 h_errno = HOST_NOT_FOUND; 108 else 109 h_errno = TRY_AGAIN; 110 break; 111 case SERVFAIL: 112 h_errno = TRY_AGAIN; 113 break; 114 case NOERROR: 115 if (hp->aa) 116 h_errno = NO_ADDRESS; 117 else 118 h_errno = TRY_AGAIN; 119 break; 120 case FORMERR: 121 case NOTIMP: 122 case REFUSED: 123 h_errno = NO_RECOVERY; 124 } 125 return ((struct hostent *) NULL); 126 } 127 bp = hostbuf; 128 buflen = sizeof(hostbuf); 129 cp = (char *)&answer + sizeof(HEADER); 130 if (qdcount) { 131 if (iquery) { 132 if ((n = dn_expand((char *)&answer, eom, 133 cp, bp, buflen)) < 0) { 134 h_errno = NO_RECOVERY; 135 return ((struct hostent *) NULL); 136 } 137 cp += n + QFIXEDSZ; 138 host.h_name = bp; 139 n = strlen(bp) + 1; 140 bp += n; 141 buflen -= n; 142 } else 143 cp += dn_skipname(cp, eom) + QFIXEDSZ; 144 while (--qdcount > 0) 145 cp += dn_skipname(cp, eom) + QFIXEDSZ; 146 } else if (iquery) { 147 if (hp->aa) 148 h_errno = HOST_NOT_FOUND; 149 else 150 h_errno = TRY_AGAIN; 151 return ((struct hostent *) NULL); 152 } 153 ap = host_aliases; 154 host.h_aliases = host_aliases; 155 hap = h_addr_ptrs; 156 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 157 host.h_addr_list = h_addr_ptrs; 158 #endif 159 haveanswer = 0; 160 while (--ancount >= 0 && cp < eom) { 161 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 162 break; 163 cp += n; 164 type = _getshort(cp); 165 cp += sizeof(u_short); 166 class = _getshort(cp); 167 cp += sizeof(u_short) + sizeof(u_long); 168 n = _getshort(cp); 169 cp += sizeof(u_short); 170 if (type == T_CNAME) { 171 cp += n; 172 if (ap >= &host_aliases[MAXALIASES-1]) 173 continue; 174 *ap++ = bp; 175 n = strlen(bp) + 1; 176 bp += n; 177 buflen -= n; 178 continue; 179 } 180 if (type == T_PTR) { 181 if ((n = dn_expand((char *)&answer, eom, 182 cp, bp, buflen)) < 0) { 183 cp += n; 184 continue; 185 } 186 cp += n; 187 host.h_name = bp; 188 return(&host); 189 } 190 if (type != T_A) { 191 #ifdef DEBUG 192 if (_res.options & RES_DEBUG) 193 printf("unexpected answer type %d, size %d\n", 194 type, n); 195 #endif 196 cp += n; 197 continue; 198 } 199 if (haveanswer) { 200 if (n != host.h_length) { 201 cp += n; 202 continue; 203 } 204 if (class != getclass) { 205 cp += n; 206 continue; 207 } 208 } else { 209 host.h_length = n; 210 getclass = class; 211 host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; 212 if (!iquery) { 213 host.h_name = bp; 214 bp += strlen(bp) + 1; 215 } 216 } 217 218 bp += sizeof(align) - ((u_long)bp % sizeof(align)); 219 220 if (bp + n >= &hostbuf[sizeof(hostbuf)]) { 221 #ifdef DEBUG 222 if (_res.options & RES_DEBUG) 223 printf("size (%d) too big\n", n); 224 #endif 225 break; 226 } 227 bcopy(cp, *hap++ = bp, n); 228 bp +=n; 229 cp += n; 230 haveanswer++; 231 } 232 if (haveanswer) { 233 *ap = NULL; 234 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 235 *hap = NULL; 236 #else 237 host.h_addr = h_addr_ptrs[0]; 238 #endif 239 return (&host); 240 } else { 241 h_errno = TRY_AGAIN; 242 return ((struct hostent *) NULL); 243 } 244 } 245 246 struct hostent * 247 gethostbyname(name) 248 char *name; 249 { 250 register char *cp, **domain; 251 int n; 252 struct hostent *hp, *gethostdomain(); 253 char *hostalias(); 254 extern struct hostent *_gethtbyname(); 255 256 if (!(_res.options & RES_INIT) && res_init() == -1) 257 return ((struct hostent *) NULL); 258 /* 259 * disallow names consisting only of digits/dots, unless 260 * they end in a dot. 261 */ 262 if (isdigit(name[0])) 263 for (cp = name;; ++cp) { 264 if (!*cp) { 265 if (*--cp == '.') 266 break; 267 h_errno = HOST_NOT_FOUND; 268 return ((struct hostent *) NULL); 269 } 270 if (!isdigit(*cp) && *cp != '.') 271 break; 272 } 273 errno = 0; 274 for (cp = name, n = 0; *cp; cp++) 275 if (*cp == '.') 276 n++; 277 if (n == 0 && (cp = hostalias(name))) 278 return (gethostdomain(cp, (char *)NULL)); 279 if ((n == 0 || *--cp != '.') && (_res.options & RES_DEFNAMES)) 280 for (domain = _res.dnsrch; *domain; domain++) { 281 hp = gethostdomain(name, *domain); 282 if (hp) 283 return (hp); 284 /* 285 * If no server present, use host table. 286 * If host isn't found in this domain, 287 * keep trying higher domains in the search list 288 * (if that's enabled). 289 * On a NO_ADDRESS error, keep trying, otherwise 290 * a wildcard MX entry could keep us from finding 291 * host entries higher in the domain. 292 * If we get some other error (non-authoritative negative 293 * answer or server failure), then stop searching up, 294 * but try the input name below in case it's fully-qualified. 295 */ 296 if (errno == ECONNREFUSED) 297 return (_gethtbyname(name)); 298 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_ADDRESS) || 299 (_res.options & RES_DNSRCH) == 0) 300 break; 301 h_errno = 0; 302 } 303 /* 304 * If the search/default failed, try the name as fully-qualified, 305 * but only if it contained at least one dot (even trailing). 306 */ 307 if (n) 308 return (gethostdomain(name, (char *)NULL)); 309 return ((struct hostent *) NULL); 310 } 311 312 static struct hostent * 313 gethostdomain(name, domain) 314 char *name, *domain; 315 { 316 querybuf buf; 317 char nbuf[2*MAXDNAME+2]; 318 char *longname = nbuf; 319 int n; 320 321 if (domain == NULL) { 322 /* 323 * Check for trailing '.'; 324 * copy without '.' if present. 325 */ 326 n = strlen(name) - 1; 327 if (name[n] == '.' && n < sizeof(nbuf) - 1) { 328 bcopy(name, nbuf, n); 329 nbuf[n] = '\0'; 330 } else 331 longname = name; 332 } else 333 (void)sprintf(nbuf, "%.*s.%.*s", 334 MAXDNAME, name, MAXDNAME, domain); 335 n = res_mkquery(QUERY, longname, C_IN, T_A, (char *)NULL, 0, NULL, 336 (char *)&buf, sizeof(buf)); 337 if (n < 0) { 338 #ifdef DEBUG 339 if (_res.options & RES_DEBUG) 340 printf("res_mkquery failed\n"); 341 #endif 342 return ((struct hostent *) NULL); 343 } 344 return (getanswer((char *)&buf, n, 0)); 345 } 346 347 struct hostent * 348 gethostbyaddr(addr, len, type) 349 char *addr; 350 int len, type; 351 { 352 int n; 353 querybuf buf; 354 register struct hostent *hp; 355 char qbuf[MAXDNAME]; 356 extern struct hostent *_gethtbyaddr(); 357 358 if (type != AF_INET) 359 return ((struct hostent *) NULL); 360 (void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa", 361 ((unsigned)addr[3] & 0xff), 362 ((unsigned)addr[2] & 0xff), 363 ((unsigned)addr[1] & 0xff), 364 ((unsigned)addr[0] & 0xff)); 365 n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, (char *)NULL, 0, NULL, 366 (char *)&buf, sizeof(buf)); 367 if (n < 0) { 368 #ifdef DEBUG 369 if (_res.options & RES_DEBUG) 370 printf("res_mkquery failed\n"); 371 #endif 372 return ((struct hostent *) NULL); 373 } 374 hp = getanswer((char *)&buf, n, 1); 375 if (hp == NULL && errno == ECONNREFUSED) 376 hp = _gethtbyaddr(addr, len, type); 377 if (hp == NULL) 378 return ((struct hostent *) NULL); 379 hp->h_addrtype = type; 380 hp->h_length = len; 381 h_addr_ptrs[0] = (char *)&host_addr; 382 h_addr_ptrs[1] = (char *)0; 383 host_addr = *(struct in_addr *)addr; 384 return(hp); 385 } 386 387 char * 388 hostalias(name) 389 register char *name; 390 { 391 register char *C1, *C2; 392 FILE *fp; 393 char *file, *getenv(), *strcpy(), *strncpy(); 394 char buf[BUFSIZ]; 395 static char abuf[MAXDNAME]; 396 397 file = getenv("HOSTALIASES"); 398 if (file == NULL || (fp = fopen(file, "r")) == NULL) 399 return (NULL); 400 buf[sizeof(buf) - 1] = '\0'; 401 while (fgets(buf, sizeof(buf), fp)) { 402 for (C1 = buf; *C1 && !isspace(*C1); ++C1); 403 if (!*C1) 404 break; 405 *C1 = '\0'; 406 if (!strcasecmp(buf, name)) { 407 while (isspace(*++C1)); 408 if (!*C1) 409 break; 410 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); 411 abuf[sizeof(abuf) - 1] = *C2 = '\0'; 412 (void)strncpy(abuf, C1, sizeof(abuf) - 1); 413 fclose(fp); 414 return (abuf); 415 } 416 } 417 fclose(fp); 418 return (NULL); 419 } 420 421 _sethtent(f) 422 int f; 423 { 424 if (hostf == NULL) 425 hostf = fopen(HOSTDB, "r" ); 426 else 427 rewind(hostf); 428 stayopen |= f; 429 } 430 431 _endhtent() 432 { 433 if (hostf && !stayopen) { 434 (void) fclose(hostf); 435 hostf = NULL; 436 } 437 } 438 439 struct hostent * 440 _gethtent() 441 { 442 char *p; 443 register char *cp, **q; 444 445 if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL) 446 return (NULL); 447 again: 448 if ((p = fgets(line, BUFSIZ, hostf)) == NULL) 449 return (NULL); 450 if (*p == '#') 451 goto again; 452 cp = any(p, "#\n"); 453 if (cp == NULL) 454 goto again; 455 *cp = '\0'; 456 cp = any(p, " \t"); 457 if (cp == NULL) 458 goto again; 459 *cp++ = '\0'; 460 /* THIS STUFF IS INTERNET SPECIFIC */ 461 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 462 host.h_addr_list = host_addrs; 463 #endif 464 host.h_addr = hostaddr; 465 *((u_long *)host.h_addr) = inet_addr(p); 466 host.h_length = sizeof (u_long); 467 host.h_addrtype = AF_INET; 468 while (*cp == ' ' || *cp == '\t') 469 cp++; 470 host.h_name = cp; 471 q = host.h_aliases = host_aliases; 472 cp = any(cp, " \t"); 473 if (cp != NULL) 474 *cp++ = '\0'; 475 while (cp && *cp) { 476 if (*cp == ' ' || *cp == '\t') { 477 cp++; 478 continue; 479 } 480 if (q < &host_aliases[MAXALIASES - 1]) 481 *q++ = cp; 482 cp = any(cp, " \t"); 483 if (cp != NULL) 484 *cp++ = '\0'; 485 } 486 *q = NULL; 487 return (&host); 488 } 489 490 static char * 491 any(cp, match) 492 register char *cp; 493 char *match; 494 { 495 register char *mp, c; 496 497 while (c = *cp) { 498 for (mp = match; *mp; mp++) 499 if (*mp == c) 500 return (cp); 501 cp++; 502 } 503 return ((char *)0); 504 } 505 506 struct hostent * 507 _gethtbyname(name) 508 char *name; 509 { 510 register struct hostent *p; 511 register char **cp; 512 513 _sethtent(0); 514 while (p = _gethtent()) { 515 if (strcasecmp(p->h_name, name) == 0) 516 break; 517 for (cp = p->h_aliases; *cp != 0; cp++) 518 if (strcasecmp(*cp, name) == 0) 519 goto found; 520 } 521 found: 522 _endhtent(); 523 return (p); 524 } 525 526 struct hostent * 527 _gethtbyaddr(addr, len, type) 528 char *addr; 529 int len, type; 530 { 531 register struct hostent *p; 532 533 _sethtent(0); 534 while (p = _gethtent()) 535 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len)) 536 break; 537 _endhtent(); 538 return (p); 539 } 540