gethnamaddr.c revision 1.14 1 /* $NetBSD: gethnamaddr.c,v 1.14 1999/01/20 23:31:02 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.14 1999/01/20 23:31:02 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 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) -
422 (size_t)((u_long)bp % sizeof(align));
423
424 if (bp + n >= &hostbuf[sizeof hostbuf]) {
425 dprintf("size (%d) too big\n", n);
426 had_error++;
427 continue;
428 }
429 if (hap >= &h_addr_ptrs[MAXADDRS-1]) {
430 if (!toobig++)
431 dprintf("Too many addresses (%d)\n",
432 MAXADDRS);
433 cp += n;
434 continue;
435 }
436 (void)memcpy(*hap++ = bp, cp, (size_t)n);
437 bp += n;
438 buflen -= n;
439 cp += n;
440 break;
441 default:
442 abort();
443 }
444 if (!had_error)
445 haveanswer++;
446 }
447 if (haveanswer) {
448 *ap = NULL;
449 *hap = NULL;
450 # if defined(RESOLVSORT)
451 /*
452 * Note: we sort even if host can take only one address
453 * in its return structures - should give it the "best"
454 * address in that case, not some random one
455 */
456 if (_res.nsort && haveanswer > 1 && qtype == T_A)
457 addrsort(h_addr_ptrs, haveanswer);
458 # endif /*RESOLVSORT*/
459 if (!host.h_name) {
460 n = strlen(qname) + 1; /* for the \0 */
461 if (n > buflen || n >= MAXHOSTNAMELEN)
462 goto no_recovery;
463 strcpy(bp, qname);
464 host.h_name = bp;
465 bp += n;
466 buflen -= n;
467 }
468 if (_res.options & RES_USE_INET6)
469 map_v4v6_hostent(&host, &bp, &buflen);
470 h_errno = NETDB_SUCCESS;
471 return (&host);
472 }
473 no_recovery:
474 h_errno = NO_RECOVERY;
475 return (NULL);
476 }
477
478 struct hostent *
479 gethostbyname(name)
480 const char *name;
481 {
482 struct hostent *hp;
483
484 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
485 h_errno = NETDB_INTERNAL;
486 return (NULL);
487 }
488 if (_res.options & RES_USE_INET6) {
489 hp = gethostbyname2(name, AF_INET6);
490 if (hp)
491 return (hp);
492 }
493 return (gethostbyname2(name, AF_INET));
494 }
495
496 struct hostent *
497 gethostbyname2(name, af)
498 const char *name;
499 int af;
500 {
501 const char *cp;
502 char *bp;
503 int size, len;
504 struct hostent *hp;
505 static const ns_dtab dtab[] = {
506 NS_FILES_CB(_gethtbyname, NULL)
507 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
508 NS_NIS_CB(_yp_gethtbyname, NULL)
509 { 0 }
510 };
511
512 switch (af) {
513 case AF_INET:
514 size = INADDRSZ;
515 break;
516 case AF_INET6:
517 size = IN6ADDRSZ;
518 break;
519 default:
520 h_errno = NETDB_INTERNAL;
521 errno = EAFNOSUPPORT;
522 return (NULL);
523 }
524
525 host.h_addrtype = af;
526 host.h_length = size;
527
528 /*
529 * if there aren't any dots, it could be a user-level alias.
530 * this is also done in res_query() since we are not the only
531 * function that looks up host names.
532 */
533 if (!strchr(name, '.') && (cp = __hostalias(name)))
534 name = cp;
535
536 /*
537 * disallow names consisting only of digits/dots, unless
538 * they end in a dot.
539 */
540 if (isdigit(name[0]))
541 for (cp = name;; ++cp) {
542 if (!*cp) {
543 if (*--cp == '.')
544 break;
545 /*
546 * All-numeric, no dot at the end.
547 * Fake up a hostent as if we'd actually
548 * done a lookup.
549 */
550 if (inet_pton(af, name, host_addr) <= 0) {
551 h_errno = HOST_NOT_FOUND;
552 return (NULL);
553 }
554 strncpy(hostbuf, name, MAXDNAME);
555 hostbuf[MAXDNAME] = '\0';
556 bp = hostbuf + MAXDNAME;
557 len = sizeof hostbuf - MAXDNAME;
558 host.h_name = hostbuf;
559 host.h_aliases = host_aliases;
560 host_aliases[0] = NULL;
561 h_addr_ptrs[0] = (char *)host_addr;
562 h_addr_ptrs[1] = NULL;
563 host.h_addr_list = h_addr_ptrs;
564 if (_res.options & RES_USE_INET6)
565 map_v4v6_hostent(&host, &bp, &len);
566 h_errno = NETDB_SUCCESS;
567 return (&host);
568 }
569 if (!isdigit(*cp) && *cp != '.')
570 break;
571 }
572 if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
573 name[0] == ':')
574 for (cp = name;; ++cp) {
575 if (!*cp) {
576 if (*--cp == '.')
577 break;
578 /*
579 * All-IPv6-legal, no dot at the end.
580 * Fake up a hostent as if we'd actually
581 * done a lookup.
582 */
583 if (inet_pton(af, name, host_addr) <= 0) {
584 h_errno = HOST_NOT_FOUND;
585 return (NULL);
586 }
587 strncpy(hostbuf, name, MAXDNAME);
588 hostbuf[MAXDNAME] = '\0';
589 bp = hostbuf + MAXDNAME;
590 len = sizeof hostbuf - MAXDNAME;
591 host.h_name = hostbuf;
592 host.h_aliases = host_aliases;
593 host_aliases[0] = NULL;
594 h_addr_ptrs[0] = (char *)host_addr;
595 h_addr_ptrs[1] = NULL;
596 host.h_addr_list = h_addr_ptrs;
597 h_errno = NETDB_SUCCESS;
598 return (&host);
599 }
600 if (!isxdigit(*cp) && *cp != ':' && *cp != '.')
601 break;
602 }
603
604 hp = (struct hostent *)NULL;
605 h_errno = NETDB_INTERNAL;
606 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
607 default_dns_files, name, len, af) != NS_SUCCESS)
608 return (struct hostent *)NULL;
609 h_errno = NETDB_SUCCESS;
610 return (hp);
611 }
612
613 struct hostent *
614 gethostbyaddr(addr, len, af)
615 const char *addr; /* XXX should have been def'd as u_char! */
616 int len, af;
617 {
618 const u_char *uaddr = (const u_char *)addr;
619 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
620 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
621 int size;
622 struct hostent *hp;
623 static const ns_dtab dtab[] = {
624 NS_FILES_CB(_gethtbyaddr, NULL)
625 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
626 NS_NIS_CB(_yp_gethtbyaddr, NULL)
627 { 0 }
628 };
629
630 if (af == AF_INET6 && len == IN6ADDRSZ &&
631 (!memcmp(uaddr, mapped, sizeof mapped) ||
632 !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
633 /* Unmap. */
634 addr += sizeof mapped;
635 uaddr += sizeof mapped;
636 af = AF_INET;
637 len = INADDRSZ;
638 }
639 switch (af) {
640 case AF_INET:
641 size = INADDRSZ;
642 break;
643 case AF_INET6:
644 size = IN6ADDRSZ;
645 break;
646 default:
647 errno = EAFNOSUPPORT;
648 h_errno = NETDB_INTERNAL;
649 return (NULL);
650 }
651 if (size != len) {
652 errno = EINVAL;
653 h_errno = NETDB_INTERNAL;
654 return (NULL);
655 }
656 hp = (struct hostent *)NULL;
657 h_errno = NETDB_INTERNAL;
658 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
659 default_dns_files, uaddr, len, af) != NS_SUCCESS)
660 return (struct hostent *)NULL;
661 h_errno = NETDB_SUCCESS;
662 return (hp);
663 }
664
665 void
666 _sethtent(f)
667 int f;
668 {
669 if (!hostf)
670 hostf = fopen(_PATH_HOSTS, "r" );
671 else
672 rewind(hostf);
673 stayopen = f;
674 }
675
676 void
677 _endhtent()
678 {
679 if (hostf && !stayopen) {
680 (void) fclose(hostf);
681 hostf = NULL;
682 }
683 }
684
685 struct hostent *
686 _gethtent()
687 {
688 char *p;
689 register char *cp, **q;
690 int af, len;
691
692 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) {
693 h_errno = NETDB_INTERNAL;
694 return (NULL);
695 }
696 again:
697 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) {
698 h_errno = HOST_NOT_FOUND;
699 return (NULL);
700 }
701 if (*p == '#')
702 goto again;
703 if (!(cp = strpbrk(p, "#\n")))
704 goto again;
705 *cp = '\0';
706 if (!(cp = strpbrk(p, " \t")))
707 goto again;
708 *cp++ = '\0';
709 if (inet_pton(AF_INET6, p, host_addr) > 0) {
710 af = AF_INET6;
711 len = IN6ADDRSZ;
712 } else if (inet_pton(AF_INET, p, host_addr) > 0) {
713 if (_res.options & RES_USE_INET6) {
714 map_v4v6_address((char*)host_addr, (char*)host_addr);
715 af = AF_INET6;
716 len = IN6ADDRSZ;
717 } else {
718 af = AF_INET;
719 len = INADDRSZ;
720 }
721 } else {
722 goto again;
723 }
724 h_addr_ptrs[0] = (char *)host_addr;
725 h_addr_ptrs[1] = NULL;
726 host.h_addr_list = h_addr_ptrs;
727 host.h_length = len;
728 host.h_addrtype = af;
729 while (*cp == ' ' || *cp == '\t')
730 cp++;
731 host.h_name = cp;
732 q = host.h_aliases = host_aliases;
733 if ((cp = strpbrk(cp, " \t")) != NULL)
734 *cp++ = '\0';
735 while (cp && *cp) {
736 if (*cp == ' ' || *cp == '\t') {
737 cp++;
738 continue;
739 }
740 if (q < &host_aliases[MAXALIASES - 1])
741 *q++ = cp;
742 if ((cp = strpbrk(cp, " \t")) != NULL)
743 *cp++ = '\0';
744 }
745 *q = NULL;
746 h_errno = NETDB_SUCCESS;
747 return (&host);
748 }
749
750 /*ARGSUSED*/
751 int
752 _gethtbyname(rv, cb_data, ap)
753 void *rv;
754 void *cb_data;
755 va_list ap;
756 {
757 struct hostent *hp;
758 const char *name;
759 #ifdef notyet
760 int len, af;
761 #endif
762
763 name = va_arg(ap, char *);
764 #ifdef notyet
765 len = va_arg(ap, int);
766 af = va_arg(ap, int);
767 #endif
768
769 hp = NULL;
770 if (_res.options & RES_USE_INET6)
771 hp = _gethtbyname2(name, AF_INET6);
772 if (hp==NULL)
773 hp = _gethtbyname2(name, AF_INET);
774 *((struct hostent **)rv) = hp;
775 if (hp==NULL) {
776 h_errno = HOST_NOT_FOUND;
777 return NS_NOTFOUND;
778 }
779 return NS_SUCCESS;
780 }
781
782 struct hostent *
783 _gethtbyname2(name, af)
784 const char *name;
785 int af;
786 {
787 register struct hostent *p;
788 register char **cp;
789
790 _sethtent(0);
791 while ((p = _gethtent()) != NULL) {
792 if (p->h_addrtype != af)
793 continue;
794 if (strcasecmp(p->h_name, name) == 0)
795 break;
796 for (cp = p->h_aliases; *cp != 0; cp++)
797 if (strcasecmp(*cp, name) == 0)
798 goto found;
799 }
800 found:
801 _endhtent();
802 return (p);
803 }
804
805 /*ARGSUSED*/
806 int
807 _gethtbyaddr(rv, cb_data, ap)
808 void *rv;
809 void *cb_data;
810 va_list ap;
811 {
812 register struct hostent *p;
813 const unsigned char *addr;
814 int len, af;
815
816 addr = va_arg(ap, unsigned char *);
817 len = va_arg(ap, int);
818 af = va_arg(ap, int);
819
820
821 _sethtent(0);
822 while ((p = _gethtent()) != NULL)
823 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
824 (size_t)len))
825 break;
826 _endhtent();
827 *((struct hostent **)rv) = p;
828 if (p==NULL) {
829 h_errno = HOST_NOT_FOUND;
830 return NS_NOTFOUND;
831 }
832 return NS_SUCCESS;
833 }
834
835 static void
836 map_v4v6_address(src, dst)
837 const char *src;
838 char *dst;
839 {
840 u_char *p = (u_char *)dst;
841 char tmp[INADDRSZ];
842 int i;
843
844 /* Stash a temporary copy so our caller can update in place. */
845 (void)memcpy(tmp, src, INADDRSZ);
846 /* Mark this ipv6 addr as a mapped ipv4. */
847 for (i = 0; i < 10; i++)
848 *p++ = 0x00;
849 *p++ = 0xff;
850 *p++ = 0xff;
851 /* Retrieve the saved copy and we're done. */
852 (void)memcpy((void *)p, tmp, INADDRSZ);
853 }
854
855 static void
856 map_v4v6_hostent(hp, bpp, lenp)
857 struct hostent *hp;
858 char **bpp;
859 int *lenp;
860 {
861 char **ap;
862
863 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
864 return;
865 hp->h_addrtype = AF_INET6;
866 hp->h_length = IN6ADDRSZ;
867 for (ap = hp->h_addr_list; *ap; ap++) {
868 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
869
870 if (*lenp < (i + IN6ADDRSZ)) {
871 /* Out of memory. Truncate address list here. XXX */
872 *ap = NULL;
873 return;
874 }
875 *bpp += i;
876 *lenp -= i;
877 map_v4v6_address(*ap, *bpp);
878 *ap = *bpp;
879 *bpp += IN6ADDRSZ;
880 *lenp -= IN6ADDRSZ;
881 }
882 }
883
884 #ifdef RESOLVSORT
885 static void
886 addrsort(ap, num)
887 char **ap;
888 int num;
889 {
890 int i, j;
891 char **p;
892 short aval[MAXADDRS];
893 int needsort = 0;
894
895 p = ap;
896 for (i = 0; i < num; i++, p++) {
897 for (j = 0 ; (unsigned)j < _res.nsort; j++)
898 if (_res.sort_list[j].addr.s_addr ==
899 (((struct in_addr *)(void *)(*p))->s_addr &
900 _res.sort_list[j].mask))
901 break;
902 aval[i] = j;
903 if (needsort == 0 && i > 0 && j < aval[i-1])
904 needsort = i;
905 }
906 if (!needsort)
907 return;
908
909 while (needsort < num) {
910 for (j = needsort - 1; j >= 0; j--) {
911 if (aval[j] > aval[j+1]) {
912 char *hp;
913
914 i = aval[j];
915 aval[j] = aval[j+1];
916 aval[j+1] = i;
917
918 hp = ap[j];
919 ap[j] = ap[j+1];
920 ap[j+1] = hp;
921
922 } else
923 break;
924 }
925 needsort++;
926 }
927 }
928 #endif
929
930 #if defined(BSD43_BSD43_NFS) || defined(sun)
931 /* some libc's out there are bound internally to these names (UMIPS) */
932 void
933 ht_sethostent(stayopen)
934 int stayopen;
935 {
936 _sethtent(stayopen);
937 }
938
939 void
940 ht_endhostent()
941 {
942 _endhtent();
943 }
944
945 struct hostent *
946 ht_gethostbyname(name)
947 char *name;
948 {
949 return (_gethtbyname(name));
950 }
951
952 struct hostent *
953 ht_gethostbyaddr(addr, len, af)
954 const char *addr;
955 int len, af;
956 {
957 return (_gethtbyaddr(addr, len, af));
958 }
959
960 struct hostent *
961 gethostent()
962 {
963 return (_gethtent());
964 }
965
966 void
967 dns_service()
968 {
969 return;
970 }
971
972 #undef dn_skipname
973 dn_skipname(comp_dn, eom)
974 const u_char *comp_dn, *eom;
975 {
976 return (__dn_skipname(comp_dn, eom));
977 }
978 #endif /*old-style libc with yp junk in it*/
979
980 /*ARGSUSED*/
981 int
982 _dns_gethtbyname(rv, cb_data, ap)
983 void *rv;
984 void *cb_data;
985 va_list ap;
986 {
987 querybuf buf;
988 int n, type;
989 struct hostent *hp;
990 const char *name;
991 int len, af;
992
993 name = va_arg(ap, char *);
994 len = va_arg(ap, int);
995 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
996 /*LINTED*/
997 (void)(len ? &len : &len);
998 #endif
999 af = va_arg(ap, int);
1000
1001 switch (af) {
1002 case AF_INET:
1003 type = T_A;
1004 break;
1005 case AF_INET6:
1006 type = T_AAAA;
1007 break;
1008 default:
1009 return NS_UNAVAIL;
1010 }
1011 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof(buf))) < 0) {
1012 dprintf("res_search failed (%d)\n", n);
1013 return NS_NOTFOUND;
1014 }
1015 hp = getanswer(&buf, n, name, type);
1016 if (hp == NULL)
1017 switch (h_errno) {
1018 case HOST_NOT_FOUND:
1019 return NS_NOTFOUND;
1020 case TRY_AGAIN:
1021 return NS_TRYAGAIN;
1022 default:
1023 return NS_UNAVAIL;
1024 }
1025 *((struct hostent **)rv) = hp;
1026 return NS_SUCCESS;
1027 }
1028
1029 /*ARGSUSED*/
1030 int
1031 _dns_gethtbyaddr(rv, cb_data, ap)
1032 void *rv;
1033 void *cb_data;
1034 va_list ap;
1035 {
1036 char qbuf[MAXDNAME + 1], *qp;
1037 int n;
1038 querybuf buf;
1039 struct hostent *hp;
1040 const unsigned char *uaddr;
1041 int len, af;
1042
1043 uaddr = va_arg(ap, unsigned char *);
1044 len = va_arg(ap, int);
1045 #ifdef __GNUC__ /* to shut up gcc warnings */
1046 (void)&len;
1047 #endif
1048 af = va_arg(ap, int);
1049
1050 switch (af) {
1051 case AF_INET:
1052 (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
1053 (uaddr[3] & 0xff),
1054 (uaddr[2] & 0xff),
1055 (uaddr[1] & 0xff),
1056 (uaddr[0] & 0xff));
1057 break;
1058
1059 case AF_INET6:
1060 qp = qbuf;
1061 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1062 qp += sprintf(qp, "%x.%x.",
1063 uaddr[n] & 0xf,
1064 ((unsigned int)uaddr[n] >> 4) & 0xf);
1065 }
1066 strcpy(qp, "ip6.int");
1067 break;
1068 default:
1069 abort();
1070 }
1071
1072 n = res_query(qbuf, C_IN, T_PTR, (u_char *)(void *)&buf, sizeof(buf));
1073 if (n < 0) {
1074 dprintf("res_query failed (%d)\n", n);
1075 return NS_NOTFOUND;
1076 }
1077 hp = getanswer(&buf, n, qbuf, T_PTR);
1078 if (hp == NULL)
1079 switch (h_errno) {
1080 case HOST_NOT_FOUND:
1081 return NS_NOTFOUND;
1082 case TRY_AGAIN:
1083 return NS_TRYAGAIN;
1084 default:
1085 return NS_UNAVAIL;
1086 }
1087 hp->h_addrtype = af;
1088 hp->h_length = len;
1089 (void)memcpy(host_addr, uaddr, (size_t)len);
1090 h_addr_ptrs[0] = (char *)&host_addr;
1091 h_addr_ptrs[1] = (char *)0;
1092 if (af == AF_INET && (_res.options & RES_USE_INET6)) {
1093 map_v4v6_address((char*)host_addr, (char*)host_addr);
1094 hp->h_addrtype = AF_INET6;
1095 hp->h_length = IN6ADDRSZ;
1096 }
1097
1098 *((struct hostent **)rv) = hp;
1099 h_errno = NETDB_SUCCESS;
1100 return NS_SUCCESS;
1101 }
1102
1103 #ifdef YP
1104 /*ARGSUSED*/
1105 struct hostent *
1106 _yphostent(line, af)
1107 char *line;
1108 int af;
1109 {
1110 static struct in_addr host_addrs[MAXADDRS];
1111 char *p = line;
1112 char *cp, **q;
1113 char **hap;
1114 struct in_addr *buf;
1115 int more;
1116
1117 host.h_name = NULL;
1118 host.h_addr_list = h_addr_ptrs;
1119 host.h_length = sizeof(u_int32_t);
1120 host.h_addrtype = AF_INET;
1121 hap = h_addr_ptrs;
1122 buf = host_addrs;
1123 q = host.h_aliases = host_aliases;
1124
1125 /*
1126 * XXX: maybe support IPv6 parsing, based on 'af' setting
1127 */
1128 nextline:
1129 more = 0;
1130 cp = strpbrk(p, " \t");
1131 if (cp == NULL) {
1132 if (host.h_name == NULL)
1133 return (NULL);
1134 else
1135 goto done;
1136 }
1137 *cp++ = '\0';
1138
1139 *hap++ = (char *)(void *)buf;
1140 (void) inet_aton(p, buf++);
1141
1142 while (*cp == ' ' || *cp == '\t')
1143 cp++;
1144 p = cp;
1145 cp = strpbrk(p, " \t\n");
1146 if (cp != NULL) {
1147 if (*cp == '\n')
1148 more = 1;
1149 *cp++ = '\0';
1150 }
1151 if (!host.h_name)
1152 host.h_name = p;
1153 else if (strcmp(host.h_name, p)==0)
1154 ;
1155 else if (q < &host_aliases[MAXALIASES - 1])
1156 *q++ = p;
1157 p = cp;
1158 if (more)
1159 goto nextline;
1160
1161 while (cp && *cp) {
1162 if (*cp == ' ' || *cp == '\t') {
1163 cp++;
1164 continue;
1165 }
1166 if (*cp == '\n') {
1167 cp++;
1168 goto nextline;
1169 }
1170 if (q < &host_aliases[MAXALIASES - 1])
1171 *q++ = cp;
1172 cp = strpbrk(cp, " \t");
1173 if (cp != NULL)
1174 *cp++ = '\0';
1175 }
1176 done:
1177 *q = NULL;
1178 *hap = NULL;
1179 return (&host);
1180 }
1181
1182 /*ARGSUSED*/
1183 int
1184 _yp_gethtbyaddr(rv, cb_data, ap)
1185 void *rv;
1186 void *cb_data;
1187 va_list ap;
1188 {
1189 struct hostent *hp = (struct hostent *)NULL;
1190 static char *__ypcurrent;
1191 int __ypcurrentlen, r;
1192 char name[sizeof("xxx.xxx.xxx.xxx") + 1];
1193 const unsigned char *uaddr;
1194 int len, af;
1195
1196 uaddr = va_arg(ap, unsigned char *);
1197 len = va_arg(ap, int);
1198 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
1199 /*LINTED*/
1200 (void)(len ? &len : &len);
1201 #endif
1202 af = va_arg(ap, int);
1203
1204 if (!__ypdomain) {
1205 if (_yp_check(&__ypdomain) == 0)
1206 return NS_UNAVAIL;
1207 }
1208 /*
1209 * XXX: based on the value of af, it would be possible to lookup
1210 * IPv6 names in YP, by changing the following snprintf().
1211 * Is it worth it?
1212 */
1213 (void)snprintf(name, sizeof name, "%u.%u.%u.%u",
1214 (uaddr[0] & 0xff),
1215 (uaddr[1] & 0xff),
1216 (uaddr[2] & 0xff),
1217 (uaddr[3] & 0xff));
1218 if (__ypcurrent)
1219 free(__ypcurrent);
1220 __ypcurrent = NULL;
1221 r = yp_match(__ypdomain, "hosts.byaddr", name,
1222 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1223 if (r==0)
1224 hp = _yphostent(__ypcurrent, af);
1225 if (hp==NULL) {
1226 h_errno = HOST_NOT_FOUND;
1227 return NS_NOTFOUND;
1228 }
1229 *((struct hostent **)rv) = hp;
1230 return NS_SUCCESS;
1231 }
1232
1233 /*ARGSUSED*/
1234 int
1235 _yp_gethtbyname(rv, cb_data, ap)
1236 void *rv;
1237 void *cb_data;
1238 va_list ap;
1239 {
1240 struct hostent *hp = (struct hostent *)NULL;
1241 static char *__ypcurrent;
1242 int __ypcurrentlen, r;
1243 const char *name;
1244 int len, af;
1245
1246 name = va_arg(ap, char *);
1247 len = va_arg(ap, int);
1248 #if defined(__GNUC__) || defined(lint) /* to shut up gcc warnings */
1249 /*LINTED*/
1250 (void)(len ? &len : &len);
1251 #endif
1252 af = va_arg(ap, int);
1253
1254 if (!__ypdomain) {
1255 if (_yp_check(&__ypdomain) == 0)
1256 return NS_UNAVAIL;
1257 }
1258 if (__ypcurrent)
1259 free(__ypcurrent);
1260 __ypcurrent = NULL;
1261 r = yp_match(__ypdomain, "hosts.byname", name,
1262 (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
1263 if (r==0)
1264 hp = _yphostent(__ypcurrent, af);
1265 if (hp==NULL) {
1266 h_errno = HOST_NOT_FOUND;
1267 return NS_NOTFOUND;
1268 }
1269 *((struct hostent **)rv) = hp;
1270 return NS_SUCCESS;
1271 }
1272 #endif
1273