gethnamaddr.c revision 1.8 1 /* $NetBSD: gethnamaddr.c,v 1.8 1998/11/13 15:46:53 christos Exp $ */
2
3 /*
4 * ++Copyright++ 1985, 1988, 1993
5 * -
6 * Copyright (c) 1985, 1988, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 * -
37 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
38 *
39 * Permission to use, copy, modify, and distribute this software for any
40 * purpose with or without fee is hereby granted, provided that the above
41 * copyright notice and this permission notice appear in all copies, and that
42 * the name of Digital Equipment Corporation not be used in advertising or
43 * publicity pertaining to distribution of the document or software without
44 * specific, written prior permission.
45 *
46 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
47 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
49 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
50 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
51 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
52 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 * SOFTWARE.
54 * -
55 * --Copyright--
56 */
57
58 #include <sys/cdefs.h>
59 #if defined(LIBC_SCCS) && !defined(lint)
60 #if 0
61 static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
62 static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp ";
63 #else
64 __RCSID("$NetBSD: gethnamaddr.c,v 1.8 1998/11/13 15:46:53 christos Exp $");
65 #endif
66 #endif /* LIBC_SCCS and not lint */
67
68 #if defined(_LIBC)
69 #include "namespace.h"
70 #endif
71 #include <sys/types.h>
72 #include <sys/param.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
76 #include <arpa/nameser.h>
77
78 #include <stdio.h>
79 #include <netdb.h>
80 #include <resolv.h>
81 #include <ctype.h>
82 #include <errno.h>
83 #include <syslog.h>
84
85 #ifndef LOG_AUTH
86 # define LOG_AUTH 0
87 #endif
88
89 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
90
91 #include <stdlib.h>
92 #include <string.h>
93
94 #ifdef YP
95 #include <rpc/rpc.h>
96 #include <rpcsvc/yp_prot.h>
97 #include <rpcsvc/ypclnt.h>
98 #endif
99
100 #if defined(_LIBC) && defined(__weak_alias)
101 __weak_alias(gethostbyaddr,_gethostbyaddr);
102 __weak_alias(gethostbyname,_gethostbyname);
103 #endif
104
105 #define MAXALIASES 35
106 #define MAXADDRS 35
107
108 static const char AskedForGot[] =
109 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
110
111 static char *h_addr_ptrs[MAXADDRS + 1];
112
113 #ifdef YP
114 static char *__ypdomain;
115 #endif
116
117 static struct hostent host;
118 static char *host_aliases[MAXALIASES];
119 static char hostbuf[8*1024];
120 static u_char host_addr[16]; /* IPv4 or IPv6 */
121 static FILE *hostf = NULL;
122 static int stayopen = 0;
123
124
125 #if PACKETSZ > 1024
126 #define MAXPACKET PACKETSZ
127 #else
128 #define MAXPACKET 1024
129 #endif
130
131 typedef union {
132 HEADER hdr;
133 u_char buf[MAXPACKET];
134 } querybuf;
135
136 typedef union {
137 int32_t al;
138 char ac;
139 } align;
140
141 extern int h_errno;
142
143 #ifdef DEBUG
144 static void dprintf __P((char *, int));
145 #endif
146 static struct hostent *getanswer __P((const querybuf *, int,
147 const char *, int));
148 static void map_v4v6_address __P((const char *, char *));
149 static void map_v4v6_hostent __P((struct hostent *, char **, int *));
150 #ifdef RESOLVSORT
151 static void addrsort __P((char **, int));
152 #endif
153
154 struct hostent *gethostbyname __P((const char *));
155 struct hostent *gethostbyname2 __P((const char *, int));
156 struct hostent *gethostbyaddr __P((const char *, int, int ));
157 void _sethtent __P((int));
158 void _endhtent __P((void));
159 struct hostent *_gethtent __P((void));
160 struct hostent *_gethtbyname __P((const char *));
161 struct hostent *_gethtbyname2 __P((const char *, int));
162 struct hostent *_gethtbyaddr __P((const char *, int, int ));
163 void ht_sethostent __P((int));
164 void ht_endhostent __P((void));
165 struct hostent *ht_gethostbyname __P((char *));
166 struct hostent *ht_gethostbyaddr __P((const char *, int, int ));
167 struct hostent *gethostent __P((void));
168 void dns_service __P((void));
169 int dn_skipname __P((const u_char *, const u_char *));
170 #ifdef YP
171 struct hostent *_yphostent __P((char *));
172 struct hostent *_yp_gethtbyaddr __P((const char *, int, int ));
173 struct hostent *_yp_gethtbyname __P((const char *));
174 #endif
175
176
177 #ifdef DEBUG
178 static void
179 dprintf(msg, num)
180 char *msg;
181 int num;
182 {
183 if (_res.options & RES_DEBUG) {
184 int save = errno;
185
186 printf(msg, num);
187 errno = save;
188 }
189 }
190 #else
191 # define dprintf(msg, num) /*nada*/
192 #endif
193
194 static struct hostent *
195 getanswer(answer, anslen, qname, qtype)
196 const querybuf *answer;
197 int anslen;
198 const char *qname;
199 int qtype;
200 {
201 register const HEADER *hp;
202 register const u_char *cp;
203 register int n;
204 const u_char *eom;
205 char *bp, **ap, **hap;
206 int type, class, buflen, ancount, qdcount;
207 int haveanswer, had_error;
208 int toobig = 0;
209 char tbuf[MAXDNAME];
210 const char *tname;
211 int (*name_ok) __P((const char *));
212
213 tname = qname;
214 host.h_name = NULL;
215 eom = answer->buf + anslen;
216 switch (qtype) {
217 case T_A:
218 case T_AAAA:
219 name_ok = res_hnok;
220 break;
221 case T_PTR:
222 name_ok = res_dnok;
223 break;
224 default:
225 return (NULL); /* XXX should be abort(); */
226 }
227 /*
228 * find first satisfactory answer
229 */
230 hp = &answer->hdr;
231 ancount = ntohs(hp->ancount);
232 qdcount = ntohs(hp->qdcount);
233 bp = hostbuf;
234 buflen = sizeof hostbuf;
235 cp = answer->buf + HFIXEDSZ;
236 if (qdcount != 1) {
237 h_errno = NO_RECOVERY;
238 return (NULL);
239 }
240 n = dn_expand(answer->buf, eom, cp, bp, buflen);
241 if ((n < 0) || !(*name_ok)(bp)) {
242 h_errno = NO_RECOVERY;
243 return (NULL);
244 }
245 cp += n + QFIXEDSZ;
246 if (qtype == T_A || qtype == T_AAAA) {
247 /* res_send() has already verified that the query name is the
248 * same as the one we sent; this just gets the expanded name
249 * (i.e., with the succeeding search-domain tacked on).
250 */
251 n = strlen(bp) + 1; /* for the \0 */
252 if (n >= MAXHOSTNAMELEN) {
253 h_errno = NO_RECOVERY;
254 return (NULL);
255 }
256 host.h_name = bp;
257 bp += n;
258 buflen -= n;
259 /* The qname can be abbreviated, but h_name is now absolute. */
260 qname = host.h_name;
261 }
262 ap = host_aliases;
263 *ap = NULL;
264 host.h_aliases = host_aliases;
265 hap = h_addr_ptrs;
266 *hap = NULL;
267 host.h_addr_list = h_addr_ptrs;
268 haveanswer = 0;
269 had_error = 0;
270 while (ancount-- > 0 && cp < eom && !had_error) {
271 n = dn_expand(answer->buf, eom, cp, bp, buflen);
272 if ((n < 0) || !(*name_ok)(bp)) {
273 had_error++;
274 continue;
275 }
276 cp += n; /* name */
277 type = _getshort(cp);
278 cp += INT16SZ; /* type */
279 class = _getshort(cp);
280 cp += INT16SZ + INT32SZ; /* class, TTL */
281 n = _getshort(cp);
282 cp += INT16SZ; /* len */
283 if (class != C_IN) {
284 /* XXX - debug? syslog? */
285 cp += n;
286 continue; /* XXX - had_error++ ? */
287 }
288 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
289 if (ap >= &host_aliases[MAXALIASES-1])
290 continue;
291 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
292 if ((n < 0) || !(*name_ok)(tbuf)) {
293 had_error++;
294 continue;
295 }
296 cp += n;
297 /* Store alias. */
298 *ap++ = bp;
299 n = strlen(bp) + 1; /* for the \0 */
300 if (n >= MAXHOSTNAMELEN) {
301 had_error++;
302 continue;
303 }
304 bp += n;
305 buflen -= n;
306 /* Get canonical name. */
307 n = strlen(tbuf) + 1; /* for the \0 */
308 if (n > buflen || n >= MAXHOSTNAMELEN) {
309 had_error++;
310 continue;
311 }
312 strcpy(bp, tbuf);
313 host.h_name = bp;
314 bp += n;
315 buflen -= n;
316 continue;
317 }
318 if (qtype == T_PTR && type == T_CNAME) {
319 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
320 if (n < 0 || !res_dnok(tbuf)) {
321 had_error++;
322 continue;
323 }
324 cp += n;
325 /* Get canonical name. */
326 n = strlen(tbuf) + 1; /* for the \0 */
327 if (n > buflen || n >= MAXHOSTNAMELEN) {
328 had_error++;
329 continue;
330 }
331 strcpy(bp, tbuf);
332 tname = bp;
333 bp += n;
334 buflen -= n;
335 continue;
336 }
337 if (type != qtype) {
338 syslog(LOG_NOTICE|LOG_AUTH,
339 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
340 qname, p_class(C_IN), p_type(qtype),
341 p_type(type));
342 cp += n;
343 continue; /* XXX - had_error++ ? */
344 }
345 switch (type) {
346 case T_PTR:
347 if (strcasecmp(tname, bp) != 0) {
348 syslog(LOG_NOTICE|LOG_AUTH,
349 AskedForGot, qname, bp);
350 cp += n;
351 continue; /* XXX - had_error++ ? */
352 }
353 n = dn_expand(answer->buf, eom, cp, bp, buflen);
354 if ((n < 0) || !res_hnok(bp)) {
355 had_error++;
356 break;
357 }
358 #if MULTI_PTRS_ARE_ALIASES
359 cp += n;
360 if (!haveanswer)
361 host.h_name = bp;
362 else if (ap < &host_aliases[MAXALIASES-1])
363 *ap++ = bp;
364 else
365 n = -1;
366 if (n != -1) {
367 n = strlen(bp) + 1; /* for the \0 */
368 if (n >= MAXHOSTNAMELEN) {
369 had_error++;
370 break;
371 }
372 bp += n;
373 buflen -= n;
374 }
375 break;
376 #else
377 host.h_name = bp;
378 if (_res.options & RES_USE_INET6) {
379 n = strlen(bp) + 1; /* for the \0 */
380 if (n >= MAXHOSTNAMELEN) {
381 had_error++;
382 break;
383 }
384 bp += n;
385 buflen -= n;
386 map_v4v6_hostent(&host, &bp, &buflen);
387 }
388 h_errno = NETDB_SUCCESS;
389 return (&host);
390 #endif
391 case T_A:
392 case T_AAAA:
393 if (strcasecmp(host.h_name, bp) != 0) {
394 syslog(LOG_NOTICE|LOG_AUTH,
395 AskedForGot, host.h_name, bp);
396 cp += n;
397 continue; /* XXX - had_error++ ? */
398 }
399 if (n != host.h_length) {
400 cp += n;
401 continue;
402 }
403 if (!haveanswer) {
404 register int nn;
405
406 host.h_name = bp;
407 nn = strlen(bp) + 1; /* for the \0 */
408 bp += nn;
409 buflen -= nn;
410 }
411
412 bp += sizeof(align) - (size_t)((u_long)bp % sizeof(align));
413
414 if (bp + n >= &hostbuf[sizeof hostbuf]) {
415 dprintf("size (%d) too big\n", n);
416 had_error++;
417 continue;
418 }
419 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
420 if (!toobig++)
421 dprintf("Too many addresses (%d)\n",
422 MAXADDRS);
423 cp += n;
424 continue;
425 }
426 (void)memcpy(*hap++ = bp, cp, (size_t)n);
427 bp += n;
428 buflen -= n;
429 cp += n;
430 break;
431 default:
432 abort();
433 }
434 if (!had_error)
435 haveanswer++;
436 }
437 if (haveanswer) {
438 *ap = NULL;
439 *hap = NULL;
440 # if defined(RESOLVSORT)
441 /*
442 * Note: we sort even if host can take only one address
443 * in its return structures - should give it the "best"
444 * address in that case, not some random one
445 */
446 if (_res.nsort && haveanswer > 1 && qtype == T_A)
447 addrsort(h_addr_ptrs, haveanswer);
448 # endif /*RESOLVSORT*/
449 if (!host.h_name) {
450 n = strlen(qname) + 1; /* for the \0 */
451 if (n > buflen || n >= MAXHOSTNAMELEN)
452 goto no_recovery;
453 strcpy(bp, qname);
454 host.h_name = bp;
455 bp += n;
456 buflen -= n;
457 }
458 if (_res.options & RES_USE_INET6)
459 map_v4v6_hostent(&host, &bp, &buflen);
460 h_errno = NETDB_SUCCESS;
461 return (&host);
462 }
463 no_recovery:
464 h_errno = NO_RECOVERY;
465 return (NULL);
466 }
467
468 struct hostent *
469 gethostbyname(name)
470 const char *name;
471 {
472 struct hostent *hp;
473
474 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
475 h_errno = NETDB_INTERNAL;
476 return (NULL);
477 }
478 if (_res.options & RES_USE_INET6) {
479 hp = gethostbyname2(name, AF_INET6);
480 if (hp)
481 return (hp);
482 }
483 return (gethostbyname2(name, AF_INET));
484 }
485
486 struct hostent *
487 gethostbyname2(name, af)
488 const char *name;
489 int af;
490 {
491 querybuf buf;
492 const char *cp;
493 char *bp;
494 int n, size, type, len, i;
495 char lookups[MAXDNSLUS];
496 struct hostent *hp;
497
498 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
499 return (_gethtbyname(name));
500
501 switch (af) {
502 case AF_INET:
503 size = INADDRSZ;
504 type = T_A;
505 break;
506 case AF_INET6:
507 size = IN6ADDRSZ;
508 type = T_AAAA;
509 break;
510 default:
511 h_errno = NETDB_INTERNAL;
512 errno = EAFNOSUPPORT;
513 return (NULL);
514 }
515
516 host.h_addrtype = af;
517 host.h_length = size;
518
519 /*
520 * if there aren't any dots, it could be a user-level alias.
521 * this is also done in res_query() since we are not the only
522 * function that looks up host names.
523 */
524 if (!strchr(name, '.') && (cp = __hostalias(name)))
525 name = cp;
526
527 /*
528 * disallow names consisting only of digits/dots, unless
529 * they end in a dot.
530 */
531 if (isdigit(name[0]))
532 for (cp = name;; ++cp) {
533 if (!*cp) {
534 if (*--cp == '.')
535 break;
536 /*
537 * All-numeric, no dot at the end.
538 * Fake up a hostent as if we'd actually
539 * done a lookup.
540 */
541 if (inet_pton(af, name, host_addr) <= 0) {
542 h_errno = HOST_NOT_FOUND;
543 return (NULL);
544 }
545 strncpy(hostbuf, name, MAXDNAME);
546 hostbuf[MAXDNAME] = '\0';
547 bp = hostbuf + MAXDNAME;
548 len = sizeof hostbuf - MAXDNAME;
549 host.h_name = hostbuf;
550 host.h_aliases = host_aliases;
551 host_aliases[0] = NULL;
552 h_addr_ptrs[0] = (char *)host_addr;
553 h_addr_ptrs[1] = NULL;
554 host.h_addr_list = h_addr_ptrs;
555 if (_res.options & RES_USE_INET6)
556 map_v4v6_hostent(&host, &bp, &len);
557 h_errno = NETDB_SUCCESS;
558 return (&host);
559 }
560 if (!isdigit(*cp) && *cp != '.')
561 break;
562 }
563 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
564 name[0] == ':')
565 for (cp = name;; ++cp) {
566 if (!*cp) {
567 if (*--cp == '.')
568 break;
569 /*
570 * All-IPv6-legal, no dot at the end.
571 * Fake up a hostent as if we'd actually
572 * done a lookup.
573 */
574 if (inet_pton(af, name, host_addr) <= 0) {
575 h_errno = HOST_NOT_FOUND;
576 return (NULL);
577 }
578 strncpy(hostbuf, name, MAXDNAME);
579 hostbuf[MAXDNAME] = '\0';
580 bp = hostbuf + MAXDNAME;
581 len = sizeof hostbuf - MAXDNAME;
582 host.h_name = hostbuf;
583 host.h_aliases = host_aliases;
584 host_aliases[0] = NULL;
585 h_addr_ptrs[0] = (char *)host_addr;
586 h_addr_ptrs[1] = NULL;
587 host.h_addr_list = h_addr_ptrs;
588 h_errno = NETDB_SUCCESS;
589 return (&host);
590 }
591 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
592 break;
593 }
594
595 (void)memcpy(lookups, _res.lookups, sizeof lookups);
596 if (lookups[0] == '\0')
597 strncpy(lookups, "bf", sizeof lookups);
598
599 hp = (struct hostent *)NULL;
600 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
601 switch (lookups[i]) {
602 #ifdef YP
603 case 'y':
604 hp = _yp_gethtbyname(name);
605 break;
606 #endif
607 case 'b':
608 if ((n = res_search(name, C_IN, T_A, buf.buf,
609 sizeof(buf))) < 0) {
610 dprintf("res_search failed (%d)\n", n);
611 break;
612 }
613 hp = getanswer(&buf, n, name, type);
614 break;
615 case 'f':
616 hp = _gethtbyname(name);
617 break;
618 }
619 }
620 return (hp);
621 }
622
623 struct hostent *
624 gethostbyaddr(addr, len, af)
625 const char *addr; /* XXX should have been def'd as u_char! */
626 int len, af;
627 {
628 const u_char *uaddr = (const u_char *)addr;
629 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
630 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
631 int n, size, i;
632 querybuf buf;
633 struct hostent *hp;
634 char qbuf[MAXDNAME+1], *qp;
635 char lookups[MAXDNSLUS];
636
637 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
638 return (_gethtbyaddr(addr, len, af));
639
640 if (af == AF_INET6 && len == IN6ADDRSZ &&
641 (!memcmp(uaddr, mapped, sizeof mapped) ||
642 !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
643 /* Unmap. */
644 addr += sizeof mapped;
645 uaddr += sizeof mapped;
646 af = AF_INET;
647 len = INADDRSZ;
648 }
649 switch (af) {
650 case AF_INET:
651 size = INADDRSZ;
652 break;
653 case AF_INET6:
654 size = IN6ADDRSZ;
655 break;
656 default:
657 errno = EAFNOSUPPORT;
658 h_errno = NETDB_INTERNAL;
659 return (NULL);
660 }
661 if (size != len) {
662 errno = EINVAL;
663 h_errno = NETDB_INTERNAL;
664 return (NULL);
665 }
666 switch (af) {
667 case AF_INET:
668 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
669 (uaddr[3] & 0xff),
670 (uaddr[2] & 0xff),
671 (uaddr[1] & 0xff),
672 (uaddr[0] & 0xff));
673 break;
674 case AF_INET6:
675 qp = qbuf;
676 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
677 qp += sprintf(qp, "%x.%x.",
678 uaddr[n] & 0xf,
679 ((u_int32_t)uaddr[n] >> 4) & 0xf);
680 }
681 strcpy(qp, "ip6.int");
682 break;
683 default:
684 abort();
685 }
686
687 (void)memcpy(lookups, _res.lookups, sizeof lookups);
688 if (lookups[0] == '\0')
689 strncpy(lookups, "bf", sizeof lookups);
690
691 hp = (struct hostent *)NULL;
692 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
693 switch (lookups[i]) {
694 #ifdef YP
695 case 'y':
696 hp = _yp_gethtbyaddr(addr, len, af);
697 break;
698 #endif
699 case 'b':
700 n = res_query(qbuf, C_IN, T_PTR, (u_char *)(void *)&buf,
701 sizeof(buf));
702 if (n < 0) {
703 dprintf("res_query failed (%d)\n", n);
704 break;
705 }
706 hp = getanswer(&buf, n, qbuf, T_PTR);
707 if (hp == NULL)
708 break;
709 hp->h_addrtype = af;
710 hp->h_length = len;
711 (void)memcpy(host_addr, addr, (size_t)len);
712 h_addr_ptrs[0] = (char *)&host_addr;
713 h_addr_ptrs[1] = (char *)0;
714 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
715 map_v4v6_address((char*)host_addr,
716 (char*)host_addr);
717 hp->h_addrtype = AF_INET6;
718 hp->h_length = IN6ADDRSZ;
719 }
720 h_errno = NETDB_SUCCESS;
721 break;
722 case 'f':
723 hp = _gethtbyaddr(addr, len, af);
724 break;
725 }
726 }
727 return (hp);
728 }
729
730 void
731 _sethtent(f)
732 int f;
733 {
734 if (!hostf)
735 hostf = fopen(_PATH_HOSTS, "r" );
736 else
737 rewind(hostf);
738 stayopen = f;
739 }
740
741 void
742 _endhtent()
743 {
744 if (hostf && !stayopen) {
745 (void) fclose(hostf);
746 hostf = NULL;
747 }
748 }
749
750 struct hostent *
751 _gethtent()
752 {
753 char *p;
754 register char *cp, **q;
755 int af, len;
756
757 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
758 h_errno = NETDB_INTERNAL;
759 return (NULL);
760 }
761 again:
762 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
763 h_errno = HOST_NOT_FOUND;
764 return (NULL);
765 }
766 if (*p == '#')
767 goto again;
768 if (!(cp = strpbrk(p, "#\n")))
769 goto again;
770 *cp = '\0';
771 if (!(cp = strpbrk(p, " \t")))
772 goto again;
773 *cp++ = '\0';
774 if (inet_pton(AF_INET6, p, host_addr) > 0) {
775 af = AF_INET6;
776 len = IN6ADDRSZ;
777 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
778 if (_res.options & RES_USE_INET6) {
779 map_v4v6_address((char*)host_addr, (char*)host_addr);
780 af = AF_INET6;
781 len = IN6ADDRSZ;
782 } else {
783 af = AF_INET;
784 len = INADDRSZ;
785 }
786 } else {
787 goto again;
788 }
789 h_addr_ptrs[0] = (char *)host_addr;
790 h_addr_ptrs[1] = NULL;
791 host.h_addr_list = h_addr_ptrs;
792 host.h_length = len;
793 host.h_addrtype = af;
794 while (*cp == ' ' || *cp == '\t')
795 cp++;
796 host.h_name = cp;
797 q = host.h_aliases = host_aliases;
798 if ((cp = strpbrk(cp, " \t")) != NULL)
799 *cp++ = '\0';
800 while (cp && *cp) {
801 if (*cp == ' ' || *cp == '\t') {
802 cp++;
803 continue;
804 }
805 if (q < &host_aliases[MAXALIASES - 1])
806 *q++ = cp;
807 if ((cp = strpbrk(cp, " \t")) != NULL)
808 *cp++ = '\0';
809 }
810 *q = NULL;
811 h_errno = NETDB_SUCCESS;
812 return (&host);
813 }
814
815 struct hostent *
816 _gethtbyname(name)
817 const char *name;
818 {
819 struct hostent *hp;
820
821 if (_res.options & RES_USE_INET6) {
822 hp = _gethtbyname2(name, AF_INET6);
823 if (hp)
824 return (hp);
825 }
826 return (_gethtbyname2(name, AF_INET));
827 }
828
829 struct hostent *
830 _gethtbyname2(name, af)
831 const char *name;
832 int af;
833 {
834 register struct hostent *p;
835 register char **cp;
836
837 _sethtent(0);
838 while ((p = _gethtent()) != NULL) {
839 if (p->h_addrtype != af)
840 continue;
841 if (strcasecmp(p->h_name, name) == 0)
842 break;
843 for (cp = p->h_aliases; *cp != 0; cp++)
844 if (strcasecmp(*cp, name) == 0)
845 goto found;
846 }
847 found:
848 _endhtent();
849 return (p);
850 }
851
852 struct hostent *
853 _gethtbyaddr(addr, len, af)
854 const char *addr;
855 int len, af;
856 {
857 register struct hostent *p;
858
859 _sethtent(0);
860 while ((p = _gethtent()) != NULL)
861 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
862 (size_t)len))
863 break;
864 _endhtent();
865 return (p);
866 }
867
868 static void
869 map_v4v6_address(src, dst)
870 const char *src;
871 char *dst;
872 {
873 u_char *p = (u_char *)dst;
874 char tmp[INADDRSZ];
875 int i;
876
877 /* Stash a temporary copy so our caller can update in place. */
878 (void)memcpy(tmp, src, INADDRSZ);
879 /* Mark this ipv6 addr as a mapped ipv4. */
880 for (i = 0; i < 10; i++)
881 *p++ = 0x00;
882 *p++ = 0xff;
883 *p++ = 0xff;
884 /* Retrieve the saved copy and we're done. */
885 (void)memcpy((void *)p, tmp, INADDRSZ);
886 }
887
888 static void
889 map_v4v6_hostent(hp, bpp, lenp)
890 struct hostent *hp;
891 char **bpp;
892 int *lenp;
893 {
894 char **ap;
895
896 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
897 return;
898 hp->h_addrtype = AF_INET6;
899 hp->h_length = IN6ADDRSZ;
900 for (ap = hp->h_addr_list; *ap; ap++) {
901 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
902
903 if (*lenp < (i + IN6ADDRSZ)) {
904 /* Out of memory. Truncate address list here. XXX */
905 *ap = NULL;
906 return;
907 }
908 *bpp += i;
909 *lenp -= i;
910 map_v4v6_address(*ap, *bpp);
911 *ap = *bpp;
912 *bpp += IN6ADDRSZ;
913 *lenp -= IN6ADDRSZ;
914 }
915 }
916
917 #ifdef RESOLVSORT
918 static void
919 addrsort(ap, num)
920 char **ap;
921 int num;
922 {
923 int i, j;
924 char **p;
925 short aval[MAXADDRS];
926 int needsort = 0;
927
928 p = ap;
929 for (i = 0; i < num; i++, p++) {
930 for (j = 0 ; (unsigned)j < _res.nsort; j++)
931 if (_res.sort_list[j].addr.s_addr ==
932 (((struct in_addr *)(void *)(*p))->s_addr & _res.sort_list[j].mask))
933 break;
934 aval[i] = j;
935 if (needsort == 0 && i > 0 && j < aval[i-1])
936 needsort = i;
937 }
938 if (!needsort)
939 return;
940
941 while (needsort < num) {
942 for (j = needsort - 1; j >= 0; j--) {
943 if (aval[j] > aval[j+1]) {
944 char *hp;
945
946 i = aval[j];
947 aval[j] = aval[j+1];
948 aval[j+1] = i;
949
950 hp = ap[j];
951 ap[j] = ap[j+1];
952 ap[j+1] = hp;
953
954 } else
955 break;
956 }
957 needsort++;
958 }
959 }
960 #endif
961
962 #if defined(BSD43_BSD43_NFS) || defined(sun)
963 /* some libc's out there are bound internally to these names (UMIPS) */
964 void
965 ht_sethostent(stayopen)
966 int stayopen;
967 {
968 _sethtent(stayopen);
969 }
970
971 void
972 ht_endhostent()
973 {
974 _endhtent();
975 }
976
977 struct hostent *
978 ht_gethostbyname(name)
979 char *name;
980 {
981 return (_gethtbyname(name));
982 }
983
984 struct hostent *
985 ht_gethostbyaddr(addr, len, af)
986 const char *addr;
987 int len, af;
988 {
989 return (_gethtbyaddr(addr, len, af));
990 }
991
992 struct hostent *
993 gethostent()
994 {
995 return (_gethtent());
996 }
997
998 void
999 dns_service()
1000 {
1001 return;
1002 }
1003
1004 #undef dn_skipname
1005 dn_skipname(comp_dn, eom)
1006 const u_char *comp_dn, *eom;
1007 {
1008 return (__dn_skipname(comp_dn, eom));
1009 }
1010 #endif /*old-style libc with yp junk in it*/
1011
1012 #ifdef YP
1013 struct hostent *
1014 _yphostent(line)
1015 char *line;
1016 {
1017 static struct in_addr host_addrs[MAXADDRS];
1018 char *p = line;
1019 char *cp, **q;
1020 char **hap;
1021 struct in_addr *buf;
1022 int more;
1023
1024 host.h_name = NULL;
1025 host.h_addr_list = h_addr_ptrs;
1026 host.h_length = sizeof(u_int32_t);
1027 host.h_addrtype = AF_INET;
1028 hap = h_addr_ptrs;
1029 buf = host_addrs;
1030 q = host.h_aliases = host_aliases;
1031
1032 nextline:
1033 more = 0;
1034 cp = strpbrk(p, " \t");
1035 if (cp == NULL) {
1036 if (host.h_name == NULL)
1037 return (NULL);
1038 else
1039 goto done;
1040 }
1041 *cp++ = '\0';
1042
1043 *hap++ = (char *)(void *)buf;
1044 (void) inet_aton(p, buf++);
1045
1046 while (*cp == ' ' || *cp == '\t')
1047 cp++;
1048 p = cp;
1049 cp = strpbrk(p, " \t\n");
1050 if (cp != NULL) {
1051 if (*cp == '\n')
1052 more = 1;
1053 *cp++ = '\0';
1054 }
1055 if (!host.h_name)
1056 host.h_name = p;
1057 else if (strcmp(host.h_name, p)==0)
1058 ;
1059 else if (q < &host_aliases[MAXALIASES - 1])
1060 *q++ = p;
1061 p = cp;
1062 if (more)
1063 goto nextline;
1064
1065 while (cp && *cp) {
1066 if (*cp == ' ' || *cp == '\t') {
1067 cp++;
1068 continue;
1069 }
1070 if (*cp == '\n') {
1071 cp++;
1072 goto nextline;
1073 }
1074 if (q < &host_aliases[MAXALIASES - 1])
1075 *q++ = cp;
1076 cp = strpbrk(cp, " \t");
1077 if (cp != NULL)
1078 *cp++ = '\0';
1079 }
1080 done:
1081 *q = NULL;
1082 *hap = NULL;
1083 return (&host);
1084 }
1085
1086 /* ARGSUSED */
1087 struct hostent *
1088 _yp_gethtbyaddr(addr, len, type)
1089 const char *addr;
1090 int len, type;
1091 {
1092 struct hostent *hp = (struct hostent *)NULL;
1093 static char *__ypcurrent;
1094 int __ypcurrentlen, r;
1095 char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1096
1097 if (!__ypdomain) {
1098 if (_yp_check(&__ypdomain) == 0)
1099 return (hp);
1100 }
1101 (void)snprintf(name, sizeof name, "%u.%u.%u.%u",
1102 ((unsigned)addr[0] & 0xff),
1103 ((unsigned)addr[1] & 0xff),
1104 ((unsigned)addr[2] & 0xff),
1105 ((unsigned)addr[3] & 0xff));
1106 if (__ypcurrent)
1107 free(__ypcurrent);
1108 __ypcurrent = NULL;
1109 r = yp_match(__ypdomain, "hosts.byaddr", name,
1110 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1111 if (r==0)
1112 hp = _yphostent(__ypcurrent);
1113 if (hp==NULL)
1114 h_errno = HOST_NOT_FOUND;
1115 return (hp);
1116 }
1117
1118 struct hostent *
1119 _yp_gethtbyname(name)
1120 const char *name;
1121 {
1122 struct hostent *hp = (struct hostent *)NULL;
1123 static char *__ypcurrent;
1124 int __ypcurrentlen, r;
1125
1126 if (!__ypdomain) {
1127 if (_yp_check(&__ypdomain) == 0)
1128 return (hp);
1129 }
1130 if (__ypcurrent)
1131 free(__ypcurrent);
1132 __ypcurrent = NULL;
1133 r = yp_match(__ypdomain, "hosts.byname", name,
1134 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1135 if (r==0)
1136 hp = _yphostent(__ypcurrent);
1137 if (hp==NULL)
1138 h_errno = HOST_NOT_FOUND;
1139 return (hp);
1140 }
1141 #endif
1142