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