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*/ |
1044 | |