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.6 1995/08/21 09:15:32 bde Exp $"; 57 #endif /* LIBC_SCCS and not lint */ 58 59 #include <sys/param.h> 60 #include <sys/socket.h> 61 #include <netinet/in.h> 62 #include <arpa/inet.h> 63 #include <arpa/nameser.h> 64 65 #include <stdio.h> 66 #include <unistd.h> 67 #include <string.h> 68 #include <netdb.h> 69 #include <resolv.h> 70 #include <ctype.h> 71 #include <errno.h> 72 #include <syslog.h> 73 74 #include "res_config.h" 75 76 #define MAXALIASES 35 77 #define MAXADDRS 35 78 79 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ 80 81 static const char AskedForGot[] = 82 "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; 83 84 static char *h_addr_ptrs[MAXADDRS + 1]; 85 86 static struct hostent host; 87 static char *host_aliases[MAXALIASES]; 88 static char hostbuf[8*1024]; 89 static struct in_addr host_addr; 90 static FILE *hostf = NULL; 91 static int stayopen = 0; 92 93 #if PACKETSZ > 1024 94 #define MAXPACKET PACKETSZ 95 #else 96 #define MAXPACKET 1024 97 #endif 98 99 typedef union { 100 HEADER hdr; 101 u_char buf[MAXPACKET]; 102 } querybuf; 103 104 typedef union { 105 int32_t al; 106 char ac; 107 } align; 108 109 extern int h_errno; 110 111 #ifdef DEBUG 112 static void 113 dprintf(msg, num) 114 char *msg; 115 int num; 116 { 117 if (_res.options & RES_DEBUG) { 118 int save = errno; 119 120 printf(msg, num); 121 errno = save; 122 } 123 } 124 #else 125 # define dprintf(msg, num) /*nada*/ 126 #endif 127 128 129 #ifdef RESOLVSORT 130 static void 131 addrsort(ap, num) 132 char **ap; 133 int num; 134 { 135 int i, j; 136 char **p; 137 short aval[MAXADDRS]; 138 int needsort = 0; 139 140 p = ap; 141 for (i = 0; i < num; i++, p++) { 142 for (j = 0 ; (unsigned)j < _res.nsort; j++) 143 if (_res.sort_list[j].addr.s_addr == 144 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) 145 break; 146 aval[i] = j; 147 if (needsort == 0 && i > 0 && j < aval[i-1]) 148 needsort = i; 149 } 150 if (!needsort) 151 return; 152 153 while (needsort < num) { 154 for (j = needsort - 1; j >= 0; j--) { 155 if (aval[j] > aval[j+1]) { 156 char *hp; 157 158 i = aval[j]; 159 aval[j] = aval[j+1]; 160 aval[j+1] = i; 161 162 hp = ap[j]; 163 ap[j] = ap[j+1]; 164 ap[j+1] = hp; 165 166 } else 167 break; 168 } 169 needsort++; 170 } 171 } 172 #endif 173 174 static struct hostent * 175 gethostanswer(answer, anslen, qname, qclass, qtype) 176 const querybuf *answer; 177 int anslen; 178 const char *qname; 179 int qclass, qtype; 180 { 181 register const HEADER *hp; 182 register const u_char *cp; 183 register int n; 184 const u_char *eom; 185 char *bp, **ap, **hap; 186 int type, class, buflen, ancount, qdcount; 187 int haveanswer, had_error; 188 int toobig = 0; 189 char tbuf[MAXDNAME+1]; 190 191 host.h_name = NULL; 192 eom = answer->buf + anslen; 193 /* 194 * find first satisfactory answer 195 */ 196 hp = &answer->hdr; 197 ancount = ntohs(hp->ancount); 198 qdcount = ntohs(hp->qdcount); 199 bp = hostbuf; 200 buflen = sizeof hostbuf; 201 cp = answer->buf + HFIXEDSZ; 202 if (qdcount != 1) { 203 h_errno = NO_RECOVERY; 204 return (NULL); 205 } 206 if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) { 207 h_errno = NO_RECOVERY; 208 return (NULL); 209 } 210 cp += n + QFIXEDSZ; 211 if (qtype == T_A) { 212 /* res_send() has already verified that the query name is the 213 * same as the one we sent; this just gets the expanded name 214 * (i.e., with the succeeding search-domain tacked on). 215 */ 216 n = strlen(bp) + 1; /* for the \0 */ 217 host.h_name = bp; 218 bp += n; 219 buflen -= n; 220 /* The qname can be abbreviated, but h_name is now absolute. */ 221 qname = host.h_name; 222 } 223 ap = host_aliases; 224 *ap = NULL; 225 host.h_aliases = host_aliases; 226 hap = h_addr_ptrs; 227 *hap = NULL; 228 host.h_addr_list = h_addr_ptrs; 229 haveanswer = 0; 230 had_error = 0; 231 while (ancount-- > 0 && cp < eom && !had_error) { 232 n = dn_expand(answer->buf, eom, cp, bp, buflen); 233 if (n < 0) { 234 had_error++; 235 continue; 236 } 237 cp += n; /* name */ 238 type = _getshort(cp); 239 cp += INT16SZ; /* type */ 240 class = _getshort(cp); 241 cp += INT16SZ + INT32SZ; /* class, TTL */ 242 n = _getshort(cp); 243 cp += INT16SZ; /* len */ 244 if (class != qclass) { 245 /* XXX - debug? syslog? */ 246 cp += n; 247 continue; /* XXX - had_error++ ? */ 248 } 249 if (qtype == T_A && type == T_CNAME) { 250 if (ap >= &host_aliases[MAXALIASES-1]) 251 continue; 252 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 253 if (n < 0) { 254 had_error++; 255 continue; 256 } 257 cp += n; 258 if (host.h_name && strcasecmp(host.h_name, bp) != 0) { 259 syslog(LOG_NOTICE|LOG_AUTH, 260 "gethostby*.gethostanswer: asked for \"%s\", got CNAME for \"%s\"", 261 host.h_name, bp); 262 continue; /* XXX - had_error++ ? */ 263 } 264 /* Store alias. */ 265 *ap++ = bp; 266 n = strlen(bp) + 1; /* for the \0 */ 267 bp += n; 268 buflen -= n; 269 /* Get canonical name. */ 270 n = strlen(tbuf) + 1; /* for the \0 */ 271 if (n > buflen) { 272 had_error++; 273 continue; 274 } 275 strcpy(bp, tbuf); 276 host.h_name = bp; 277 bp += n; 278 buflen -= n; 279 continue; 280 } 281 if (type != qtype) { 282 /* CNAME->PTR should not cause a log message. */ 283 if (!(qtype == T_PTR && type == T_CNAME)) 284 syslog(LOG_NOTICE|LOG_AUTH, 285 "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", 286 qname, p_class(qclass), p_type(qtype), 287 p_type(type)); 288 cp += n; 289 continue; /* XXX - had_error++ ? */ 290 } 291 switch (type) { 292 case T_PTR: 293 if (strcasecmp(qname, bp) != 0) { 294 syslog(LOG_NOTICE|LOG_AUTH, 295 AskedForGot, qname, bp); 296 cp += n; 297 continue; /* XXX - had_error++ ? */ 298 } 299 n = dn_expand(answer->buf, eom, cp, bp, buflen); 300 if (n < 0) { 301 had_error++; 302 break; 303 } 304 #if MULTI_PTRS_ARE_ALIASES 305 cp += n; 306 if (!haveanswer) 307 host.h_name = bp; 308 else if (ap < &host_aliases[MAXALIASES-1]) 309 *ap++ = bp; 310 else 311 n = -1; 312 if (n != -1) { 313 n = strlen(bp) + 1; /* for the \0 */ 314 bp += n; 315 buflen -= n; 316 } 317 break; 318 #else 319 host.h_name = bp; 320 h_errno = NETDB_SUCCESS; 321 return (&host); 322 #endif 323 case T_A: 324 if (strcasecmp(host.h_name, bp) != 0) { 325 syslog(LOG_NOTICE|LOG_AUTH, 326 AskedForGot, host.h_name, bp); 327 cp += n; 328 continue; /* XXX - had_error++ ? */ 329 } 330 if (haveanswer) { 331 if (n != host.h_length) { 332 cp += n; 333 continue; 334 } 335 } else { 336 register int nn; 337 338 host.h_length = n; 339 host.h_addrtype = (class == C_IN) 340 ? AF_INET 341 : AF_UNSPEC; 342 host.h_name = bp; 343 nn = strlen(bp) + 1; /* for the \0 */ 344 bp += nn; 345 buflen -= nn; 346 } 347 348 bp += sizeof(align) - ((u_long)bp % sizeof(align)); 349 350 if (bp + n >= &hostbuf[sizeof hostbuf]) { 351 dprintf("size (%d) too big\n", n); 352 had_error++; 353 continue; 354 } 355 if (hap >= &h_addr_ptrs[MAXADDRS-1]) { 356 if (!toobig++) 357 dprintf("Too many addresses (%d)\n", 358 MAXADDRS); 359 cp += n; 360 continue; 361 } 362 bcopy(cp, *hap++ = bp, n); 363 bp += n; 364 cp += n; 365 break; 366 default: 367 dprintf("Impossible condition (type=%d)\n", type); 368 h_errno = NO_RECOVERY; 369 return (NULL); 370 } /*switch*/ 371 if (!had_error) 372 haveanswer++; 373 } /*while*/ 374 if (haveanswer) { 375 *ap = NULL; 376 *hap = NULL; 377 # if defined(RESOLVSORT) 378 /* 379 * Note: we sort even if host can take only one address 380 * in its return structures - should give it the "best" 381 * address in that case, not some random one 382 */ 383 if (_res.nsort && haveanswer > 1 && 384 qclass == C_IN && qtype == T_A) 385 addrsort(h_addr_ptrs, haveanswer); 386 # endif /*RESOLVSORT*/ 387 if (!host.h_name) { 388 n = strlen(qname) + 1; /* for the \0 */ 389 strcpy(bp, qname); 390 host.h_name = bp; 391 } 392 h_errno = NETDB_SUCCESS; 393 return (&host); 394 } else { 395 h_errno = TRY_AGAIN; 396 return (NULL); 397 } 398 } 399 400 struct hostent * 401 _gethostbydnsname(name) 402 const char *name; 403 { 404 querybuf buf; 405 register const char *cp; 406 int n; 407 408 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 409 h_errno = NETDB_INTERNAL; 410 return (NULL); 411 } 412 413 /* 414 * if there aren't any dots, it could be a user-level alias. 415 * this is also done in res_query() since we are not the only 416 * function that looks up host names. 417 */ 418 if (!strchr(name, '.') && (cp = __hostalias(name))) 419 name = cp; 420 421 /* 422 * disallow names consisting only of digits/dots, unless 423 * they end in a dot. 424 */ 425 if (isdigit(name[0])) 426 for (cp = name;; ++cp) { 427 if (!*cp) { 428 if (*--cp == '.') 429 break; 430 /* 431 * All-numeric, no dot at the end. 432 * Fake up a hostent as if we'd actually 433 * done a lookup. 434 */ 435 if (!inet_aton(name, &host_addr)) { 436 h_errno = HOST_NOT_FOUND; 437 return (NULL); 438 } 439 strncpy(hostbuf, name, MAXDNAME); 440 hostbuf[MAXDNAME] = '\0'; 441 host.h_name = hostbuf; 442 host.h_aliases = host_aliases; 443 host_aliases[0] = NULL; 444 host.h_addrtype = AF_INET; 445 host.h_length = INT32SZ; 446 h_addr_ptrs[0] = (char *)&host_addr; 447 h_addr_ptrs[1] = NULL; 448 host.h_addr_list = h_addr_ptrs; 449 return (&host); 450 } 451 if (!isdigit(*cp) && *cp != '.') 452 break; 453 } 454 455 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) { 456 dprintf("res_search failed (%d)\n", n); 457 return (NULL); 458 } 459 return (gethostanswer(&buf, n, name, C_IN, T_A)); 460 } 461 462 struct hostent * 463 _gethostbydnsaddr(addr, len, type) 464 const char *addr; 465 int len, type; 466 { 467 int n; 468 querybuf buf; 469 register struct hostent *hp; 470 char qbuf[MAXDNAME+1]; 471 #ifdef SUNSECURITY 472 register struct hostent *rhp; 473 char **haddr; 474 u_long old_options; 475 char hname2[MAXDNAME+1]; 476 #endif /*SUNSECURITY*/ 477 478 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 479 h_errno = NETDB_INTERNAL; 480 return (NULL); 481 } 482 if (type != AF_INET) { 483 errno = EAFNOSUPPORT; 484 h_errno = NETDB_INTERNAL; 485 return (NULL); 486 } 487 (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", 488 ((unsigned)addr[3] & 0xff), 489 ((unsigned)addr[2] & 0xff), 490 ((unsigned)addr[1] & 0xff), 491 ((unsigned)addr[0] & 0xff)); 492 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf); 493 if (n < 0) { 494 dprintf("res_query failed (%d)\n", n); 495 return (NULL); 496 } 497 if (!(hp = gethostanswer(&buf, n, qbuf, C_IN, T_PTR))) 498 return (NULL); /* h_errno was set by gethostanswer() */ 499 #ifdef SUNSECURITY 500 /* 501 * turn off search as the name should be absolute, 502 * 'localhost' should be matched by defnames 503 */ 504 strncpy(hname2, hp->h_name, MAXDNAME); 505 hname2[MAXDNAME] = '\0'; 506 old_options = _res.options; 507 _res.options &= ~RES_DNSRCH; 508 _res.options |= RES_DEFNAMES; 509 if (!(rhp = gethostbyname(hname2))) { 510 syslog(LOG_NOTICE|LOG_AUTH, 511 "gethostbyaddr: No A record for %s (verifying [%s])", 512 hname2, inet_ntoa(*((struct in_addr *)addr))); 513 _res.options = old_options; 514 h_errno = HOST_NOT_FOUND; 515 return (NULL); 516 } 517 _res.options = old_options; 518 for (haddr = rhp->h_addr_list; *haddr; haddr++) 519 if (!memcmp(*haddr, addr, INADDRSZ)) 520 break; 521 if (!*haddr) { 522 syslog(LOG_NOTICE|LOG_AUTH, 523 "gethostbyaddr: A record of %s != PTR record [%s]", 524 hname2, inet_ntoa(*((struct in_addr *)addr))); 525 h_errno = HOST_NOT_FOUND; 526 return (NULL); 527 } 528 #endif /*SUNSECURITY*/ 529 hp->h_addrtype = type; 530 hp->h_length = len; 531 h_addr_ptrs[0] = (char *)&host_addr; 532 h_addr_ptrs[1] = NULL; 533 host_addr = *(struct in_addr *)addr; 534 h_errno = NETDB_SUCCESS; 535 return (hp); 536 } 537 538 void 539 _sethostdnsent(stayopen) 540 int stayopen; 541 { 542 if (stayopen) 543 _res.options |= RES_STAYOPEN | RES_USEVC; 544 } 545 546 void 547 _endhostdnsent() 548 { 549 _res.options &= ~(RES_STAYOPEN | RES_USEVC); 550 _res_close(); 551 } 552