gethnamaddr.c revision 1.13 1 /* $NetBSD: gethnamaddr.c,v 1.13 1999/01/20 13:09:04 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.13 1999/01/20 13:09:04 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 <nsswitch.h>
92 #include <stdlib.h>
93 #include <string.h>
94
95 #ifdef YP
96 #include <rpc/rpc.h>
97 #include <rpcsvc/yp_prot.h>
98 #include <rpcsvc/ypclnt.h>
99 #endif
100
101 #if defined(_LIBC) && defined(__weak_alias)
102 __weak_alias(gethostbyaddr,_gethostbyaddr);
103 __weak_alias(gethostbyname,_gethostbyname);
104 #endif
105
106 #define MAXALIASES 35
107 #define MAXADDRS 35
108
109 static const char AskedForGot[] =
110 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
111
112 static char *h_addr_ptrs[MAXADDRS + 1];
113
114 #ifdef YP
115 static char *__ypdomain;
116 #endif
117
118 static struct hostent host;
119 static char *host_aliases[MAXALIASES];
120 static char hostbuf[8*1024];
121 static u_char host_addr[16]; /* IPv4 or IPv6 */
122 static FILE *hostf = NULL;
123 static int stayopen = 0;
124
125
126 #if PACKETSZ > 1024
127 #define MAXPACKET PACKETSZ
128 #else
129 #define MAXPACKET 1024
130 #endif
131
132 typedef union {
133 HEADER hdr;
134 u_char buf[MAXPACKET];
135 } querybuf;
136
137 typedef union {
138 int32_t al;
139 char ac;
140 } align;
141
142 extern int h_errno;
143
144 #ifdef DEBUG
145 static void dprintf __P((char *, int));
146 #endif
147 static struct hostent *getanswer __P((const querybuf *, int,
148 const char *, int));
149 static void map_v4v6_address __P((const char *, char *));
150 static void map_v4v6_hostent __P((struct hostent *, char **, int *));
151 #ifdef RESOLVSORT
152 static void addrsort __P((char **, int));
153 #endif
154
155 struct hostent *gethostbyname __P((const char *));
156 struct hostent *gethostbyname2 __P((const char *, int));
157 struct hostent *gethostbyaddr __P((const char *, int, int ));
158 void _sethtent __P((int));
159 void _endhtent __P((void));
160 struct hostent *_gethtent __P((void));
161 struct hostent *_gethtbyname2 __P((const char *, int));
162 void ht_sethostent __P((int));
163 void ht_endhostent __P((void));
164 struct hostent *ht_gethostbyname __P((char *));
165 struct hostent *ht_gethostbyaddr __P((const char *, int, int ));
166 struct hostent *gethostent __P((void));
167 void dns_service __P((void));
168 int dn_skipname __P((const u_char *, const u_char *));
169 int _gethtbyaddr __P((void *, void *, va_list));
170 int _gethtbyname __P((void *, void *, va_list));
171 int _dns_gethtbyaddr __P((void *, void *, va_list));
172 int _dns_gethtbyname __P((void *, void *, va_list));
173 #ifdef YP
174 struct hostent *_yphostent __P((char *, int));
175 int _yp_gethtbyaddr __P((void *, void *, va_list));
176 int _yp_gethtbyname __P((void *, void *, va_list));
177 #endif
178
179 static const ns_src default_dns_files[] = {
180 { NSSRC_DNS, NS_SUCCESS },
181 { NSSRC_FILES, NS_SUCCESS },
182 { 0 }
183 };
184
185
186 #ifdef DEBUG
187 static void
188 dprintf(msg, num)
189 char *msg;
190 int num;
191 {
192 if (_res.options & RES_DEBUG) {
193 int save = errno;
194
195 printf(msg, num);
196 errno = save;
197 }
198 }
199 #else
200 # define dprintf(msg, num) /*nada*/
201 #endif
202
203 static struct hostent *
204 getanswer(answer, anslen, qname, qtype)
205 const querybuf *answer;
206 int anslen;
207 const char *qname;
208 int qtype;
209 {
210 register const HEADER *hp;
211 register const u_char *cp;
212 register int n;
213 const u_char *eom;
214 char *bp, **ap, **hap;
215 int type, class, buflen, ancount, qdcount;
216 int haveanswer, had_error;
217 int toobig = 0;
218 char tbuf[MAXDNAME];
219 const char *tname;
220 int (*name_ok) __P((const char *));
221
222 tname = qname;
223 host.h_name = NULL;
224 eom = answer->buf + anslen;
225 switch (qtype) {
226 case T_A:
227 case T_AAAA:
228 name_ok = res_hnok;
229 break;
230 case T_PTR:
231 name_ok = res_dnok;
232 break;
233 default:
234 return (NULL); /* XXX should be abort(); */
235 }
236 /*
237 * find first satisfactory answer
238 */
239 hp = &answer->hdr;
240 ancount = ntohs(hp->ancount);
241 qdcount = ntohs(hp->qdcount);
242 bp = hostbuf;
243 buflen = sizeof hostbuf;
244 cp = answer->buf + HFIXEDSZ;
245 if (qdcount != 1) {
246 h_errno = NO_RECOVERY;
247 return (NULL);
248 }
249 n = dn_expand(answer->buf, eom, cp, bp, buflen);
250 if ((n < 0) || !(*name_ok)(bp)) {
251 h_errno = NO_RECOVERY;
252 return (NULL);
253 }
254 cp += n + QFIXEDSZ;
255 if (qtype == T_A || qtype == T_AAAA) {
256 /* res_send() has already verified that the query name is the
257 * same as the one we sent; this just gets the expanded name
258 * (i.e., with the succeeding search-domain tacked on).
259 */
260 n = strlen(bp) + 1; /* for the \0 */
261 if (n >= MAXHOSTNAMELEN) {
262 h_errno = NO_RECOVERY;
263 return (NULL);
264 }
265 host.h_name = bp;
266 bp += n;
267 buflen -= n;
268 /* The qname can be abbreviated, but h_name is now absolute. */
269 qname = host.h_name;
270 }
271 ap = host_aliases;
272 *ap = NULL;
273 host.h_aliases = host_aliases;
274 hap = h_addr_ptrs;
275 *hap = NULL;
276 host.h_addr_list = h_addr_ptrs;
277 haveanswer = 0;
278 had_error = 0;
279 while (ancount-- > 0 && cp < eom && !had_error) {
280 n = dn_expand(answer->buf, eom, cp, bp, buflen);
281 if ((n < 0) || !(*name_ok)(bp)) {
282 had_error++;
283 continue;
284 }
285 cp += n; /* name */
286 type = _getshort(cp);
287 cp += INT16SZ; /* type */
288 class = _getshort(cp);
289 cp += INT16SZ + INT32SZ; /* class, TTL */
290 n = _getshort(cp);
291 cp += INT16SZ; /* len */
292 if (class != C_IN) {
293 /* XXX - debug? syslog? */
294 cp += n;
295 continue; /* XXX - had_error++ ? */
296 }
297 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
298 if (ap >= &host_aliases[MAXALIASES-1])
299 continue;
300 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
301 if ((n < 0) || !(*name_ok)(tbuf)) {
302 had_error++;
303 continue;
304 }
305 cp += n;
306 /* Store alias. */
307 *ap++ = bp;
308 n = strlen(bp) + 1; /* for the \0 */
309 if (n >= MAXHOSTNAMELEN) {
310 had_error++;
311 continue;
312 }
313 bp += n;
314 buflen -= n;
315 /* Get canonical name. */
316 n = strlen(tbuf) + 1; /* for the \0 */
317 if (n > buflen || n >= MAXHOSTNAMELEN) {
318 had_error++;
319 continue;
320 }
321 strcpy(bp, tbuf);
322 host.h_name = bp;
323 bp += n;
324 buflen -= n;
325 continue;
326 }
327 if (qtype == T_PTR && type == T_CNAME) {
328 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
329 if (n < 0 || !res_dnok(tbuf)) {
330 had_error++;
331 continue;
332 }
333 cp += n;
334 /* Get canonical name. */
335 n = strlen(tbuf) + 1; /* for the \0 */
336 if (n > buflen || n >= MAXHOSTNAMELEN) {
337 had_error++;
338 continue;
339 }
340 strcpy(bp, tbuf);
341 tname = bp;
342 bp += n;
343 buflen -= n;
344 continue;
345 }
346 if (type != qtype) {
347 syslog(LOG_NOTICE|LOG_AUTH,
348 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
349 qname, p_class(C_IN), p_type(qtype),
350 p_type(type));
351 cp += n;
352 continue; /* XXX - had_error++ ? */
353 }
354 switch (type) {
355 case T_PTR:
356 if (strcasecmp(tname, bp) != 0) {
357 syslog(LOG_NOTICE|LOG_AUTH,
358 AskedForGot, qname, bp);
359 cp += n;
360 continue; /* XXX - had_error++ ? */
361 }
362 n = dn_expand(answer->buf, eom, cp, bp, buflen);
363 if ((n < 0) || !res_hnok(bp)) {
364 had_error++;
365 break;
366 }
367 #if MULTI_PTRS_ARE_ALIASES
368 cp += n;
369 if (!haveanswer)
370 host.h_name = bp;
371 else if (ap < &host_aliases[MAXALIASES-1])
372 *ap++ = bp;
373 else
374 n = -1;
375 if (n != -1) {
376 n = strlen(bp) + 1; /* for the \0 */
377 if (n >= MAXHOSTNAMELEN) {
378 had_error++;
379 break;
380 }
381 bp += n;
382 buflen -= n;
383 }
384 break;
385 #else
386 host.h_name = bp;
387 if (_res.options & RES_USE_INET6) {
388 n = strlen(bp) + 1; /* for the \0 */
389 if (n >= MAXHOSTNAMELEN) {
390 had_error++;
391 break;
392 }
393 bp += n;
394 buflen -= n;
395 map_v4v6_hostent(&host, &bp, &buflen);
396 }
397 h_errno = NETDB_SUCCESS;
398 return (&host);
399 #endif
400 case T_A:
401 case T_AAAA:
402 if (strcasecmp(host.h_name, bp) != 0) {
403 syslog(LOG_NOTICE|LOG_AUTH,
404 AskedForGot, host.h_name, bp);
405 cp += n;
406 continue; /* XXX - had_error++ ? */
407 }
408 if (n != host.h_length) {
409 cp += n;
410 continue;
411 }
412 if (!haveanswer) {
413 register int nn;
414
415 host.h_name = bp;
416 nn = strlen(bp) + 1; /* for the \0 */
417 bp += nn;
418 buflen -= nn;
419 }
420
421 bp += sizeof(align) - (size_t)((u_long)bp % sizeof(align));
422
423 if (bp + n >= &hostbuf[sizeof hostbuf]) {
424 dprintf("size (%d) too big\n", n);
425 had_error++;
426 continue;
427 }
428 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
429 if (!toobig++)
430 dprintf("Too many addresses (%d)\n",
431 MAXADDRS);
432 cp += n;
433 continue;
434 }
435 (void)memcpy(*hap++ = bp, cp, (size_t)n);
436 bp += n;
437 buflen -= n;
438 cp += n;
439 break;
440 default:
441 abort();
442 }
443 if (!had_error)
444 haveanswer++;
445 }
446 if (haveanswer) {
447 *ap = NULL;
448 *hap = NULL;
449 # if defined(RESOLVSORT)
450 /*
451 * Note: we sort even if host can take only one address
452 * in its return structures - should give it the "best"
453 * address in that case, not some random one
454 */
455 if (_res.nsort && haveanswer > 1 && qtype == T_A)
456 addrsort(h_addr_ptrs, haveanswer);
457 # endif /*RESOLVSORT*/
458 if (!host.h_name) {
459 n = strlen(qname) + 1; /* for the \0 */
460 if (n > buflen || n >= MAXHOSTNAMELEN)
461 goto no_recovery;
462 strcpy(bp, qname);
463 host.h_name = bp;
464 bp += n;
465 buflen -= n;
466 }
467 if (_res.options & RES_USE_INET6)
468 map_v4v6_hostent(&host, &bp, &buflen);
469 h_errno = NETDB_SUCCESS;
470 return (&host);
471 }
472 no_recovery:
473 h_errno = NO_RECOVERY;
474 return (NULL);
475 }
476
477 struct hostent *
478 gethostbyname(name)
479 const char *name;
480 {
481 struct hostent *hp;
482
483 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
484 h_errno = NETDB_INTERNAL;
485 return (NULL);
486 }
487 if (_res.options & RES_USE_INET6) {
488 hp = gethostbyname2(name, AF_INET6);
489 if (hp)
490 return (hp);
491 }
492 return (gethostbyname2(name, AF_INET));
493 }
494
495 struct hostent *
496 gethostbyname2(name, af)
497 const char *name;
498 int af;
499 {
500 const char *cp;
501 char *bp;
502 int size, len;
503 struct hostent *hp;
504 static const ns_dtab dtab[] = {
505 NS_FILES_CB(_gethtbyname, NULL)
506 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
507 NS_NIS_CB(_yp_gethtbyname, NULL)
508 { 0 }
509 };
510
511 switch (af) {
512 case AF_INET:
513 size = INADDRSZ;
514 break;
515 case AF_INET6:
516 size = IN6ADDRSZ;
517 break;
518 default:
519 h_errno = NETDB_INTERNAL;
520 errno = EAFNOSUPPORT;
521 return (NULL);
522 }
523
524 host.h_addrtype = af;
525 host.h_length = size;
526
527 /*
528 * if there aren't any dots, it could be a user-level alias.
529 * this is also done in res_query() since we are not the only
530 * function that looks up host names.
531 */
532 if (!strchr(name, '.') && (cp = __hostalias(name)))
533 name = cp;
534
535 /*
536 * disallow names consisting only of digits/dots, unless
537 * they end in a dot.
538 */
539 if (isdigit(name[0]))
540 for (cp = name;; ++cp) {
541 if (!*cp) {
542 if (*--cp == '.')
543 break;
544 /*
545 * All-numeric, no dot at the end.
546 * Fake up a hostent as if we'd actually
547 * done a lookup.
548 */
549 if (inet_pton(af, name, host_addr) <= 0) {
550 h_errno = HOST_NOT_FOUND;
551 return (NULL);
552 }
553 strncpy(hostbuf, name, MAXDNAME);
554 hostbuf[MAXDNAME] = '\0';
555 bp = hostbuf + MAXDNAME;
556 len = sizeof hostbuf - MAXDNAME;
557 host.h_name = hostbuf;
558 host.h_aliases = host_aliases;
559 host_aliases[0] = NULL;
560 h_addr_ptrs[0] = (char *)host_addr;
561 h_addr_ptrs[1] = NULL;
562 host.h_addr_list = h_addr_ptrs;
563 if (_res.options & RES_USE_INET6)
564 map_v4v6_hostent(&host, &bp, &len);
565 h_errno = NETDB_SUCCESS;
566 return (&host);
567 }
568 if (!isdigit(*cp) && *cp != '.')
569 break;
570 }
571 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
572 name[0] == ':')
573 for (cp = name;; ++cp) {
574 if (!*cp) {
575 if (*--cp == '.')
576 break;
577 /*
578 * All-IPv6-legal, no dot at the end.
579 * Fake up a hostent as if we'd actually
580 * done a lookup.
581 */
582 if (inet_pton(af, name, host_addr) <= 0) {
583 h_errno = HOST_NOT_FOUND;
584 return (NULL);
585 }
586 strncpy(hostbuf, name, MAXDNAME);
587 hostbuf[MAXDNAME] = '\0';
588 bp = hostbuf + MAXDNAME;
589 len = sizeof hostbuf - MAXDNAME;
590 host.h_name = hostbuf;
591 host.h_aliases = host_aliases;
592 host_aliases[0] = NULL;
593 h_addr_ptrs[0] = (char *)host_addr;
594 h_addr_ptrs[1] = NULL;
595 host.h_addr_list = h_addr_ptrs;
596 h_errno = NETDB_SUCCESS;
597 return (&host);
598 }
599 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
600 break;
601 }
602
603 hp = (struct hostent *)NULL;
604 h_errno = NETDB_INTERNAL;
605 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
606 default_dns_files, name, len, af) != NS_SUCCESS)
607 return (struct hostent *)NULL;
608 h_errno = NETDB_SUCCESS;
609 return (hp);
610 }
611
612 struct hostent *
613 gethostbyaddr(addr, len, af)
614 const char *addr; /* XXX should have been def'd as u_char! */
615 int len, af;
616 {
617 const u_char *uaddr = (const u_char *)addr;
618 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
619 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
620 int size;
621 struct hostent *hp;
622 static const ns_dtab dtab[] = {
623 NS_FILES_CB(_gethtbyaddr, NULL)
624 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
625 NS_NIS_CB(_yp_gethtbyaddr, NULL)
626 { 0 }
627 };
628
629 if (af == AF_INET6 && len == IN6ADDRSZ &&
630 (!memcmp(uaddr, mapped, sizeof mapped) ||
631 !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
632 /* Unmap. */
633 addr += sizeof mapped;
634 uaddr += sizeof mapped;
635 af = AF_INET;
636 len = INADDRSZ;
637 }
638 switch (af) {
639 case AF_INET:
640 size = INADDRSZ;
641 break;
642 case AF_INET6:
643 size = IN6ADDRSZ;
644 break;
645 default:
646 errno = EAFNOSUPPORT;
647 h_errno = NETDB_INTERNAL;
648 return (NULL);
649 }
650 if (size != len) {
651 errno = EINVAL;
652 h_errno = NETDB_INTERNAL;
653 return (NULL);
654 }
655 hp = (struct hostent *)NULL;
656 h_errno = NETDB_INTERNAL;
657 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
658 default_dns_files, uaddr, len, af) != NS_SUCCESS)
659 return (struct hostent *)NULL;
660 h_errno = NETDB_SUCCESS;
661 return (hp);
662 }
663
664 void
665 _sethtent(f)
666 int f;
667 {
668 if (!hostf)
669 hostf = fopen(_PATH_HOSTS, "r" );
670 else
671 rewind(hostf);
672 stayopen = f;
673 }
674
675 void
676 _endhtent()
677 {
678 if (hostf && !stayopen) {
679 (void) fclose(hostf);
680 hostf = NULL;
681 }
682 }
683
684 struct hostent *
685 _gethtent()
686 {
687 char *p;
688 register char *cp, **q;
689 int af, len;
690
691 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
692 h_errno = NETDB_INTERNAL;
693 return (NULL);
694 }
695 again:
696 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
697 h_errno = HOST_NOT_FOUND;
698 return (NULL);
699 }
700 if (*p == '#')
701 goto again;
702 if (!(cp = strpbrk(p, "#\n")))
703 goto again;
704 *cp = '\0';
705 if (!(cp = strpbrk(p, " \t")))
706 goto again;
707 *cp++ = '\0';
708 if (inet_pton(AF_INET6, p, host_addr) > 0) {
709 af = AF_INET6;
710 len = IN6ADDRSZ;
711 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
712 if (_res.options & RES_USE_INET6) {
713 map_v4v6_address((char*)host_addr, (char*)host_addr);
714 af = AF_INET6;
715 len = IN6ADDRSZ;
716 } else {
717 af = AF_INET;
718 len = INADDRSZ;
719 }
720 } else {
721 goto again;
722 }
723 h_addr_ptrs[0] = (char *)host_addr;
724 h_addr_ptrs[1] = NULL;
725 host.h_addr_list = h_addr_ptrs;
726 host.h_length = len;
727 host.h_addrtype = af;
728 while (*cp == ' ' || *cp == '\t')
729 cp++;
730 host.h_name = cp;
731 q = host.h_aliases = host_aliases;
732 if ((cp = strpbrk(cp, " \t")) != NULL)
733 *cp++ = '\0';
734 while (cp && *cp) {
735 if (*cp == ' ' || *cp == '\t') {
736 cp++;
737 continue;
738 }
739 if (q < &host_aliases[MAXALIASES - 1])
740 *q++ = cp;
741 if ((cp = strpbrk(cp, " \t")) != NULL)
742 *cp++ = '\0';
743 }
744 *q = NULL;
745 h_errno = NETDB_SUCCESS;
746 return (&host);
747 }
748
749 /*ARGSUSED*/
750 int
751 _gethtbyname(rv, cb_data, ap)
752 void *rv;
753 void *cb_data;
754 va_list ap;
755 {
756 struct hostent *hp;
757 const char *name;
758 #ifdef notyet
759 int len, af;
760 #endif
761
762 name = va_arg(ap, char *);
763 #ifdef notyet
764 len = va_arg(ap, int);
765 af = va_arg(ap, int);
766 #endif
767
768 hp = NULL;
769 if (_res.options & RES_USE_INET6)
770 hp = _gethtbyname2(name, AF_INET6);
771 if (hp==NULL)
772 hp = _gethtbyname2(name, AF_INET);
773 *((struct hostent **)rv) = hp;
774 if (hp==NULL) {
775 h_errno = HOST_NOT_FOUND;
776 return NS_NOTFOUND;
777 }
778 return NS_SUCCESS;
779 }
780
781 struct hostent *
782 _gethtbyname2(name, af)
783 const char *name;
784 int af;
785 {
786 register struct hostent *p;
787 register char **cp;
788
789 _sethtent(0);
790 while ((p = _gethtent()) != NULL) {
791 if (p->h_addrtype != af)
792 continue;
793 if (strcasecmp(p->h_name, name) == 0)
794 break;
795 for (cp = p->h_aliases; *cp != 0; cp++)
796 if (strcasecmp(*cp, name) == 0)
797 goto found;
798 }
799 found:
800 _endhtent();
801 return (p);
802 }
803
804 /*ARGSUSED*/
805 int
806 _gethtbyaddr(rv, cb_data, ap)
807 void *rv;
808 void *cb_data;
809 va_list ap;
810 {
811 register struct hostent *p;
812 const unsigned char *addr;
813 int len, af;
814
815 addr = va_arg(ap, unsigned char *);
816 len = va_arg(ap, int);
817 af = va_arg(ap, int);
818
819
820 _sethtent(0);
821 while ((p = _gethtent()) != NULL)
822 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
823 (size_t)len))
824 break;
825 _endhtent();
826 *((struct hostent **)rv) = p;
827 if (p==NULL) {
828 h_errno = HOST_NOT_FOUND;
829 return NS_NOTFOUND;
830 }
831 return NS_SUCCESS;
832 }
833
834 static void
835 map_v4v6_address(src, dst)
836 const char *src;
837 char *dst;
838 {
839 u_char *p = (u_char *)dst;
840 char tmp[INADDRSZ];
841 int i;
842
843 /* Stash a temporary copy so our caller can update in place. */
844 (void)memcpy(tmp, src, INADDRSZ);
845 /* Mark this ipv6 addr as a mapped ipv4. */
846 for (i = 0; i < 10; i++)
847 *p++ = 0x00;
848 *p++ = 0xff;
849 *p++ = 0xff;
850 /* Retrieve the saved copy and we're done. */
851 (void)memcpy((void *)p, tmp, INADDRSZ);
852 }
853
854 static void
855 map_v4v6_hostent(hp, bpp, lenp)
856 struct hostent *hp;
857 char **bpp;
858 int *lenp;
859 {
860 char **ap;
861
862 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
863 return;
864 hp->h_addrtype = AF_INET6;
865 hp->h_length = IN6ADDRSZ;
866 for (ap = hp->h_addr_list; *ap; ap++) {
867 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
868
869 if (*lenp < (i + IN6ADDRSZ)) {
870 /* Out of memory. Truncate address list here. XXX */
871 *ap = NULL;
872 return;
873 }
874 *bpp += i;
875 *lenp -= i;
876 map_v4v6_address(*ap, *bpp);
877 *ap = *bpp;
878 *bpp += IN6ADDRSZ;
879 *lenp -= IN6ADDRSZ;
880 }
881 }
882
883 #ifdef RESOLVSORT
884 static void
885 addrsort(ap, num)
886 char **ap;
887 int num;
888 {
889 int i, j;
890 char **p;
891 short aval[MAXADDRS];
892 int needsort = 0;
893
894 p = ap;
895 for (i = 0; i < num; i++, p++) {
896 for (j = 0 ; (unsigned)j < _res.nsort; j++)
897 if (_res.sort_list[j].addr.s_addr ==
898 (((struct in_addr *)(void *)(*p))->s_addr & _res.sort_list[j].mask))
899 break;
900 aval[i] = j;
901 if (needsort == 0 && i > 0 && j < aval[i-1])
902 needsort = i;
903 }
904 if (!needsort)
905 return;
906
907 while (needsort < num) {
908 for (j = needsort - 1; j >= 0; j--) {
909 if (aval[j] > aval[j+1]) {
910 char *hp;
911
912 i = aval[j];
913 aval[j] = aval[j+1];
914 aval[j+1] = i;
915
916 hp = ap[j];
917 ap[j] = ap[j+1];
918 ap[j+1] = hp;
919
920 } else
921 break;
922 }
923 needsort++;
924 }
925 }
926 #endif
927
928 #if defined(BSD43_BSD43_NFS) || defined(sun)
929 /* some libc's out there are bound internally to these names (UMIPS) */
930 void
931 ht_sethostent(stayopen)
932 int stayopen;
933 {
934 _sethtent(stayopen);
935 }
936
937 void
938 ht_endhostent()
939 {
940 _endhtent();
941 }
942
943 struct hostent *
944 ht_gethostbyname(name)
945 char *name;
946 {
947 return (_gethtbyname(name));
948 }
949
950 struct hostent *
951 ht_gethostbyaddr(addr, len, af)
952 const char *addr;
953 int len, af;
954 {
955 return (_gethtbyaddr(addr, len, af));
956 }
957
958 struct hostent *
959 gethostent()
960 {
961 return (_gethtent());
962 }
963
964 void
965 dns_service()
966 {
967 return;
968 }
969
970 #undef dn_skipname
971 dn_skipname(comp_dn, eom)
972 const u_char *comp_dn, *eom;
973 {
974 return (__dn_skipname(comp_dn, eom));
975 }
976 #endif /*old-style libc with yp junk in it*/
977
978 /*ARGSUSED*/
979 int
980 _dns_gethtbyname(rv, cb_data, ap)
981 void *rv;
982 void *cb_data;
983 va_list ap;
984 {
985 querybuf buf;
986 int n, type;
987 struct hostent *hp;
988 const char *name;
989 int len, af;
990
991 name = va_arg(ap, char *);
992 len = va_arg(ap, int);
993 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
994 /*LINTED*/
995 (void)(len ? &len : &len);
996 #endif
997 af = va_arg(ap, int);
998
999 switch (af) {
1000 case AF_INET:
1001 type = T_A;
1002 break;
1003 case AF_INET6:
1004 type = T_AAAA;
1005 break;
1006 default:
1007 return NS_UNAVAIL;
1008 }
1009 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
1010 dprintf("res_search failed (%d)\n", n);
1011 return NS_NOTFOUND;
1012 }
1013 hp = getanswer(&buf, n, name, type);
1014 if (hp == NULL)
1015 switch (h_errno) {
1016 case HOST_NOT_FOUND:
1017 return NS_NOTFOUND;
1018 case TRY_AGAIN:
1019 return NS_TRYAGAIN;
1020 default:
1021 return NS_UNAVAIL;
1022 }
1023 *((struct hostent **)rv) = hp;
1024 return NS_SUCCESS;
1025 }
1026
1027 /*ARGSUSED*/
1028 int
1029 _dns_gethtbyaddr(rv, cb_data, ap)
1030 void *rv;
1031 void *cb_data;
1032 va_list ap;
1033 {
1034 char qbuf[MAXDNAME + 1], *qp;
1035 int n;
1036 querybuf buf;
1037 struct hostent *hp;
1038 const unsigned char *uaddr;
1039 int len, af;
1040
1041 uaddr = va_arg(ap, unsigned char *);
1042 len = va_arg(ap, int);
1043 #ifdef __GNUC__ /* to shut up gcc warnings */
1044 (void)&len;
1045 #endif
1046 af = va_arg(ap, int);
1047
1048 switch (af) {
1049 case AF_INET:
1050 (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
1051 (uaddr[3] & 0xff),
1052 (uaddr[2] & 0xff),
1053 (uaddr[1] & 0xff),
1054 (uaddr[0] & 0xff));
1055 break;
1056
1057 case AF_INET6:
1058 qp = qbuf;
1059 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1060 qp += sprintf(qp, "%x.%x.",
1061 uaddr[n] & 0xf,
1062 ((unsigned int)uaddr[n] >> 4) & 0xf);
1063 }
1064 strcpy(qp, "ip6.int");
1065 break;
1066 default:
1067 abort();
1068 }
1069
1070 n = res_query(qbuf, C_IN, T_PTR, (u_char *)(void *)&buf, sizeof(buf));
1071 if (n < 0) {
1072 dprintf("res_query failed (%d)\n", n);
1073 return NS_NOTFOUND;
1074 }
1075 hp = getanswer(&buf, n, qbuf, T_PTR);
1076 if (hp == NULL)
1077 switch (h_errno) {
1078 case HOST_NOT_FOUND:
1079 return NS_NOTFOUND;
1080 case TRY_AGAIN:
1081 return NS_TRYAGAIN;
1082 default:
1083 return NS_UNAVAIL;
1084 }
1085 hp->h_addrtype = af;
1086 hp->h_length = len;
1087 (void)memcpy(host_addr, uaddr, (size_t)len);
1088 h_addr_ptrs[0] = (char *)&host_addr;
1089 h_addr_ptrs[1] = (char *)0;
1090 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
1091 map_v4v6_address((char*)host_addr, (char*)host_addr);
1092 hp->h_addrtype = AF_INET6;
1093 hp->h_length = IN6ADDRSZ;
1094 }
1095
1096 *((struct hostent **)rv) = hp;
1097 h_errno = NETDB_SUCCESS;
1098 return NS_SUCCESS;
1099 }
1100
1101 #ifdef YP
1102 /*ARGSUSED*/
1103 struct hostent *
1104 _yphostent(line, af)
1105 char *line;
1106 int af;
1107 {
1108 static struct in_addr host_addrs[MAXADDRS];
1109 char *p = line;
1110 char *cp, **q;
1111 char **hap;
1112 struct in_addr *buf;
1113 int more;
1114
1115 host.h_name = NULL;
1116 host.h_addr_list = h_addr_ptrs;
1117 host.h_length = sizeof(u_int32_t);
1118 host.h_addrtype = AF_INET;
1119 hap = h_addr_ptrs;
1120 buf = host_addrs;
1121 q = host.h_aliases = host_aliases;
1122
1123 /*
1124 * XXX: maybe support IPv6 parsing, based on 'af' setting
1125 */
1126 nextline:
1127 more = 0;
1128 cp = strpbrk(p, " \t");
1129 if (cp == NULL) {
1130 if (host.h_name == NULL)
1131 return (NULL);
1132 else
1133 goto done;
1134 }
1135 *cp++ = '\0';
1136
1137 *hap++ = (char *)(void *)buf;
1138 (void) inet_aton(p, buf++);
1139
1140 while (*cp == ' ' || *cp == '\t')
1141 cp++;
1142 p = cp;
1143 cp = strpbrk(p, " \t\n");
1144 if (cp != NULL) {
1145 if (*cp == '\n')
1146 more = 1;
1147 *cp++ = '\0';
1148 }
1149 if (!host.h_name)
1150 host.h_name = p;
1151 else if (strcmp(host.h_name, p)==0)
1152 ;
1153 else if (q < &host_aliases[MAXALIASES - 1])
1154 *q++ = p;
1155 p = cp;
1156 if (more)
1157 goto nextline;
1158
1159 while (cp && *cp) {
1160 if (*cp == ' ' || *cp == '\t') {
1161 cp++;
1162 continue;
1163 }
1164 if (*cp == '\n') {
1165 cp++;
1166 goto nextline;
1167 }
1168 if (q < &host_aliases[MAXALIASES - 1])
1169 *q++ = cp;
1170 cp = strpbrk(cp, " \t");
1171 if (cp != NULL)
1172 *cp++ = '\0';
1173 }
1174 done:
1175 *q = NULL;
1176 *hap = NULL;
1177 return (&host);
1178 }
1179
1180 /*ARGSUSED*/
1181 int
1182 _yp_gethtbyaddr(rv, cb_data, ap)
1183 void *rv;
1184 void *cb_data;
1185 va_list ap;
1186 {
1187 struct hostent *hp = (struct hostent *)NULL;
1188 static char *__ypcurrent;
1189 int __ypcurrentlen, r;
1190 char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1191 const unsigned char *uaddr;
1192 int len, af;
1193
1194 uaddr = va_arg(ap, unsigned char *);
1195 len = va_arg(ap, int);
1196 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
1197 /*LINTED*/
1198 (void)(len ? &len : &len);
1199 #endif
1200 af = va_arg(ap, int);
1201
1202 if (!__ypdomain) {
1203 if (_yp_check(&__ypdomain) == 0)
1204 return NS_UNAVAIL;
1205 }
1206 /*
1207 * XXX: based on the value of af, it would be possible to lookup
1208 * IPv6 names in YP, by changing the following snprintf().
1209 * Is it worth it?
1210 */
1211 (void)snprintf(name, sizeof name, "%u.%u.%u.%u",
1212 (uaddr[0] & 0xff),
1213 (uaddr[1] & 0xff),
1214 (uaddr[2] & 0xff),
1215 (uaddr[3] & 0xff));
1216 if (__ypcurrent)
1217 free(__ypcurrent);
1218 __ypcurrent = NULL;
1219 r = yp_match(__ypdomain, "hosts.byaddr", name,
1220 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1221 if (r==0)
1222 hp = _yphostent(__ypcurrent, af);
1223 if (hp==NULL) {
1224 h_errno = HOST_NOT_FOUND;
1225 return NS_NOTFOUND;
1226 }
1227 *((struct hostent **)rv) = hp;
1228 return NS_SUCCESS;
1229 }
1230
1231 /*ARGSUSED*/
1232 int
1233 _yp_gethtbyname(rv, cb_data, ap)
1234 void *rv;
1235 void *cb_data;
1236 va_list ap;
1237 {
1238 struct hostent *hp = (struct hostent *)NULL;
1239 static char *__ypcurrent;
1240 int __ypcurrentlen, r;
1241 const char *name;
1242 int len, af;
1243
1244 name = va_arg(ap, char *);
1245 len = va_arg(ap, int);
1246 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
1247 /*LINTED*/
1248 (void)(len ? &len : &len);
1249 #endif
1250 af = va_arg(ap, int);
1251
1252 if (!__ypdomain) {
1253 if (_yp_check(&__ypdomain) == 0)
1254 return NS_UNAVAIL;
1255 }
1256 if (__ypcurrent)
1257 free(__ypcurrent);
1258 __ypcurrent = NULL;
1259 r = yp_match(__ypdomain, "hosts.byname", name,
1260 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1261 if (r==0)
1262 hp = _yphostent(__ypcurrent, af);
1263 if (hp==NULL) {
1264 h_errno = HOST_NOT_FOUND;
1265 return NS_NOTFOUND;
1266 }
1267 *((struct hostent **)rv) = hp;
1268 return NS_SUCCESS;
1269 }
1270 #endif
1271