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