1 /*- 2 * Copyright (c) 1985, 1988, 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 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 34 * 35 * Permission to use, copy, modify, and distribute this software for any 36 * purpose with or without fee is hereby granted, provided that the above 37 * copyright notice and this permission notice appear in all copies, and that 38 * the name of Digital Equipment Corporation not be used in advertising or 39 * publicity pertaining to distribution of the document or software without 40 * specific, written prior permission. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 43 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 44 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 45 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 46 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 47 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 48 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 49 * SOFTWARE. 50 * - 51 * --Copyright-- 52 */ 53 54 #if defined(LIBC_SCCS) && !defined(lint) 55 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; 56 static char rcsid[] = "$Id: gethostbydns.c,v 1.10 1996/08/29 20:07:50 peter Exp $"; 57 #endif /* LIBC_SCCS and not lint */ 58 59 #include <sys/types.h> 60 #include <sys/param.h> 61 #include <sys/socket.h> 62 #include <netinet/in.h> 63 #include <arpa/inet.h> 64 #include <arpa/nameser.h> 65 66 #include <stdio.h> 67 #include <unistd.h> 68 #include <string.h> 69 #include <netdb.h> 70 #include <resolv.h> 71 #include <ctype.h> 72 #include <errno.h> 73 #include <syslog.h> 74 75 #include "res_config.h" 76 77 extern void _res_close __P((void)); 78 79 #define SPRINTF(x) ((size_t)sprintf x) 80 81 #define MAXALIASES 35 82 #define MAXADDRS 35 83 84 static const char AskedForGot[] = 85 "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; 86 87 static char *h_addr_ptrs[MAXADDRS + 1]; 88 static struct hostent *gethostbyname_ipv4 __P((const char *)); 89 90 static struct hostent host; 91 static char *host_aliases[MAXALIASES]; 92 static char hostbuf[8*1024]; 93 static u_char host_addr[16]; /* IPv4 or IPv6 */ 94 95 #ifdef RESOLVSORT 96 static void addrsort __P((char **, int)); 97 #endif 98 99 #if PACKETSZ > 1024 100 #define MAXPACKET PACKETSZ 101 #else 102 #define MAXPACKET 1024 103 #endif 104 105 typedef union { 106 HEADER hdr; 107 u_char buf[MAXPACKET]; 108 } querybuf; 109 110 typedef union { 111 int32_t al; 112 char ac; 113 } align; 114 115 extern int h_errno; 116 117 #ifdef DEBUG 118 static void 119 dprintf(msg, num) 120 char *msg; 121 int num; 122 { 123 if (_res.options & RES_DEBUG) { 124 int save = errno; 125 126 printf(msg, num); 127 errno = save; 128 } 129 } 130 #else 131 # define dprintf(msg, num) /*nada*/ 132 #endif 133 134 static struct hostent * 135 gethostanswer(answer, anslen, qname, qtype) 136 const querybuf *answer; 137 int anslen; 138 const char *qname; 139 int qtype; 140 { 141 register const HEADER *hp; 142 register const u_char *cp; 143 register int n; 144 const u_char *eom; 145 char *bp, **ap, **hap; 146 int type, class, buflen, ancount, qdcount; 147 int haveanswer, had_error; 148 int toobig = 0; 149 char tbuf[MAXDNAME+1]; 150 const char *tname; 151 int (*name_ok) __P((const char *)); 152 153 tname = qname; 154 host.h_name = NULL; 155 eom = answer->buf + anslen; 156 switch (qtype) { 157 case T_A: 158 case T_AAAA: 159 name_ok = res_hnok; 160 break; 161 case T_PTR: 162 name_ok = res_dnok; 163 break; 164 default: 165 h_errno = NO_RECOVERY; 166 return (NULL); /* XXX should be abort(); */ 167 } 168 /* 169 * find first satisfactory answer 170 */ 171 hp = &answer->hdr; 172 ancount = ntohs(hp->ancount); 173 qdcount = ntohs(hp->qdcount); 174 bp = hostbuf; 175 buflen = sizeof hostbuf; 176 cp = answer->buf + HFIXEDSZ; 177 if (qdcount != 1) { 178 h_errno = NO_RECOVERY; 179 return (NULL); 180 } 181 n = dn_expand(answer->buf, eom, cp, bp, buflen); 182 if ((n < 0) || !(*name_ok)(bp)) { 183 h_errno = NO_RECOVERY; 184 return (NULL); 185 } 186 cp += n + QFIXEDSZ; 187 if (qtype == T_A || qtype == T_AAAA) { 188 /* res_send() has already verified that the query name is the 189 * same as the one we sent; this just gets the expanded name 190 * (i.e., with the succeeding search-domain tacked on). 191 */ 192 n = strlen(bp) + 1; /* for the \0 */ 193 host.h_name = bp; 194 bp += n; 195 buflen -= n; 196 /* The qname can be abbreviated, but h_name is now absolute. */ 197 qname = host.h_name; 198 } 199 ap = host_aliases; 200 *ap = NULL; 201 host.h_aliases = host_aliases; 202 hap = h_addr_ptrs; 203 *hap = NULL; 204 host.h_addr_list = h_addr_ptrs; 205 haveanswer = 0; 206 had_error = 0; 207 while (ancount-- > 0 && cp < eom && !had_error) { 208 n = dn_expand(answer->buf, eom, cp, bp, buflen); 209 if ((n < 0) || !(*name_ok)(bp)) { 210 had_error++; 211 continue; 212 } 213 cp += n; /* name */ 214 type = _getshort(cp); 215 cp += INT16SZ; /* type */ 216 class = _getshort(cp); 217 cp += INT16SZ + INT32SZ; /* class, TTL */ 218 n = _getshort(cp); 219 cp += INT16SZ; /* len */ 220 if (class != C_IN) { 221 /* XXX - debug? syslog? */ 222 cp += n; 223 continue; /* XXX - had_error++ ? */ 224 } 225 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 226 if (ap >= &host_aliases[MAXALIASES-1]) 227 continue; 228 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 229 if ((n < 0) || !(*name_ok)(tbuf)) { 230 had_error++; 231 continue; 232 } 233 cp += n; 234 /* Store alias. */ 235 *ap++ = bp; 236 n = strlen(bp) + 1; /* for the \0 */ 237 bp += n; 238 buflen -= n; 239 /* Get canonical name. */ 240 n = strlen(tbuf) + 1; /* for the \0 */ 241 if (n > buflen) { 242 had_error++; 243 continue; 244 } 245 strcpy(bp, tbuf); 246 host.h_name = bp; 247 bp += n; 248 buflen -= n; 249 continue; 250 } 251 if (qtype == T_PTR && type == T_CNAME) { 252 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 253 if ((n < 0) || !res_hnok(tbuf)) { 254 had_error++; 255 continue; 256 } 257 cp += n; 258 /* Get canonical name. */ 259 n = strlen(tbuf) + 1; /* for the \0 */ 260 if (n > buflen) { 261 had_error++; 262 continue; 263 } 264 strcpy(bp, tbuf); 265 tname = bp; 266 bp += n; 267 buflen -= n; 268 continue; 269 } 270 if (type != qtype) { 271 syslog(LOG_NOTICE|LOG_AUTH, 272 "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", 273 qname, p_class(C_IN), p_type(qtype), 274 p_type(type)); 275 cp += n; 276 continue; /* XXX - had_error++ ? */ 277 } 278 switch (type) { 279 case T_PTR: 280 if (strcasecmp(tname, bp) != 0) { 281 syslog(LOG_NOTICE|LOG_AUTH, 282 AskedForGot, qname, bp); 283 cp += n; 284 continue; /* XXX - had_error++ ? */ 285 } 286 n = dn_expand(answer->buf, eom, cp, bp, buflen); 287 if ((n < 0) || !res_hnok(bp)) { 288 had_error++; 289 break; 290 } 291 #if MULTI_PTRS_ARE_ALIASES 292 cp += n; 293 if (!haveanswer) 294 host.h_name = bp; 295 else if (ap < &host_aliases[MAXALIASES-1]) 296 *ap++ = bp; 297 else 298 n = -1; 299 if (n != -1) { 300 n = strlen(bp) + 1; /* for the \0 */ 301 bp += n; 302 buflen -= n; 303 } 304 break; 305 #else 306 host.h_name = bp; 307 if (_res.options & RES_USE_INET6) { 308 n = strlen(bp) + 1; /* for the \0 */ 309 bp += n; 310 buflen -= n; 311 _map_v4v6_hostent(&host, &bp, &buflen); 312 } 313 h_errno = NETDB_SUCCESS; 314 return (&host); 315 #endif 316 case T_A: 317 case T_AAAA: 318 if (strcasecmp(host.h_name, bp) != 0) { 319 syslog(LOG_NOTICE|LOG_AUTH, 320 AskedForGot, host.h_name, bp); 321 cp += n; 322 continue; /* XXX - had_error++ ? */ 323 } 324 if (n != host.h_length) { 325 cp += n; 326 continue; 327 } 328 if (!haveanswer) { 329 register int nn; 330 331 host.h_name = bp; 332 nn = strlen(bp) + 1; /* for the \0 */ 333 bp += nn; 334 buflen -= nn; 335 } 336 337 bp += sizeof(align) - ((u_long)bp % sizeof(align)); 338 339 if (bp + n >= &hostbuf[sizeof hostbuf]) { 340 dprintf("size (%d) too big\n", n); 341 had_error++; 342 continue; 343 } 344 if (hap >= &h_addr_ptrs[MAXADDRS-1]) { 345 if (!toobig++) 346 dprintf("Too many addresses (%d)\n", 347 MAXADDRS); 348 cp += n; 349 continue; 350 } 351 bcopy(cp, *hap++ = bp, n); 352 bp += n; 353 buflen -= n; 354 cp += n; 355 break; 356 default: 357 dprintf("Impossible condition (type=%d)\n", type); 358 h_errno = NO_RECOVERY; 359 return (NULL); 360 } /*switch*/ 361 if (!had_error) 362 haveanswer++; 363 } /*while*/ 364 if (haveanswer) { 365 *ap = NULL; 366 *hap = NULL; 367 # if defined(RESOLVSORT) 368 /* 369 * Note: we sort even if host can take only one address 370 * in its return structures - should give it the "best" 371 * address in that case, not some random one 372 */ 373 if (_res.nsort && haveanswer > 1 && qtype == T_A) 374 addrsort(h_addr_ptrs, haveanswer); 375 # endif /*RESOLVSORT*/ 376 if (!host.h_name) { 377 n = strlen(qname) + 1; /* for the \0 */ 378 if (n > buflen) 379 goto try_again; 380 strcpy(bp, qname); 381 host.h_name = bp; 382 bp += n; 383 buflen -= n; 384 } 385 if (_res.options & RES_USE_INET6) 386 _map_v4v6_hostent(&host, &bp, &buflen); 387 h_errno = NETDB_SUCCESS; 388 return (&host); 389 } 390 try_again: 391 h_errno = TRY_AGAIN; 392 return (NULL); 393 } 394 395 struct hostent * 396 _gethostbydnsname(name, af) 397 const char *name; 398 int af; 399 { 400 querybuf buf; 401 register const char *cp; 402 char *bp; 403 int n, size, type, len; 404 405 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 406 h_errno = NETDB_INTERNAL; 407 return (NULL); 408 } 409 410 switch (af) { 411 case AF_INET: 412 size = INADDRSZ; 413 type = T_A; 414 break; 415 case AF_INET6: 416 size = IN6ADDRSZ; 417 type = T_AAAA; 418 break; 419 default: 420 h_errno = NETDB_INTERNAL; 421 errno = EAFNOSUPPORT; 422 return (NULL); 423 } 424 425 host.h_addrtype = af; 426 host.h_length = size; 427 428 /* 429 * if there aren't any dots, it could be a user-level alias. 430 * this is also done in res_query() since we are not the only 431 * function that looks up host names. 432 */ 433 if (!strchr(name, '.') && (cp = __hostalias(name))) 434 name = cp; 435 436 /* 437 * disallow names consisting only of digits/dots, unless 438 * they end in a dot. 439 */ 440 if (isdigit(name[0])) 441 for (cp = name;; ++cp) { 442 if (!*cp) { 443 if (*--cp == '.') 444 break; 445 /* 446 * All-numeric, no dot at the end. 447 * Fake up a hostent as if we'd actually 448 * done a lookup. 449 */ 450 if (inet_pton(af, name, host_addr) <= 0) { 451 h_errno = HOST_NOT_FOUND; 452 return (NULL); 453 } 454 strncpy(hostbuf, name, MAXDNAME); 455 hostbuf[MAXDNAME] = '\0'; 456 bp = hostbuf + MAXDNAME; 457 len = sizeof hostbuf - MAXDNAME; 458 host.h_name = hostbuf; 459 host.h_aliases = host_aliases; 460 host_aliases[0] = NULL; 461 h_addr_ptrs[0] = (char *)host_addr; 462 h_addr_ptrs[1] = NULL; 463 host.h_addr_list = h_addr_ptrs; 464 if (_res.options & RES_USE_INET6) 465 _map_v4v6_hostent(&host, &bp, &len); 466 h_errno = NETDB_SUCCESS; 467 return (&host); 468 } 469 if (!isdigit(*cp) && *cp != '.') 470 break; 471 } 472 473 if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) { 474 dprintf("res_search failed (%d)\n", n); 475 return (NULL); 476 } 477 return (gethostanswer(&buf, n, name, type)); 478 } 479 480 struct hostent * 481 _gethostbydnsaddr(addr, len, af) 482 const char *addr; /* XXX should have been def'd as u_char! */ 483 int len, af; 484 { 485 const u_char *uaddr = (const u_char *)addr; 486 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; 487 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; 488 int n, size; 489 querybuf buf; 490 register struct hostent *hp; 491 char qbuf[MAXDNAME+1], *qp; 492 #ifdef SUNSECURITY 493 register struct hostent *rhp; 494 char **haddr; 495 u_long old_options; 496 char hname2[MAXDNAME+1]; 497 #endif /*SUNSECURITY*/ 498 499 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 500 h_errno = NETDB_INTERNAL; 501 return (NULL); 502 } 503 if (af == AF_INET6 && len == IN6ADDRSZ && 504 (!bcmp(uaddr, mapped, sizeof mapped) || 505 !bcmp(uaddr, tunnelled, sizeof tunnelled))) { 506 /* Unmap. */ 507 addr += sizeof mapped; 508 uaddr += sizeof mapped; 509 af = AF_INET; 510 len = INADDRSZ; 511 } 512 switch (af) { 513 case AF_INET: 514 size = INADDRSZ; 515 break; 516 case AF_INET6: 517 size = IN6ADDRSZ; 518 break; 519 default: 520 errno = EAFNOSUPPORT; 521 h_errno = NETDB_INTERNAL; 522 return (NULL); 523 } 524 if (size != len) { 525 errno = EINVAL; 526 h_errno = NETDB_INTERNAL; 527 return (NULL); 528 } 529 switch (af) { 530 case AF_INET: 531 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", 532 (uaddr[3] & 0xff), 533 (uaddr[2] & 0xff), 534 (uaddr[1] & 0xff), 535 (uaddr[0] & 0xff)); 536 break; 537 case AF_INET6: 538 qp = qbuf; 539 for (n = IN6ADDRSZ - 1; n >= 0; n--) { 540 qp += SPRINTF((qp, "%x.%x.", 541 uaddr[n] & 0xf, 542 (uaddr[n] >> 4) & 0xf)); 543 } 544 strcpy(qp, "ip6.int"); 545 break; 546 default: 547 abort(); 548 } 549 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf); 550 if (n < 0) { 551 dprintf("res_query failed (%d)\n", n); 552 return (NULL); 553 } 554 if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR))) 555 return (NULL); /* h_errno was set by gethostanswer() */ 556 #ifdef SUNSECURITY 557 if (af == AF_INET) { 558 /* 559 * turn off search as the name should be absolute, 560 * 'localhost' should be matched by defnames 561 */ 562 strncpy(hname2, hp->h_name, MAXDNAME); 563 hname2[MAXDNAME] = '\0'; 564 old_options = _res.options; 565 _res.options &= ~RES_DNSRCH; 566 _res.options |= RES_DEFNAMES; 567 if (!(rhp = gethostbyname(hname2))) { 568 syslog(LOG_NOTICE|LOG_AUTH, 569 "gethostbyaddr: No A record for %s (verifying [%s])", 570 hname2, inet_ntoa(*((struct in_addr *)addr))); 571 _res.options = old_options; 572 h_errno = HOST_NOT_FOUND; 573 return (NULL); 574 } 575 _res.options = old_options; 576 for (haddr = rhp->h_addr_list; *haddr; haddr++) 577 if (!memcmp(*haddr, addr, INADDRSZ)) 578 break; 579 if (!*haddr) { 580 syslog(LOG_NOTICE|LOG_AUTH, 581 "gethostbyaddr: A record of %s != PTR record [%s]", 582 hname2, inet_ntoa(*((struct in_addr *)addr))); 583 h_errno = HOST_NOT_FOUND; 584 return (NULL); 585 } 586 } 587 #endif /*SUNSECURITY*/ 588 hp->h_addrtype = af; 589 hp->h_length = len; 590 bcopy(addr, host_addr, len); 591 h_addr_ptrs[0] = (char *)host_addr; 592 h_addr_ptrs[1] = NULL; 593 if (af == AF_INET && (_res.options & RES_USE_INET6)) { 594 _map_v4v6_address((char*)host_addr, (char*)host_addr); 595 hp->h_addrtype = AF_INET6; 596 hp->h_length = IN6ADDRSZ; 597 } 598 h_errno = NETDB_SUCCESS; 599 return (hp); 600 } 601 602 #ifdef RESOLVSORT 603 static void 604 addrsort(ap, num) 605 char **ap; 606 int num; 607 { 608 int i, j; 609 char **p; 610 short aval[MAXADDRS]; 611 int needsort = 0; 612 613 p = ap; 614 for (i = 0; i < num; i++, p++) { 615 for (j = 0 ; (unsigned)j < _res.nsort; j++) 616 if (_res.sort_list[j].addr.s_addr == 617 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) 618 break; 619 aval[i] = j; 620 if (needsort == 0 && i > 0 && j < aval[i-1]) 621 needsort = i; 622 } 623 if (!needsort) 624 return; 625 626 while (needsort < num) { 627 for (j = needsort - 1; j >= 0; j--) { 628 if (aval[j] > aval[j+1]) { 629 char *hp; 630 631 i = aval[j]; 632 aval[j] = aval[j+1]; 633 aval[j+1] = i; 634 635 hp = ap[j]; 636 ap[j] = ap[j+1]; 637 ap[j+1] = hp; 638 639 } else 640 break; 641 } 642 needsort++; 643 } 644 } 645 #endif 646 void 647 _sethostdnsent(stayopen) 648 int stayopen; 649 { 650 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 651 return; 652 if (stayopen) 653 _res.options |= RES_STAYOPEN | RES_USEVC; 654 } 655 656 void 657 _endhostdnsent() 658 { 659 _res.options &= ~(RES_STAYOPEN | RES_USEVC); 660 _res_close(); 661 } 662