initial import
[glibc.git] / resolv / gethnamaddr.c
blob55a3fb09a4b8bfe9733b215fc6af5223529d9f34
1 /*
2 * ++Copyright++ 1985, 1988, 1993
3 * -
4 * Copyright (c) 1985, 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 * -
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 * -
53 * --Copyright--
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
58 static char rcsid[] = "$Id$";
59 #endif /* LIBC_SCCS and not lint */
61 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 #include <arpa/nameser.h>
67 #include <stdio.h>
68 #include <netdb.h>
69 #include <resolv.h>
70 #include <ctype.h>
71 #include <errno.h>
72 #include <syslog.h>
74 #ifndef LOG_AUTH
75 # define LOG_AUTH 0
76 #endif
78 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
80 #if defined(BSD) && (BSD >= 199103)
81 # include <string.h>
82 #else
83 # include "../conf/portability.h"
84 #endif
85 #if defined(USE_OPTIONS_H)
86 # include <../conf/options.h>
87 #endif
89 #define MAXALIASES 35
90 #define MAXADDRS 35
92 static const char AskedForGot[] =
93 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
95 static char *h_addr_ptrs[MAXADDRS + 1];
97 static struct hostent host;
98 static char *host_aliases[MAXALIASES];
99 static char hostbuf[8*1024];
100 static struct in_addr host_addr;
101 static FILE *hostf = NULL;
102 static int stayopen = 0;
104 #ifdef RESOLVSORT
105 static void addrsort __P((char **, int));
106 #endif
108 #if PACKETSZ > 1024
109 #define MAXPACKET PACKETSZ
110 #else
111 #define MAXPACKET 1024
112 #endif
114 typedef union {
115 HEADER hdr;
116 u_char buf[MAXPACKET];
117 } querybuf;
119 typedef union {
120 int32_t al;
121 char ac;
122 } align;
124 extern int h_errno;
126 #ifdef DEBUG
127 static void
128 dprintf(msg, num)
129 char *msg;
130 int num;
132 if (_res.options & RES_DEBUG) {
133 int save = errno;
135 printf(msg, num);
136 errno = save;
139 #else
140 # define dprintf(msg, num) /*nada*/
141 #endif
143 static struct hostent *
144 getanswer(answer, anslen, qname, qclass, qtype)
145 const querybuf *answer;
146 int anslen;
147 const char *qname;
148 int qclass, qtype;
150 register const HEADER *hp;
151 register const u_char *cp;
152 register int n;
153 const u_char *eom;
154 char *bp, **ap, **hap;
155 int type, class, buflen, ancount, qdcount;
156 int haveanswer, had_error;
157 int toobig = 0;
158 char tbuf[MAXDNAME+1];
160 host.h_name = NULL;
161 eom = answer->buf + anslen;
163 * find first satisfactory answer
165 hp = &answer->hdr;
166 ancount = ntohs(hp->ancount);
167 qdcount = ntohs(hp->qdcount);
168 bp = hostbuf;
169 buflen = sizeof hostbuf;
170 cp = answer->buf + HFIXEDSZ;
171 if (qdcount != 1) {
172 h_errno = NO_RECOVERY;
173 return (NULL);
175 if ((n = dn_expand(answer->buf, eom, cp, bp, buflen)) < 0) {
176 h_errno = NO_RECOVERY;
177 return (NULL);
179 cp += n + QFIXEDSZ;
180 if (qtype == T_A) {
181 /* res_send() has already verified that the query name is the
182 * same as the one we sent; this just gets the expanded name
183 * (i.e., with the succeeding search-domain tacked on).
185 n = strlen(bp) + 1; /* for the \0 */
186 host.h_name = bp;
187 bp += n;
188 buflen -= n;
189 /* The qname can be abbreviated, but h_name is now absolute. */
190 qname = host.h_name;
192 ap = host_aliases;
193 *ap = NULL;
194 host.h_aliases = host_aliases;
195 hap = h_addr_ptrs;
196 *hap = NULL;
197 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
198 host.h_addr_list = h_addr_ptrs;
199 #endif
200 haveanswer = 0;
201 had_error = 0;
202 while (ancount-- > 0 && cp < eom && !had_error) {
203 n = dn_expand(answer->buf, eom, cp, bp, buflen);
204 if (n < 0) {
205 had_error++;
206 continue;
208 cp += n; /* name */
209 type = _getshort(cp);
210 cp += INT16SZ; /* type */
211 class = _getshort(cp);
212 cp += INT16SZ + INT32SZ; /* class, TTL */
213 n = _getshort(cp);
214 cp += INT16SZ; /* len */
215 if (class != qclass) {
216 /* XXX - debug? syslog? */
217 cp += n;
218 continue; /* XXX - had_error++ ? */
220 if (qtype == T_A && type == T_CNAME) {
221 if (ap >= &host_aliases[MAXALIASES-1])
222 continue;
223 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
224 if (n < 0) {
225 had_error++;
226 continue;
228 cp += n;
229 if (host.h_name && strcasecmp(host.h_name, bp) != 0) {
230 syslog(LOG_NOTICE|LOG_AUTH,
231 "gethostby*.getanswer: asked for \"%s\", got CNAME for \"%s\"",
232 host.h_name, bp);
233 continue; /* XXX - had_error++ ? */
235 /* Store alias. */
236 *ap++ = bp;
237 n = strlen(bp) + 1; /* for the \0 */
238 bp += n;
239 buflen -= n;
240 /* Get canonical name. */
241 n = strlen(tbuf) + 1; /* for the \0 */
242 if (n > buflen) {
243 had_error++;
244 continue;
246 strcpy(bp, tbuf);
247 host.h_name = bp;
248 bp += n;
249 buflen -= n;
250 continue;
252 if (type != qtype) {
253 syslog(LOG_NOTICE|LOG_AUTH,
254 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
255 qname, p_class(qclass), p_type(qtype),
256 p_type(type));
257 cp += n;
258 continue; /* XXX - had_error++ ? */
260 switch (type) {
261 case T_PTR:
262 if (strcasecmp(qname, bp) != 0) {
263 syslog(LOG_NOTICE|LOG_AUTH,
264 AskedForGot, qname, bp);
265 cp += n;
266 continue; /* XXX - had_error++ ? */
268 n = dn_expand(answer->buf, eom, cp, bp, buflen);
269 if (n < 0) {
270 had_error++;
271 break;
273 #if MULTI_PTRS_ARE_ALIASES
274 cp += n;
275 if (!haveanswer)
276 host.h_name = bp;
277 else if (ap < &host_aliases[MAXALIASES-1])
278 *ap++ = bp;
279 else
280 n = -1;
281 if (n != -1) {
282 n = strlen(bp) + 1; /* for the \0 */
283 bp += n;
284 buflen -= n;
286 break;
287 #else
288 host.h_name = bp;
289 h_errno = NETDB_SUCCESS;
290 return (&host);
291 #endif
292 case T_A:
293 if (strcasecmp(host.h_name, bp) != 0) {
294 syslog(LOG_NOTICE|LOG_AUTH,
295 AskedForGot, host.h_name, bp);
296 cp += n;
297 continue; /* XXX - had_error++ ? */
299 if (haveanswer) {
300 if (n != host.h_length) {
301 cp += n;
302 continue;
304 } else {
305 register int nn;
307 host.h_length = n;
308 host.h_addrtype = (class == C_IN)
309 ? AF_INET
310 : AF_UNSPEC;
311 host.h_name = bp;
312 nn = strlen(bp) + 1; /* for the \0 */
313 bp += nn;
314 buflen -= nn;
317 bp += sizeof(align) - ((u_long)bp % sizeof(align));
319 if (bp + n >= &hostbuf[sizeof hostbuf]) {
320 dprintf("size (%d) too big\n", n);
321 had_error++;
322 continue;
324 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
325 if (!toobig++)
326 dprintf("Too many addresses (%d)\n",
327 MAXADDRS);
328 cp += n;
329 continue;
331 bcopy(cp, *hap++ = bp, n);
332 bp += n;
333 cp += n;
334 break;
335 default:
336 dprintf("Impossible condition (type=%d)\n", type);
337 h_errno = NO_RECOVERY;
338 return (NULL);
339 } /*switch*/
340 if (!had_error)
341 haveanswer++;
342 } /*while*/
343 if (haveanswer) {
344 *ap = NULL;
345 *hap = NULL;
346 # if defined(RESOLVSORT)
348 * Note: we sort even if host can take only one address
349 * in its return structures - should give it the "best"
350 * address in that case, not some random one
352 if (_res.nsort && haveanswer > 1 &&
353 qclass == C_IN && qtype == T_A)
354 addrsort(h_addr_ptrs, haveanswer);
355 # endif /*RESOLVSORT*/
356 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
357 /* nothing */
358 #else
359 host.h_addr = h_addr_ptrs[0];
360 #endif /*BSD*/
361 if (!host.h_name) {
362 n = strlen(qname) + 1; /* for the \0 */
363 strcpy(bp, qname);
364 host.h_name = bp;
366 h_errno = NETDB_SUCCESS;
367 return (&host);
368 } else {
369 h_errno = TRY_AGAIN;
370 return (NULL);
374 struct hostent *
375 gethostbyname(name)
376 const char *name;
378 querybuf buf;
379 register const char *cp;
380 int n;
381 extern struct hostent *_gethtbyname();
384 * if there aren't any dots, it could be a user-level alias.
385 * this is also done in res_query() since we are not the only
386 * function that looks up host names.
388 if (!strchr(name, '.') && (cp = __hostalias(name)))
389 name = cp;
392 * disallow names consisting only of digits/dots, unless
393 * they end in a dot.
395 if (isdigit(name[0]))
396 for (cp = name;; ++cp) {
397 if (!*cp) {
398 if (*--cp == '.')
399 break;
401 * All-numeric, no dot at the end.
402 * Fake up a hostent as if we'd actually
403 * done a lookup.
405 if (!inet_aton(name, &host_addr)) {
406 h_errno = HOST_NOT_FOUND;
407 return (NULL);
409 host.h_name = (char *)name;
410 host.h_aliases = host_aliases;
411 host_aliases[0] = NULL;
412 host.h_addrtype = AF_INET;
413 host.h_length = INT32SZ;
414 h_addr_ptrs[0] = (char *)&host_addr;
415 h_addr_ptrs[1] = NULL;
416 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
417 host.h_addr_list = h_addr_ptrs;
418 #else
419 host.h_addr = h_addr_ptrs[0];
420 #endif
421 h_errno = NETDB_SUCCESS;
422 return (&host);
424 if (!isdigit(*cp) && *cp != '.')
425 break;
428 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
429 dprintf("res_search failed (%d)\n", n);
430 if (errno == ECONNREFUSED)
431 return (_gethtbyname(name));
432 return (NULL);
434 return (getanswer(&buf, n, name, C_IN, T_A));
437 struct hostent *
438 gethostbyaddr(addr, len, type)
439 const char *addr;
440 int len, type;
442 int n;
443 querybuf buf;
444 register struct hostent *hp;
445 char qbuf[MAXDNAME+1];
446 #ifdef SUNSECURITY
447 register struct hostent *rhp;
448 char **haddr;
449 u_long old_options;
450 char hname2[MAXDNAME+1];
451 #endif /*SUNSECURITY*/
452 extern struct hostent *_gethtbyaddr();
454 if (type != AF_INET) {
455 errno = EAFNOSUPPORT;
456 h_errno = NETDB_INTERNAL;
457 return (NULL);
459 (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
460 ((unsigned)addr[3] & 0xff),
461 ((unsigned)addr[2] & 0xff),
462 ((unsigned)addr[1] & 0xff),
463 ((unsigned)addr[0] & 0xff));
464 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
465 if (n < 0) {
466 dprintf("res_query failed (%d)\n", n);
467 if (errno == ECONNREFUSED)
468 return (_gethtbyaddr(addr, len, type));
469 return (NULL);
471 if (!(hp = getanswer(&buf, n, qbuf, C_IN, T_PTR)))
472 return (NULL); /* h_errno was set by getanswer() */
473 #ifdef SUNSECURITY
475 * turn off search as the name should be absolute,
476 * 'localhost' should be matched by defnames
478 strncpy(hname2, hp->h_name, MAXDNAME);
479 hname2[MAXDNAME] = '\0';
480 old_options = _res.options;
481 _res.options &= ~RES_DNSRCH;
482 _res.options |= RES_DEFNAMES;
483 if (!(rhp = gethostbyname(hp->h_name))) {
484 syslog(LOG_NOTICE|LOG_AUTH,
485 "gethostbyaddr: No A record for %s (verifying [%s])",
486 hname2, inet_ntoa(*((struct in_addr *)addr)));
487 _res.options = old_options;
488 h_errno = HOST_NOT_FOUND;
489 return (NULL);
491 _res.options = old_options;
492 for (haddr = rhp->h_addr_list; *haddr; haddr++)
493 if (!memcmp(*haddr, addr, INADDRSZ))
494 break;
495 if (!*haddr) {
496 syslog(LOG_NOTICE|LOG_AUTH,
497 "gethostbyaddr: A record of %s != PTR record [%s]",
498 hname2, inet_ntoa(*((struct in_addr *)addr)));
499 h_errno = HOST_NOT_FOUND;
500 return (NULL);
502 #endif /*SUNSECURITY*/
503 hp->h_addrtype = type;
504 hp->h_length = len;
505 h_addr_ptrs[0] = (char *)&host_addr;
506 h_addr_ptrs[1] = NULL;
507 host_addr = *(struct in_addr *)addr;
508 h_errno = NETDB_SUCCESS;
509 return (hp);
512 void
513 _sethtent(f)
514 int f;
516 if (!hostf)
517 hostf = fopen(_PATH_HOSTS, "r" );
518 else
519 rewind(hostf);
520 stayopen = f;
523 void
524 _endhtent()
526 if (hostf && !stayopen) {
527 (void) fclose(hostf);
528 hostf = NULL;
532 struct hostent *
533 _gethtent()
535 char *p;
536 register char *cp, **q;
538 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
539 h_errno = NETDB_INTERNAL;
540 return (NULL);
542 again:
543 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
544 h_errno = HOST_NOT_FOUND;
545 return (NULL);
547 if (*p == '#')
548 goto again;
549 if (!(cp = strpbrk(p, "#\n")))
550 goto again;
551 *cp = '\0';
552 if (!(cp = strpbrk(p, " \t")))
553 goto again;
554 *cp++ = '\0';
555 /* THIS STUFF IS INTERNET SPECIFIC */
556 if (!inet_aton(p, &host_addr))
557 goto again;
558 h_addr_ptrs[0] = (char *)&host_addr;
559 h_addr_ptrs[1] = NULL;
560 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
561 host.h_addr_list = h_addr_ptrs;
562 #else
563 host.h_addr = h_addr_ptrs[0];
564 #endif
565 host.h_length = INT32SZ;
566 host.h_addrtype = AF_INET;
567 while (*cp == ' ' || *cp == '\t')
568 cp++;
569 host.h_name = cp;
570 q = host.h_aliases = host_aliases;
571 if (cp = strpbrk(cp, " \t"))
572 *cp++ = '\0';
573 while (cp && *cp) {
574 if (*cp == ' ' || *cp == '\t') {
575 cp++;
576 continue;
578 if (q < &host_aliases[MAXALIASES - 1])
579 *q++ = cp;
580 if (cp = strpbrk(cp, " \t"))
581 *cp++ = '\0';
583 *q = NULL;
584 h_errno = NETDB_SUCCESS;
585 return (&host);
588 struct hostent *
589 _gethtbyname(name)
590 char *name;
592 register struct hostent *p;
593 register char **cp;
595 _sethtent(0);
596 while (p = _gethtent()) {
597 if (strcasecmp(p->h_name, name) == 0)
598 break;
599 for (cp = p->h_aliases; *cp != 0; cp++)
600 if (strcasecmp(*cp, name) == 0)
601 goto found;
603 found:
604 _endhtent();
605 return (p);
608 struct hostent *
609 _gethtbyaddr(addr, len, type)
610 const char *addr;
611 int len, type;
613 register struct hostent *p;
615 _sethtent(0);
616 while (p = _gethtent())
617 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
618 break;
619 _endhtent();
620 return (p);
623 #ifdef RESOLVSORT
624 static void
625 addrsort(ap, num)
626 char **ap;
627 int num;
629 int i, j;
630 char **p;
631 short aval[MAXADDRS];
632 int needsort = 0;
634 p = ap;
635 for (i = 0; i < num; i++, p++) {
636 for (j = 0 ; (unsigned)j < _res.nsort; j++)
637 if (_res.sort_list[j].addr.s_addr ==
638 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
639 break;
640 aval[i] = j;
641 if (needsort == 0 && i > 0 && j < aval[i-1])
642 needsort = i;
644 if (!needsort)
645 return;
647 while (needsort < num) {
648 for (j = needsort - 1; j >= 0; j--) {
649 if (aval[j] > aval[j+1]) {
650 char *hp;
652 i = aval[j];
653 aval[j] = aval[j+1];
654 aval[j+1] = i;
656 hp = ap[j];
657 ap[j] = ap[j+1];
658 ap[j+1] = hp;
660 } else
661 break;
663 needsort++;
666 #endif
668 #if defined(BSD43_BSD43_NFS) || defined(sun)
669 /* some libc's out there are bound internally to these names (UMIPS) */
670 void
671 ht_sethostent(stayopen)
672 int stayopen;
674 _sethtent(stayopen);
677 void
678 ht_endhostent()
680 _endhtent();
683 struct hostent *
684 ht_gethostbyname(name)
685 char *name;
687 return (_gethtbyname(name));
690 struct hostent *
691 ht_gethostbyaddr(addr, len, type)
692 const char *addr;
693 int len, type;
695 return (_gethtbyaddr(addr, len, type));
698 struct hostent *
699 gethostent()
701 return (_gethtent());
704 void
705 dns_service()
707 return;
710 #undef dn_skipname
711 dn_skipname(comp_dn, eom)
712 const u_char *comp_dn, *eom;
714 return (__dn_skipname(comp_dn, eom));
716 #endif /*old-style libc with yp junk in it*/
718 #ifdef ultrix
719 /* more icky libc packaging in ultrix */
721 local_hostname_length(hostname)
722 const char *hostname;
724 int len_host, len_domain;
726 if (!*_res.defdname)
727 res_init();
728 len_host = strlen(hostname);
729 len_domain = strlen(_res.defdname);
730 if (len_host > len_domain &&
731 !strcasecmp(hostname + len_host - len_domain, _res.defdname) &&
732 hostname[len_host - len_domain - 1] == '.')
733 return (len_host - len_domain - 1);
734 return (0);
736 #endif