summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/gethostnamadr.c
diff options
context:
space:
mode:
authorcvs2svn <admin@example.com>1999-03-26 18:24:03 +0000
committercvs2svn <admin@example.com>1999-03-26 18:24:03 +0000
commit3fc228fb4c1a39aceaee3d7013365042a6077bd0 (patch)
treeaf769f6648929b3b2c1f9e053a3754fa989ce302 /src/lib/libc/net/gethostnamadr.c
parent536c76cbb863bab152f19842ab88772c01e922c7 (diff)
downloadopenbsd-OPENBSD_2_5.tar.gz
openbsd-OPENBSD_2_5.tar.bz2
openbsd-OPENBSD_2_5.zip
This commit was manufactured by cvs2git to create branch 'OPENBSD_2_5'.OPENBSD_2_5
Diffstat (limited to 'src/lib/libc/net/gethostnamadr.c')
-rw-r--r--src/lib/libc/net/gethostnamadr.c1147
1 files changed, 1147 insertions, 0 deletions
diff --git a/src/lib/libc/net/gethostnamadr.c b/src/lib/libc/net/gethostnamadr.c
new file mode 100644
index 0000000000..6ff456fb0c
--- /dev/null
+++ b/src/lib/libc/net/gethostnamadr.c
@@ -0,0 +1,1147 @@
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)
55static char rcsid[] = "$OpenBSD: gethostnamadr.c,v 1.31 1998/11/20 11:18:44 d Exp $";
56#endif /* LIBC_SCCS and not lint */
57
58#include <sys/param.h>
59#include <sys/socket.h>
60#include <netinet/in.h>
61#include <arpa/inet.h>
62#include <arpa/nameser.h>
63#include <netdb.h>
64#include <resolv.h>
65#include <stdio.h>
66#include <ctype.h>
67#include <errno.h>
68#include <string.h>
69#include <syslog.h>
70#include <stdlib.h>
71#ifdef YP
72#include <rpc/rpc.h>
73#include <rpcsvc/yp.h>
74#include <rpcsvc/ypclnt.h>
75#include "ypinternal.h"
76#endif
77#include "thread_private.h"
78
79#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
80
81#define MAXALIASES 35
82#define MAXADDRS 35
83
84static char *h_addr_ptrs[MAXADDRS + 1];
85
86#ifdef YP
87static char *__ypdomain;
88#endif
89
90static struct hostent host;
91static char *host_aliases[MAXALIASES];
92static char hostbuf[BUFSIZ+1];
93static union {
94 struct in_addr _host_in_addr;
95 u_char _host_addr[16]; /* IPv4 or IPv6 */
96} _host_addr_u;
97#define host_addr _host_addr_u._host_addr
98static FILE *hostf = NULL;
99static int stayopen = 0;
100
101static void map_v4v6_address __P((const char *src, char *dst));
102static void map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
103
104#ifdef RESOLVSORT
105static void addrsort __P((char **, int));
106#endif
107
108int _hokchar __P((const char *));
109
110static const char AskedForGot[] =
111 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
112
113#if PACKETSZ > 1024
114#define MAXPACKET PACKETSZ
115#else
116#define MAXPACKET 1024
117#endif
118
119typedef union {
120 HEADER hdr;
121 u_char buf[MAXPACKET];
122} querybuf;
123
124typedef union {
125 int32_t al;
126 char ac;
127} align;
128
129static struct hostent *getanswer __P((const querybuf *, int, const char *,
130 int));
131
132extern int h_errno;
133
134int
135_hokchar(p)
136 const char *p;
137{
138 char c;
139
140 /*
141 * Many people do not obey RFC 822 and 1035. The valid
142 * characters are a-z, A-Z, 0-9, '-' and . But the others
143 * tested for below can happen, and we must be more permissive
144 * than the resolver until those idiots clean up their act.
145 * We let '/' through, but not '..'
146 */
147 while ((c = *p++)) {
148 if (('a' <= c && c <= 'z') ||
149 ('A' <= c && c <= 'Z') ||
150 ('0' <= c && c <= '9'))
151 continue;
152 if (strchr("-_/", c))
153 continue;
154 if (c == '.' && *p != '.')
155 continue;
156 return 0;
157 }
158 return 1;
159}
160
161static struct hostent *
162getanswer(answer, anslen, qname, qtype)
163 const querybuf *answer;
164 int anslen;
165 const char *qname;
166 int qtype;
167{
168 register const HEADER *hp;
169 register const u_char *cp;
170 register int n;
171 const u_char *eom;
172 char *bp, **ap, **hap;
173 int type, class, buflen, ancount, qdcount;
174 int haveanswer, had_error;
175 int toobig = 0;
176 char tbuf[MAXDNAME];
177 const char *tname;
178 int (*name_ok) __P((const char *));
179
180 tname = qname;
181 host.h_name = NULL;
182 eom = answer->buf + anslen;
183 switch (qtype) {
184 case T_A:
185 case T_AAAA:
186#ifdef USE_RESOLV_NAME_OK
187 name_ok = res_hnok;
188 break;
189#endif
190 case T_PTR:
191#ifdef USE_RESOLV_NAME_OK
192 name_ok = res_dnok;
193#else
194 name_ok = _hokchar;
195#endif
196 break;
197 default:
198 return (NULL);
199 }
200 /*
201 * find first satisfactory answer
202 */
203 hp = &answer->hdr;
204 ancount = ntohs(hp->ancount);
205 qdcount = ntohs(hp->qdcount);
206 bp = hostbuf;
207 buflen = sizeof hostbuf;
208 cp = answer->buf + HFIXEDSZ;
209 if (qdcount != 1) {
210 h_errno = NO_RECOVERY;
211 return (NULL);
212 }
213 n = dn_expand(answer->buf, eom, cp, bp, buflen);
214 if ((n < 0) || !(*name_ok)(bp)) {
215 h_errno = NO_RECOVERY;
216 return (NULL);
217 }
218 cp += n + QFIXEDSZ;
219 if (qtype == T_A || qtype == T_AAAA) {
220 /* res_send() has already verified that the query name is the
221 * same as the one we sent; this just gets the expanded name
222 * (i.e., with the succeeding search-domain tacked on).
223 */
224 n = strlen(bp) + 1; /* for the \0 */
225 host.h_name = bp;
226 bp += n;
227 buflen -= n;
228 /* The qname can be abbreviated, but h_name is now absolute. */
229 qname = host.h_name;
230 }
231 ap = host_aliases;
232 *ap = NULL;
233 host.h_aliases = host_aliases;
234 hap = h_addr_ptrs;
235 *hap = NULL;
236 host.h_addr_list = h_addr_ptrs;
237 haveanswer = 0;
238 had_error = 0;
239 while (ancount-- > 0 && cp < eom && !had_error) {
240 n = dn_expand(answer->buf, eom, cp, bp, buflen);
241 if ((n < 0) || !(*name_ok)(bp)) {
242 had_error++;
243 continue;
244 }
245 cp += n; /* name */
246 type = _getshort(cp);
247 cp += INT16SZ; /* type */
248 class = _getshort(cp);
249 cp += INT16SZ + INT32SZ; /* class, TTL */
250 n = _getshort(cp);
251 cp += INT16SZ; /* len */
252 if (class != C_IN) {
253 /* XXX - debug? syslog? */
254 cp += n;
255 continue; /* XXX - had_error++ ? */
256 }
257 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
258 if (ap >= &host_aliases[MAXALIASES-1])
259 continue;
260 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
261 if ((n < 0) || !(*name_ok)(tbuf)) {
262 had_error++;
263 continue;
264 }
265 cp += n;
266 /* Store alias. */
267 *ap++ = bp;
268 n = strlen(bp) + 1; /* for the \0 */
269 bp += n;
270 buflen -= n;
271 /* Get canonical name. */
272 n = strlen(tbuf) + 1; /* for the \0 */
273 if (n > buflen) {
274 had_error++;
275 continue;
276 }
277 strcpy(bp, tbuf);
278 host.h_name = bp;
279 bp += n;
280 buflen -= n;
281 continue;
282 }
283 if (qtype == T_PTR && type == T_CNAME) {
284 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
285 if ((n < 0) || !res_hnok(tbuf)) {
286 had_error++;
287 continue;
288 }
289 cp += n;
290 /* Get canonical name. */
291 n = strlen(tbuf) + 1; /* for the \0 */
292 if (n > buflen) {
293 had_error++;
294 continue;
295 }
296 strcpy(bp, tbuf);
297 tname = bp;
298 bp += n;
299 buflen -= n;
300 continue;
301 }
302 if (type != qtype) {
303 syslog(LOG_NOTICE|LOG_AUTH,
304 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
305 qname, p_class(C_IN), p_type(qtype),
306 p_type(type));
307 cp += n;
308 continue; /* XXX - had_error++ ? */
309 }
310 switch (type) {
311 case T_PTR:
312 if (strcasecmp(tname, bp) != 0) {
313 syslog(LOG_NOTICE|LOG_AUTH,
314 AskedForGot, qname, bp);
315 cp += n;
316 continue; /* XXX - had_error++ ? */
317 }
318 n = dn_expand(answer->buf, eom, cp, bp, buflen);
319 if ((n < 0) || !res_hnok(bp)) {
320 had_error++;
321 break;
322 }
323#if MULTI_PTRS_ARE_ALIASES
324 cp += n;
325 if (!haveanswer)
326 host.h_name = bp;
327 else if (ap < &host_aliases[MAXALIASES-1])
328 *ap++ = bp;
329 else
330 n = -1;
331 if (n != -1) {
332 n = strlen(bp) + 1; /* for the \0 */
333 bp += n;
334 buflen -= n;
335 }
336 break;
337#else
338 host.h_name = bp;
339 if (_res.options & RES_USE_INET6) {
340 n = strlen(bp) + 1; /* for the \0 */
341 bp += n;
342 buflen -= n;
343 map_v4v6_hostent(&host, &bp, &buflen);
344 }
345 h_errno = NETDB_SUCCESS;
346 return (&host);
347#endif
348 case T_A:
349 case T_AAAA:
350 if (strcasecmp(host.h_name, bp) != 0) {
351 syslog(LOG_NOTICE|LOG_AUTH,
352 AskedForGot, host.h_name, bp);
353 cp += n;
354 continue; /* XXX - had_error++ ? */
355 }
356 if (n != host.h_length) {
357 cp += n;
358 continue;
359 }
360 if (!haveanswer) {
361 register int nn;
362
363 host.h_name = bp;
364 nn = strlen(bp) + 1; /* for the \0 */
365 bp += nn;
366 buflen -= nn;
367 }
368
369 bp += sizeof(align) - ((u_long)bp % sizeof(align));
370
371 if (bp + n >= &hostbuf[sizeof hostbuf]) {
372#ifdef DEBUG
373 if (_res.options & RES_DEBUG)
374 printf("size (%d) too big\n", n);
375#endif
376 had_error++;
377 continue;
378 }
379 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
380 if (!toobig++)
381#ifdef DEBUG
382 if (_res.options & RES_DEBUG)
383 printf("Too many addresses (%d)\n", MAXADDRS);
384#endif
385 cp += n;
386 continue;
387 }
388 bcopy(cp, *hap++ = bp, n);
389 bp += n;
390 buflen -= n;
391 cp += n;
392 break;
393 }
394 if (!had_error)
395 haveanswer++;
396 }
397 if (haveanswer) {
398 *ap = NULL;
399 *hap = NULL;
400# if defined(RESOLVSORT)
401 /*
402 * Note: we sort even if host can take only one address
403 * in its return structures - should give it the "best"
404 * address in that case, not some random one
405 */
406 if (_res.nsort && haveanswer > 1 && qtype == T_A)
407 addrsort(h_addr_ptrs, haveanswer);
408# endif /*RESOLVSORT*/
409 if (!host.h_name) {
410 n = strlen(qname) + 1; /* for the \0 */
411 if (n > buflen)
412 goto try_again;
413 strcpy(bp, qname);
414 host.h_name = bp;
415 bp += n;
416 buflen -= n;
417 }
418 if (_res.options & RES_USE_INET6)
419 map_v4v6_hostent(&host, &bp, &buflen);
420 h_errno = NETDB_SUCCESS;
421 return (&host);
422 }
423 try_again:
424 h_errno = TRY_AGAIN;
425 return (NULL);
426}
427
428#ifndef notyet
429/*
430 * XXX This is an extremely bogus implementations.
431 *
432 * FreeBSD has this interface:
433 * int gethostbyaddr_r(const char *addr, int len, int type,
434 * struct hostent *result, struct hostent_data *buffer)
435 */
436
437struct hostent *
438gethostbyname_r(name, hp, buf, buflen, errorp)
439 const char * name;
440 struct hostent * hp;
441 char * buf;
442 int buflen;
443 int * errorp;
444{
445 struct hostent *res;
446
447 res = gethostbyname(name);
448 *errorp = h_errno;
449 if (res == NULL)
450 return NULL;
451 memcpy(hp, res, sizeof *hp); /* XXX not sufficient */
452 return hp;
453}
454
455/*
456 * XXX This is an extremely bogus implementations.
457 */
458struct hostent *
459gethostbyaddr_r(addr, len, af, he, buf, buflen, errorp)
460 const char *addr; /* XXX should have been def'd as u_char! */
461 int len, af;
462 struct hostent * he;
463 char * buf;
464 int buflen;
465 int * errorp;
466{
467 struct hostent * res;
468
469 res = gethostbyaddr(addr, len, af);
470 *errorp = h_errno;
471 if (res == NULL)
472 return NULL;
473 memcpy(he, res, sizeof *he); /* XXX not sufficient */
474 return he;
475}
476
477/* XXX RFC2133 expects a gethostbyname2_r() -- unimplemented */
478#endif
479
480_THREAD_PRIVATE_MUTEX(gethostnamadr)
481
482struct hostent *
483gethostbyname(name)
484 const char *name;
485{
486 struct hostent *hp;
487 extern struct hostent *_gethtbyname2();
488
489 _THREAD_PRIVATE_MUTEX_LOCK(gethostnamadr);
490 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
491 hp = _gethtbyname2(name, AF_INET);
492
493 else if (_res.options & RES_USE_INET6) {
494 hp = gethostbyname2(name, AF_INET6);
495 if (hp == NULL)
496 hp = gethostbyname2(name, AF_INET);
497 }
498 else
499 hp = gethostbyname2(name, AF_INET);
500 _THREAD_PRIVATE_MUTEX_UNLOCK(gethostnamadr);
501 return hp;
502}
503
504struct hostent *
505gethostbyname2(name, af)
506 const char *name;
507 int af;
508{
509 querybuf buf;
510 register const char *cp;
511 char *bp;
512 int n, size, type, len, i;
513 extern struct hostent *_gethtbyname2(), *_yp_gethtbyname();
514 register struct hostent *hp;
515 char lookups[MAXDNSLUS];
516
517 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
518 return (_gethtbyname2(name, af));
519
520 switch (af) {
521 case AF_INET:
522 size = INADDRSZ;
523 type = T_A;
524 break;
525 case AF_INET6:
526 size = IN6ADDRSZ;
527 type = T_AAAA;
528 break;
529 default:
530 h_errno = NETDB_INTERNAL;
531 errno = EAFNOSUPPORT;
532 return (NULL);
533 }
534
535 host.h_addrtype = af;
536 host.h_length = size;
537
538 /*
539 * if there aren't any dots, it could be a user-level alias.
540 * this is also done in res_query() since we are not the only
541 * function that looks up host names.
542 */
543 if (!strchr(name, '.') && (cp = __hostalias(name)))
544 name = cp;
545
546 /*
547 * disallow names consisting only of digits/dots, unless
548 * they end in a dot.
549 */
550 if (isdigit(name[0]))
551 for (cp = name;; ++cp) {
552 if (!*cp) {
553 if (*--cp == '.')
554 break;
555 /*
556 * All-numeric, no dot at the end.
557 * Fake up a hostent as if we'd actually
558 * done a lookup.
559 */
560 if (inet_pton(af, name, host_addr) <= 0) {
561 h_errno = HOST_NOT_FOUND;
562 return (NULL);
563 }
564 strncpy(hostbuf, name, MAXHOSTNAMELEN-1);
565 hostbuf[MAXHOSTNAMELEN-1] = '\0';
566 bp = hostbuf + MAXHOSTNAMELEN;
567 len = sizeof hostbuf - MAXHOSTNAMELEN;
568 host.h_name = hostbuf;
569 host.h_aliases = host_aliases;
570 host_aliases[0] = NULL;
571 h_addr_ptrs[0] = (char *)host_addr;
572 h_addr_ptrs[1] = NULL;
573 host.h_addr_list = h_addr_ptrs;
574 if (_res.options & RES_USE_INET6)
575 map_v4v6_hostent(&host, &bp, &len);
576 h_errno = NETDB_SUCCESS;
577 return (&host);
578 }
579 if (!isdigit(*cp) && *cp != '.')
580 break;
581 }
582 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
583 name[0] == ':')
584 for (cp = name;; ++cp) {
585 if (!*cp) {
586 if (*--cp == '.')
587 break;
588 /*
589 * All-IPv6-legal, no dot at the end.
590 * Fake up a hostent as if we'd actually
591 * done a lookup.
592 */
593 if (inet_pton(af, name, host_addr) <= 0) {
594 h_errno = HOST_NOT_FOUND;
595 return (NULL);
596 }
597 strncpy(hostbuf, name, MAXHOSTNAMELEN-1);
598 hostbuf[MAXHOSTNAMELEN-1] = '\0';
599 bp = hostbuf + MAXHOSTNAMELEN;
600 len = sizeof hostbuf - MAXHOSTNAMELEN;
601 host.h_name = hostbuf;
602 host.h_aliases = host_aliases;
603 host_aliases[0] = NULL;
604 h_addr_ptrs[0] = (char *)host_addr;
605 h_addr_ptrs[1] = NULL;
606 host.h_addr_list = h_addr_ptrs;
607 h_errno = NETDB_SUCCESS;
608 return (&host);
609 }
610 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
611 break;
612 }
613
614 bcopy(_res.lookups, lookups, sizeof lookups);
615 if (lookups[0] == '\0')
616 strncpy(lookups, "bf", sizeof lookups);
617
618 hp = (struct hostent *)NULL;
619 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
620 switch (lookups[i]) {
621#ifdef YP
622 case 'y':
623 /* YP only supports AF_INET. */
624 if (af == AF_INET)
625 hp = _yp_gethtbyname(name);
626 break;
627#endif
628 case 'b':
629 if ((n = res_search(name, C_IN, type, buf.buf,
630 sizeof(buf))) < 0) {
631#ifdef DEBUG
632 if (_res.options & RES_DEBUG)
633 printf("res_search failed\n");
634#endif
635 break;
636 }
637 hp = getanswer(&buf, n, name, type);
638 break;
639 case 'f':
640 hp = _gethtbyname2(name, af);
641 break;
642 }
643 }
644 /* XXX h_errno not correct in all cases... */
645 return (hp);
646}
647
648struct hostent *
649gethostbyaddr(addr, len, af)
650 const char *addr; /* XXX should have been def'd as u_char! */
651 int len, af;
652{
653 const u_char *uaddr = (const u_char *)addr;
654 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
655 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
656 int n, size, i;
657 querybuf buf;
658 register struct hostent *hp;
659 char qbuf[MAXDNAME+1], *qp;
660 extern struct hostent *_gethtbyaddr(), *_yp_gethtbyaddr();
661 char lookups[MAXDNSLUS];
662 struct hostent *res;
663
664 _THREAD_PRIVATE_MUTEX_LOCK(gethostnamadr);
665 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
666 res = _gethtbyaddr(addr, len, af);
667 _THREAD_PRIVATE_MUTEX_UNLOCK(gethostnamadr);
668 return (res);
669 }
670
671 if (af == AF_INET6 && len == IN6ADDRSZ &&
672 (!bcmp(uaddr, mapped, sizeof mapped) ||
673 !bcmp(uaddr, tunnelled, sizeof tunnelled))) {
674 /* Unmap. */
675 addr += sizeof mapped;
676 uaddr += sizeof mapped;
677 af = AF_INET;
678 len = INADDRSZ;
679 }
680 switch (af) {
681 case AF_INET:
682 size = INADDRSZ;
683 break;
684 case AF_INET6:
685 size = IN6ADDRSZ;
686 break;
687 default:
688 errno = EAFNOSUPPORT;
689 h_errno = NETDB_INTERNAL;
690 _THREAD_PRIVATE_MUTEX_UNLOCK(gethostnamadr);
691 return (NULL);
692 }
693 if (size != len) {
694 errno = EINVAL;
695 h_errno = NETDB_INTERNAL;
696 _THREAD_PRIVATE_MUTEX_UNLOCK(gethostnamadr);
697 return (NULL);
698 }
699 switch (af) {
700 case AF_INET:
701 (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
702 (uaddr[3] & 0xff),
703 (uaddr[2] & 0xff),
704 (uaddr[1] & 0xff),
705 (uaddr[0] & 0xff));
706 break;
707 case AF_INET6:
708 qp = qbuf;
709 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
710 qp += sprintf(qp, "%x.%x.",
711 uaddr[n] & 0xf,
712 (uaddr[n] >> 4) & 0xf);
713 }
714 strcpy(qp, "ip6.int");
715 break;
716 }
717
718 bcopy(_res.lookups, lookups, sizeof lookups);
719 if (lookups[0] == '\0')
720 strncpy(lookups, "bf", sizeof lookups);
721
722 hp = (struct hostent *)NULL;
723 for (i = 0; i < MAXDNSLUS && hp == NULL && lookups[i]; i++) {
724 switch (lookups[i]) {
725#ifdef YP
726 case 'y':
727 /* YP only supports AF_INET. */
728 if (af == AF_INET)
729 hp = _yp_gethtbyaddr(addr);
730 break;
731#endif
732 case 'b':
733 n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf,
734 sizeof buf.buf);
735 if (n < 0) {
736#ifdef DEBUG
737 if (_res.options & RES_DEBUG)
738 printf("res_query failed\n");
739#endif
740 break;
741 }
742 if (!(hp = getanswer(&buf, n, qbuf, T_PTR)))
743 break;
744 hp->h_addrtype = af;
745 hp->h_length = len;
746 bcopy(addr, host_addr, len);
747 h_addr_ptrs[0] = (char *)host_addr;
748 h_addr_ptrs[1] = NULL;
749 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
750 map_v4v6_address((char*)host_addr,
751 (char*)host_addr);
752 hp->h_addrtype = AF_INET6;
753 hp->h_length = IN6ADDRSZ;
754 }
755 h_errno = NETDB_SUCCESS;
756 break;
757 case 'f':
758 hp = _gethtbyaddr(addr, len, af);
759 break;
760 }
761 }
762 _THREAD_PRIVATE_MUTEX_UNLOCK(gethostnamadr);
763 /* XXX h_errno not correct in all cases... */
764 return (hp);
765}
766
767void
768_sethtent(f)
769 int f;
770{
771 if (hostf == NULL)
772 hostf = fopen(_PATH_HOSTS, "r" );
773 else
774 rewind(hostf);
775 stayopen = f;
776}
777
778void
779_endhtent()
780{
781 if (hostf && !stayopen) {
782 (void) fclose(hostf);
783 hostf = NULL;
784 }
785}
786
787struct hostent *
788_gethtent()
789{
790 char *p;
791 register char *cp, **q;
792 int af;
793 size_t len;
794
795 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
796 h_errno = NETDB_INTERNAL;
797 return (NULL);
798 }
799 again:
800 if ((p = fgetln(hostf, &len)) == NULL) {
801 h_errno = HOST_NOT_FOUND;
802 return (NULL);
803 }
804 if (p[len-1] == '\n')
805 len--;
806 if (len >= sizeof(hostbuf) || len == 0)
807 goto again;
808 p = memcpy(hostbuf, p, len);
809 hostbuf[len] = '\0';
810 if (*p == '#')
811 goto again;
812 if ((cp = strchr(p, '#')))
813 *cp = '\0';
814 if (!(cp = strpbrk(p, " \t")))
815 goto again;
816 *cp++ = '\0';
817 if ((_res.options & RES_USE_INET6) &&
818 inet_pton(AF_INET6, p, host_addr) > 0) {
819 af = AF_INET6;
820 len = IN6ADDRSZ;
821 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
822 if (_res.options & RES_USE_INET6) {
823 map_v4v6_address((char*)host_addr, (char*)host_addr);
824 af = AF_INET6;
825 len = IN6ADDRSZ;
826 } else {
827 af = AF_INET;
828 len = INADDRSZ;
829 }
830 } else {
831 goto again;
832 }
833 h_addr_ptrs[0] = (char *)host_addr;
834 h_addr_ptrs[1] = NULL;
835 host.h_addr_list = h_addr_ptrs;
836 host.h_length = len;
837 host.h_addrtype = af;
838 while (*cp == ' ' || *cp == '\t')
839 cp++;
840 host.h_name = cp;
841 q = host.h_aliases = host_aliases;
842 if ((cp = strpbrk(cp, " \t")))
843 *cp++ = '\0';
844 while (cp && *cp) {
845 if (*cp == ' ' || *cp == '\t') {
846 cp++;
847 continue;
848 }
849 if (q < &host_aliases[MAXALIASES - 1])
850 *q++ = cp;
851 if ((cp = strpbrk(cp, " \t")))
852 *cp++ = '\0';
853 }
854 *q = NULL;
855 if (_res.options & RES_USE_INET6) {
856 char *bp = hostbuf;
857 int buflen = sizeof hostbuf;
858
859 map_v4v6_hostent(&host, &bp, &buflen);
860 }
861 h_errno = NETDB_SUCCESS;
862 return (&host);
863}
864
865struct hostent *
866_gethtbyname(name)
867 const char *name;
868{
869 extern struct hostent *_gethtbyname2();
870 struct hostent *hp;
871
872 if (_res.options & RES_USE_INET6) {
873 hp = _gethtbyname2(name, AF_INET6);
874 if (hp)
875 return (hp);
876 }
877 return (_gethtbyname2(name, AF_INET));
878}
879
880struct hostent *
881_gethtbyname2(name, af)
882 const char *name;
883 int af;
884{
885 register struct hostent *p;
886 register char **cp;
887
888 _sethtent(0);
889 while ((p = _gethtent())) {
890 if (p->h_addrtype != af)
891 continue;
892 if (strcasecmp(p->h_name, name) == 0)
893 break;
894 for (cp = p->h_aliases; *cp != 0; cp++)
895 if (strcasecmp(*cp, name) == 0)
896 goto found;
897 }
898 found:
899 _endhtent();
900 return (p);
901}
902
903struct hostent *
904_gethtbyaddr(addr, len, af)
905 const char *addr;
906 int len, af;
907{
908 register struct hostent *p;
909
910 _sethtent(0);
911 while ((p = _gethtent()))
912 if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
913 break;
914 _endhtent();
915 return (p);
916}
917
918#ifdef YP
919struct hostent *
920_yphostent(line)
921 char *line;
922{
923 static struct in_addr host_addrs[MAXADDRS];
924 char *p = line;
925 char *cp, **q;
926 char **hap;
927 struct in_addr *buf;
928 int more;
929
930 host.h_name = NULL;
931 host.h_addr_list = h_addr_ptrs;
932 host.h_length = INADDRSZ;
933 host.h_addrtype = AF_INET;
934 hap = h_addr_ptrs;
935 buf = host_addrs;
936 q = host.h_aliases = host_aliases;
937
938nextline:
939 more = 0;
940 cp = strpbrk(p, " \t");
941 if (cp == NULL) {
942 if (host.h_name == NULL)
943 return (NULL);
944 else
945 goto done;
946 }
947 *cp++ = '\0';
948
949 *hap++ = (char *)buf;
950 (void) inet_aton(p, buf++);
951
952 while (*cp == ' ' || *cp == '\t')
953 cp++;
954 p = cp;
955 cp = strpbrk(p, " \t\n");
956 if (cp != NULL) {
957 if (*cp == '\n')
958 more = 1;
959 *cp++ = '\0';
960 }
961 if (!host.h_name)
962 host.h_name = p;
963 else if (strcmp(host.h_name, p)==0)
964 ;
965 else if (q < &host_aliases[MAXALIASES - 1])
966 *q++ = p;
967 p = cp;
968 if (more)
969 goto nextline;
970
971 while (cp && *cp) {
972 if (*cp == ' ' || *cp == '\t') {
973 cp++;
974 continue;
975 }
976 if (*cp == '\n') {
977 cp++;
978 goto nextline;
979 }
980 if (q < &host_aliases[MAXALIASES - 1])
981 *q++ = cp;
982 cp = strpbrk(cp, " \t");
983 if (cp != NULL)
984 *cp++ = '\0';
985 }
986done:
987 *q = NULL;
988 *hap = NULL;
989 return (&host);
990}
991
992struct hostent *
993_yp_gethtbyaddr(addr)
994 const char *addr;
995{
996 struct hostent *hp = (struct hostent *)NULL;
997 static char *__ypcurrent;
998 int __ypcurrentlen, r;
999 char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1000
1001 if (!__ypdomain) {
1002 if (_yp_check(&__ypdomain) == 0)
1003 return (hp);
1004 }
1005 sprintf(name, "%u.%u.%u.%u",
1006 ((unsigned)addr[0] & 0xff),
1007 ((unsigned)addr[1] & 0xff),
1008 ((unsigned)addr[2] & 0xff),
1009 ((unsigned)addr[3] & 0xff));
1010 if (__ypcurrent)
1011 free(__ypcurrent);
1012 __ypcurrent = NULL;
1013 r = yp_match(__ypdomain, "hosts.byaddr", name,
1014 strlen(name), &__ypcurrent, &__ypcurrentlen);
1015 if (r==0)
1016 hp = _yphostent(__ypcurrent);
1017 if (hp==NULL)
1018 h_errno = HOST_NOT_FOUND;
1019 return (hp);
1020}
1021
1022struct hostent *
1023_yp_gethtbyname(name)
1024 const char *name;
1025{
1026 struct hostent *hp = (struct hostent *)NULL;
1027 static char *__ypcurrent;
1028 int __ypcurrentlen, r;
1029
1030 if (strlen(name) >= MAXHOSTNAMELEN)
1031 return (NULL);
1032 if (!__ypdomain) {
1033 if (_yp_check(&__ypdomain) == 0)
1034 return (hp);
1035 }
1036 if (__ypcurrent)
1037 free(__ypcurrent);
1038 __ypcurrent = NULL;
1039 r = yp_match(__ypdomain, "hosts.byname", name,
1040 strlen(name), &__ypcurrent, &__ypcurrentlen);
1041 if (r == 0)
1042 hp = _yphostent(__ypcurrent);
1043 if (hp == NULL)
1044 h_errno = HOST_NOT_FOUND;
1045 return (hp);
1046}
1047#endif
1048
1049static void
1050map_v4v6_address(src, dst)
1051 const char *src;
1052 char *dst;
1053{
1054 u_char *p = (u_char *)dst;
1055 char tmp[INADDRSZ];
1056 int i;
1057
1058 /* Stash a temporary copy so our caller can update in place. */
1059 bcopy(src, tmp, INADDRSZ);
1060 /* Mark this ipv6 addr as a mapped ipv4. */
1061 for (i = 0; i < 10; i++)
1062 *p++ = 0x00;
1063 *p++ = 0xff;
1064 *p++ = 0xff;
1065 /* Retrieve the saved copy and we're done. */
1066 bcopy(tmp, (void*)p, INADDRSZ);
1067}
1068
1069static void
1070map_v4v6_hostent(hp, bpp, lenp)
1071 struct hostent *hp;
1072 char **bpp;
1073 int *lenp;
1074{
1075 char **ap;
1076
1077 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1078 return;
1079 hp->h_addrtype = AF_INET6;
1080 hp->h_length = IN6ADDRSZ;
1081 for (ap = hp->h_addr_list; *ap; ap++) {
1082 int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
1083
1084 if (*lenp < (i + IN6ADDRSZ)) {
1085 /* Out of memory. Truncate address list here. XXX */
1086 *ap = NULL;
1087 return;
1088 }
1089 *bpp += i;
1090 *lenp -= i;
1091 map_v4v6_address(*ap, *bpp);
1092 *ap = *bpp;
1093 *bpp += IN6ADDRSZ;
1094 *lenp -= IN6ADDRSZ;
1095 }
1096}
1097
1098struct hostent *
1099gethostent()
1100{
1101 return (_gethtent());
1102}
1103
1104#ifdef RESOLVSORT
1105static void
1106addrsort(ap, num)
1107 char **ap;
1108 int num;
1109{
1110 int i, j;
1111 char **p;
1112 short aval[MAXADDRS];
1113 int needsort = 0;
1114
1115 p = ap;
1116 for (i = 0; i < num; i++, p++) {
1117 for (j = 0 ; (unsigned)j < _res.nsort; j++)
1118 if (_res.sort_list[j].addr.s_addr ==
1119 (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask))
1120 break;
1121 aval[i] = j;
1122 if (needsort == 0 && i > 0 && j < aval[i-1])
1123 needsort = i;
1124 }
1125 if (!needsort)
1126 return;
1127
1128 while (needsort < num) {
1129 for (j = needsort - 1; j >= 0; j--) {
1130 if (aval[j] > aval[j+1]) {
1131 char *hp;
1132
1133 i = aval[j];
1134 aval[j] = aval[j+1];
1135 aval[j+1] = i;
1136
1137 hp = ap[j];
1138 ap[j] = ap[j+1];
1139 ap[j+1] = hp;
1140
1141 } else
1142 break;
1143 }
1144 needsort++;
1145 }
1146}
1147#endif