gethnamaddr.c revision 1.11 1 /* $NetBSD: gethnamaddr.c,v 1.11 1999/01/19 08:01:12 lukem 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.11 1999/01/19 08:01:12 lukem 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 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 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 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 int
750 _gethtbyname(rv, cb_data, ap)
751 void *rv;
752 void *cb_data;
753 va_list ap;
754 {
755 struct hostent *hp;
756 const char *name;
757 int len, af;
758
759 name = va_arg(ap, char *);
760 len = va_arg(ap, int);
761 af = va_arg(ap, int);
762
763 hp = NULL;
764 if (_res.options & RES_USE_INET6)
765 hp = _gethtbyname2(name, AF_INET6);
766 if (hp==NULL)
767 hp = _gethtbyname2(name, AF_INET);
768 *((struct hostent **)rv) = hp;
769 if (hp==NULL) {
770 h_errno = HOST_NOT_FOUND;
771 return NS_NOTFOUND;
772 }
773 return NS_SUCCESS;
774 }
775
776 struct hostent *
777 _gethtbyname2(name, af)
778 const char *name;
779 int af;
780 {
781 register struct hostent *p;
782 register char **cp;
783
784 _sethtent(0);
785 while ((p = _gethtent()) != NULL) {
786 if (p->h_addrtype != af)
787 continue;
788 if (strcasecmp(p->h_name, name) == 0)
789 break;
790 for (cp = p->h_aliases; *cp != 0; cp++)
791 if (strcasecmp(*cp, name) == 0)
792 goto found;
793 }
794 found:
795 _endhtent();
796 return (p);
797 }
798
799 int
800 _gethtbyaddr(rv, cb_data, ap)
801 void *rv;
802 void *cb_data;
803 va_list ap;
804 {
805 register struct hostent *p;
806 const unsigned char *addr;
807 int len, af;
808
809 addr = va_arg(ap, unsigned char *);
810 len = va_arg(ap, int);
811 af = va_arg(ap, int);
812
813
814 _sethtent(0);
815 while ((p = _gethtent()) != NULL)
816 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
817 (size_t)len))
818 break;
819 _endhtent();
820 *((struct hostent **)rv) = p;
821 if (p==NULL) {
822 h_errno = HOST_NOT_FOUND;
823 return NS_NOTFOUND;
824 }
825 return NS_SUCCESS;
826 }
827
828 static void
829 map_v4v6_address(src, dst)
830 const char *src;
831 char *dst;
832 {
833 u_char *p = (u_char *)dst;
834 char tmp[INADDRSZ];
835 int i;
836
837 /* Stash a temporary copy so our caller can update in place. */
838 (void)memcpy(tmp, src, INADDRSZ);
839 /* Mark this ipv6 addr as a mapped ipv4. */
840 for (i = 0; i < 10; i++)
841 *p++ = 0x00;
842 *p++ = 0xff;
843 *p++ = 0xff;
844 /* Retrieve the saved copy and we're done. */
845 (void)memcpy((void *)p, tmp, INADDRSZ);
846 }
847
848 static void
849 map_v4v6_hostent(hp, bpp, lenp)
850 struct hostent *hp;
851 char **bpp;
852 int *lenp;
853 {
854 char **ap;
855
856 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
857 return;
858 hp->h_addrtype = AF_INET6;
859 hp->h_length = IN6ADDRSZ;
860 for (ap = hp->h_addr_list; *ap; ap++) {
861 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
862
863 if (*lenp < (i + IN6ADDRSZ)) {
864 /* Out of memory. Truncate address list here. XXX */
865 *ap = NULL;
866 return;
867 }
868 *bpp += i;
869 *lenp -= i;
870 map_v4v6_address(*ap, *bpp);
871 *ap = *bpp;
872 *bpp += IN6ADDRSZ;
873 *lenp -= IN6ADDRSZ;
874 }
875 }
876
877 #ifdef RESOLVSORT
878 static void
879 addrsort(ap, num)
880 char **ap;
881 int num;
882 {
883 int i, j;
884 char **p;
885 short aval[MAXADDRS];
886 int needsort = 0;
887
888 p = ap;
889 for (i = 0; i < num; i++, p++) {
890 for (j = 0 ; (unsigned)j < _res.nsort; j++)
891 if (_res.sort_list[j].addr.s_addr ==
892 (((struct in_addr *)(void *)(*p))->s_addr & _res.sort_list[j].mask))
893 break;
894 aval[i] = j;
895 if (needsort == 0 && i > 0 && j < aval[i-1])
896 needsort = i;
897 }
898 if (!needsort)
899 return;
900
901 while (needsort < num) {
902 for (j = needsort - 1; j >= 0; j--) {
903 if (aval[j] > aval[j+1]) {
904 char *hp;
905
906 i = aval[j];
907 aval[j] = aval[j+1];
908 aval[j+1] = i;
909
910 hp = ap[j];
911 ap[j] = ap[j+1];
912 ap[j+1] = hp;
913
914 } else
915 break;
916 }
917 needsort++;
918 }
919 }
920 #endif
921
922 #if defined(BSD43_BSD43_NFS) || defined(sun)
923 /* some libc's out there are bound internally to these names (UMIPS) */
924 void
925 ht_sethostent(stayopen)
926 int stayopen;
927 {
928 _sethtent(stayopen);
929 }
930
931 void
932 ht_endhostent()
933 {
934 _endhtent();
935 }
936
937 struct hostent *
938 ht_gethostbyname(name)
939 char *name;
940 {
941 return (_gethtbyname(name));
942 }
943
944 struct hostent *
945 ht_gethostbyaddr(addr, len, af)
946 const char *addr;
947 int len, af;
948 {
949 return (_gethtbyaddr(addr, len, af));
950 }
951
952 struct hostent *
953 gethostent()
954 {
955 return (_gethtent());
956 }
957
958 void
959 dns_service()
960 {
961 return;
962 }
963
964 #undef dn_skipname
965 dn_skipname(comp_dn, eom)
966 const u_char *comp_dn, *eom;
967 {
968 return (__dn_skipname(comp_dn, eom));
969 }
970 #endif /*old-style libc with yp junk in it*/
971
972 int
973 _dns_gethtbyname(rv, cb_data, ap)
974 void *rv;
975 void *cb_data;
976 va_list ap;
977 {
978 querybuf buf;
979 int n, type;
980 struct hostent *hp;
981 const char *name;
982 int len, af;
983
984 name = va_arg(ap, char *);
985 len = va_arg(ap, int);
986 #ifdef __GNUC__ /* to shut up gcc warnings */
987 (void)&len;
988 #endif
989 af = va_arg(ap, int);
990
991 switch (af) {
992 case AF_INET:
993 type = T_A;
994 break;
995 case AF_INET6:
996 type = T_AAAA;
997 break;
998 default:
999 return NS_UNAVAIL;
1000 }
1001 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
1002 dprintf("res_search failed (%d)\n", n);
1003 return NS_NOTFOUND;
1004 }
1005 hp = getanswer(&buf, n, name, type);
1006 if (hp == NULL)
1007 switch (h_errno) {
1008 case HOST_NOT_FOUND:
1009 return NS_NOTFOUND;
1010 case TRY_AGAIN:
1011 return NS_TRYAGAIN;
1012 default:
1013 return NS_UNAVAIL;
1014 }
1015 *((struct hostent **)rv) = hp;
1016 return NS_SUCCESS;
1017 }
1018
1019 int
1020 _dns_gethtbyaddr(rv, cb_data, ap)
1021 void *rv;
1022 void *cb_data;
1023 va_list ap;
1024 {
1025 char qbuf[MAXDNAME + 1], *qp;
1026 int n;
1027 querybuf buf;
1028 struct hostent *hp;
1029 const unsigned char *uaddr;
1030 int len, af;
1031
1032 uaddr = va_arg(ap, unsigned char *);
1033 len = va_arg(ap, int);
1034 #ifdef __GNUC__ /* to shut up gcc warnings */
1035 (void)&len;
1036 #endif
1037 af = va_arg(ap, int);
1038
1039 switch (af) {
1040 case AF_INET:
1041 (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
1042 (uaddr[3] & 0xff),
1043 (uaddr[2] & 0xff),
1044 (uaddr[1] & 0xff),
1045 (uaddr[0] & 0xff));
1046 break;
1047
1048 case AF_INET6:
1049 qp = qbuf;
1050 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1051 qp += sprintf(qp, "%x.%x.",
1052 uaddr[n] & 0xf,
1053 (uaddr[n] >> 4) & 0xf);
1054 }
1055 strcpy(qp, "ip6.int");
1056 break;
1057 default:
1058 abort();
1059 }
1060
1061 n = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof(buf));
1062 if (n < 0) {
1063 dprintf("res_query failed (%d)\n", n);
1064 return NS_NOTFOUND;
1065 }
1066 hp = getanswer(&buf, n, qbuf, T_PTR);
1067 if (hp == NULL)
1068 switch (h_errno) {
1069 case HOST_NOT_FOUND:
1070 return NS_NOTFOUND;
1071 case TRY_AGAIN:
1072 return NS_TRYAGAIN;
1073 default:
1074 return NS_UNAVAIL;
1075 }
1076 hp->h_addrtype = af;
1077 hp->h_length = len;
1078 (void)memcpy(host_addr, (char *)uaddr, (size_t)len);
1079 h_addr_ptrs[0] = (char *)&host_addr;
1080 h_addr_ptrs[1] = (char *)0;
1081 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
1082 map_v4v6_address((char*)host_addr, (char*)host_addr);
1083 hp->h_addrtype = AF_INET6;
1084 hp->h_length = IN6ADDRSZ;
1085 }
1086
1087 *((struct hostent **)rv) = hp;
1088 h_errno = NETDB_SUCCESS;
1089 return NS_SUCCESS;
1090 }
1091
1092 #ifdef YP
1093 struct hostent *
1094 _yphostent(line, af)
1095 char *line;
1096 int af;
1097 {
1098 static struct in_addr host_addrs[MAXADDRS];
1099 char *p = line;
1100 char *cp, **q;
1101 char **hap;
1102 struct in_addr *buf;
1103 int more;
1104
1105 host.h_name = NULL;
1106 host.h_addr_list = h_addr_ptrs;
1107 host.h_length = sizeof(u_int32_t);
1108 host.h_addrtype = AF_INET;
1109 hap = h_addr_ptrs;
1110 buf = host_addrs;
1111 q = host.h_aliases = host_aliases;
1112
1113 /*
1114 * XXX: maybe support IPv6 parsing, based on 'af' setting
1115 */
1116 nextline:
1117 more = 0;
1118 cp = strpbrk(p, " \t");
1119 if (cp == NULL) {
1120 if (host.h_name == NULL)
1121 return (NULL);
1122 else
1123 goto done;
1124 }
1125 *cp++ = '\0';
1126
1127 *hap++ = (char *)(void *)buf;
1128 (void) inet_aton(p, buf++);
1129
1130 while (*cp == ' ' || *cp == '\t')
1131 cp++;
1132 p = cp;
1133 cp = strpbrk(p, " \t\n");
1134 if (cp != NULL) {
1135 if (*cp == '\n')
1136 more = 1;
1137 *cp++ = '\0';
1138 }
1139 if (!host.h_name)
1140 host.h_name = p;
1141 else if (strcmp(host.h_name, p)==0)
1142 ;
1143 else if (q < &host_aliases[MAXALIASES - 1])
1144 *q++ = p;
1145 p = cp;
1146 if (more)
1147 goto nextline;
1148
1149 while (cp && *cp) {
1150 if (*cp == ' ' || *cp == '\t') {
1151 cp++;
1152 continue;
1153 }
1154 if (*cp == '\n') {
1155 cp++;
1156 goto nextline;
1157 }
1158 if (q < &host_aliases[MAXALIASES - 1])
1159 *q++ = cp;
1160 cp = strpbrk(cp, " \t");
1161 if (cp != NULL)
1162 *cp++ = '\0';
1163 }
1164 done:
1165 *q = NULL;
1166 *hap = NULL;
1167 return (&host);
1168 }
1169
1170 int
1171 _yp_gethtbyaddr(rv, cb_data, ap)
1172 void *rv;
1173 void *cb_data;
1174 va_list ap;
1175 {
1176 struct hostent *hp = (struct hostent *)NULL;
1177 static char *__ypcurrent;
1178 int __ypcurrentlen, r;
1179 char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1180 const unsigned char *uaddr;
1181 int len, af;
1182
1183 uaddr = va_arg(ap, unsigned char *);
1184 len = va_arg(ap, int);
1185 #ifdef __GNUC__ /* to shut up gcc warnings */
1186 (void)&len;
1187 #endif
1188 af = va_arg(ap, int);
1189
1190 if (!__ypdomain) {
1191 if (_yp_check(&__ypdomain) == 0)
1192 return NS_UNAVAIL;
1193 }
1194 /*
1195 * XXX: based on the value of af, it would be possible to lookup
1196 * IPv6 names in YP, by changing the following snprintf().
1197 * Is it worth it?
1198 */
1199 (void)snprintf(name, sizeof name, "%u.%u.%u.%u",
1200 (uaddr[0] & 0xff),
1201 (uaddr[1] & 0xff),
1202 (uaddr[2] & 0xff),
1203 (uaddr[3] & 0xff));
1204 if (__ypcurrent)
1205 free(__ypcurrent);
1206 __ypcurrent = NULL;
1207 r = yp_match(__ypdomain, "hosts.byaddr", name,
1208 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1209 if (r==0)
1210 hp = _yphostent(__ypcurrent, af);
1211 if (hp==NULL) {
1212 h_errno = HOST_NOT_FOUND;
1213 return NS_NOTFOUND;
1214 }
1215 *((struct hostent **)rv) = hp;
1216 return NS_SUCCESS;
1217 }
1218
1219 int
1220 _yp_gethtbyname(rv, cb_data, ap)
1221 void *rv;
1222 void *cb_data;
1223 va_list ap;
1224 {
1225 struct hostent *hp = (struct hostent *)NULL;
1226 static char *__ypcurrent;
1227 int __ypcurrentlen, r;
1228 const char *name;
1229 int len, af;
1230
1231 name = va_arg(ap, char *);
1232 len = va_arg(ap, int);
1233 #ifdef __GNUC__ /* to shut up gcc warnings */
1234 (void)&len;
1235 #endif
1236 af = va_arg(ap, int);
1237
1238 if (!__ypdomain) {
1239 if (_yp_check(&__ypdomain) == 0)
1240 return NS_UNAVAIL;
1241 }
1242 if (__ypcurrent)
1243 free(__ypcurrent);
1244 __ypcurrent = NULL;
1245 r = yp_match(__ypdomain, "hosts.byname", name,
1246 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1247 if (r==0)
1248 hp = _yphostent(__ypcurrent, af);
1249 if (hp==NULL) {
1250 h_errno = HOST_NOT_FOUND;
1251 return NS_NOTFOUND;
1252 }
1253 *((struct hostent **)rv) = hp;
1254 return NS_SUCCESS;
1255 }
1256 #endif
1257