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 | #include <shlib-compat.h> |
58 | #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_25) |
59 | |
60 | # include <sys/types.h> |
61 | # include <sys/param.h> |
62 | # include <sys/socket.h> |
63 | # include <netinet/in.h> |
64 | # include <arpa/inet.h> |
65 | # include <arpa/nameser.h> |
66 | |
67 | # include <stdio.h> |
68 | # include <netdb.h> |
69 | # include <resolv/resolv-internal.h> |
70 | # include <resolv/resolv_context.h> |
71 | # include <ctype.h> |
72 | # include <errno.h> |
73 | # include <stdlib.h> |
74 | # include <string.h> |
75 | |
76 | # define MAXALIASES 35 |
77 | # define MAXADDRS 35 |
78 | |
79 | static char *h_addr_ptrs[MAXADDRS + 1]; |
80 | |
81 | static struct hostent host; |
82 | static char *host_aliases[MAXALIASES]; |
83 | static char hostbuf[8*1024]; |
84 | static u_char host_addr[16]; /* IPv4 or IPv6 */ |
85 | static FILE *hostf = NULL; |
86 | static int stayopen = 0; |
87 | |
88 | static struct hostent *res_gethostbyname2_context (struct resolv_context *, |
89 | const char *name, int af); |
90 | |
91 | static void map_v4v6_address (const char *src, char *dst) __THROW; |
92 | static void map_v4v6_hostent (struct hostent *hp, char **bp, int *len) __THROW; |
93 | |
94 | extern void addrsort (char **, int) __THROW; |
95 | |
96 | # if PACKETSZ > 65536 |
97 | # define MAXPACKET PACKETSZ |
98 | # else |
99 | # define MAXPACKET 65536 |
100 | # endif |
101 | |
102 | /* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */ |
103 | # ifdef MAXHOSTNAMELEN |
104 | # undef MAXHOSTNAMELEN |
105 | # endif |
106 | # define MAXHOSTNAMELEN 256 |
107 | |
108 | typedef union { |
109 | HEADER hdr; |
110 | u_char buf[MAXPACKET]; |
111 | } querybuf; |
112 | |
113 | typedef union { |
114 | int32_t al; |
115 | char ac; |
116 | } align; |
117 | |
118 | # ifndef h_errno |
119 | extern int h_errno; |
120 | # endif |
121 | |
122 | # define BOUNDED_INCR(x) \ |
123 | do { \ |
124 | cp += x; \ |
125 | if (cp > eom) { \ |
126 | __set_h_errno (NO_RECOVERY); \ |
127 | return (NULL); \ |
128 | } \ |
129 | } while (0) |
130 | |
131 | # define BOUNDS_CHECK(ptr, count) \ |
132 | do { \ |
133 | if ((ptr) + (count) > eom) { \ |
134 | __set_h_errno (NO_RECOVERY); \ |
135 | return (NULL); \ |
136 | } \ |
137 | } while (0) |
138 | |
139 | |
140 | static struct hostent * |
141 | getanswer (const querybuf *answer, int anslen, const char *qname, int qtype) |
142 | { |
143 | const HEADER *hp; |
144 | const u_char *cp; |
145 | int n; |
146 | const u_char *eom, *erdata; |
147 | char *bp, **ap, **hap; |
148 | int type, class, buflen, ancount, qdcount; |
149 | int haveanswer, had_error; |
150 | char tbuf[MAXDNAME]; |
151 | const char *tname; |
152 | int (*name_ok) (const char *); |
153 | |
154 | tname = qname; |
155 | host.h_name = NULL; |
156 | eom = answer->buf + anslen; |
157 | switch (qtype) { |
158 | case T_A: |
159 | case T_AAAA: |
160 | name_ok = res_hnok; |
161 | break; |
162 | case T_PTR: |
163 | name_ok = res_dnok; |
164 | break; |
165 | default: |
166 | return (NULL); /* XXX should be abort(); */ |
167 | } |
168 | /* |
169 | * find first satisfactory answer |
170 | */ |
171 | hp = &answer->hdr; |
172 | ancount = ntohs(hp->ancount); |
173 | qdcount = ntohs(hp->qdcount); |
174 | bp = hostbuf; |
175 | buflen = sizeof hostbuf; |
176 | cp = answer->buf; |
177 | BOUNDED_INCR(HFIXEDSZ); |
178 | if (qdcount != 1) { |
179 | __set_h_errno (NO_RECOVERY); |
180 | return (NULL); |
181 | } |
182 | n = __libc_dn_expand (answer->buf, eom, cp, bp, buflen); |
183 | if ((n < 0) || !(*name_ok)(bp)) { |
184 | __set_h_errno (NO_RECOVERY); |
185 | return (NULL); |
186 | } |
187 | BOUNDED_INCR(n + QFIXEDSZ); |
188 | if (qtype == T_A || qtype == T_AAAA) { |
189 | /* res_send() has already verified that the query name is the |
190 | * same as the one we sent; this just gets the expanded name |
191 | * (i.e., with the succeeding search-domain tacked on). |
192 | */ |
193 | n = strlen(bp) + 1; /* for the \0 */ |
194 | if (n >= MAXHOSTNAMELEN) { |
195 | __set_h_errno (NO_RECOVERY); |
196 | return (NULL); |
197 | } |
198 | host.h_name = bp; |
199 | bp += n; |
200 | buflen -= n; |
201 | /* The qname can be abbreviated, but h_name is now absolute. */ |
202 | qname = host.h_name; |
203 | } |
204 | ap = host_aliases; |
205 | *ap = NULL; |
206 | host.h_aliases = host_aliases; |
207 | hap = h_addr_ptrs; |
208 | *hap = NULL; |
209 | host.h_addr_list = h_addr_ptrs; |
210 | haveanswer = 0; |
211 | had_error = 0; |
212 | while (ancount-- > 0 && cp < eom && !had_error) { |
213 | n = __libc_dn_expand (answer->buf, eom, cp, bp, buflen); |
214 | if ((n < 0) || !(*name_ok)(bp)) { |
215 | had_error++; |
216 | continue; |
217 | } |
218 | cp += n; /* name */ |
219 | BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); |
220 | type = ns_get16(cp); |
221 | cp += INT16SZ; /* type */ |
222 | class = ns_get16(cp); |
223 | cp += INT16SZ + INT32SZ; /* class, TTL */ |
224 | n = ns_get16(cp); |
225 | cp += INT16SZ; /* len */ |
226 | BOUNDS_CHECK(cp, n); |
227 | erdata = cp + n; |
228 | if (class != C_IN) { |
229 | /* XXX - debug? syslog? */ |
230 | cp += n; |
231 | continue; /* XXX - had_error++ ? */ |
232 | } |
233 | if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { |
234 | if (ap >= &host_aliases[MAXALIASES-1]) |
235 | continue; |
236 | n = __libc_dn_expand (answer->buf, eom, cp, |
237 | tbuf, sizeof tbuf); |
238 | if ((n < 0) || !(*name_ok)(tbuf)) { |
239 | had_error++; |
240 | continue; |
241 | } |
242 | cp += n; |
243 | if (cp != erdata) { |
244 | __set_h_errno (NO_RECOVERY); |
245 | return (NULL); |
246 | } |
247 | /* Store alias. */ |
248 | *ap++ = bp; |
249 | n = strlen(bp) + 1; /* for the \0 */ |
250 | if (n >= MAXHOSTNAMELEN) { |
251 | had_error++; |
252 | continue; |
253 | } |
254 | bp += n; |
255 | buflen -= n; |
256 | /* Get canonical name. */ |
257 | n = strlen(tbuf) + 1; /* for the \0 */ |
258 | if (n > buflen || n >= MAXHOSTNAMELEN) { |
259 | had_error++; |
260 | continue; |
261 | } |
262 | strcpy(bp, tbuf); |
263 | host.h_name = bp; |
264 | bp += n; |
265 | buflen -= n; |
266 | continue; |
267 | } |
268 | if (qtype == T_PTR && type == T_CNAME) { |
269 | n = __libc_dn_expand (answer->buf, eom, cp, |
270 | tbuf, sizeof tbuf); |
271 | if (n < 0 || !res_dnok(tbuf)) { |
272 | had_error++; |
273 | continue; |
274 | } |
275 | cp += n; |
276 | if (cp != erdata) { |
277 | __set_h_errno (NO_RECOVERY); |
278 | return (NULL); |
279 | } |
280 | /* Get canonical name. */ |
281 | n = strlen(tbuf) + 1; /* for the \0 */ |
282 | if (n > buflen || n >= MAXHOSTNAMELEN) { |
283 | had_error++; |
284 | continue; |
285 | } |
286 | strcpy(bp, tbuf); |
287 | tname = bp; |
288 | bp += n; |
289 | buflen -= n; |
290 | continue; |
291 | } |
292 | if (type != qtype) { |
293 | /* Log a low priority message if we get an unexpected |
294 | * record, but skip it if we are using DNSSEC since it |
295 | * uses many different types in responses that do not |
296 | * match QTYPE. |
297 | */ |
298 | cp += n; |
299 | continue; /* XXX - had_error++ ? */ |
300 | } |
301 | switch (type) { |
302 | case T_PTR: |
303 | if (strcasecmp(tname, bp) != 0) { |
304 | cp += n; |
305 | continue; /* XXX - had_error++ ? */ |
306 | } |
307 | n = __libc_dn_expand (answer->buf, eom, cp, |
308 | bp, buflen); |
309 | if ((n < 0) || !res_hnok(bp)) { |
310 | had_error++; |
311 | break; |
312 | } |
313 | cp += n; |
314 | if (cp != erdata) { |
315 | __set_h_errno (NO_RECOVERY); |
316 | return (NULL); |
317 | } |
318 | if (!haveanswer) |
319 | host.h_name = bp; |
320 | else if (ap < &host_aliases[MAXALIASES-1]) |
321 | *ap++ = bp; |
322 | else |
323 | n = -1; |
324 | if (n != -1) { |
325 | n = strlen(bp) + 1; /* for the \0 */ |
326 | if (n >= MAXHOSTNAMELEN) { |
327 | had_error++; |
328 | break; |
329 | } |
330 | bp += n; |
331 | buflen -= n; |
332 | } |
333 | break; |
334 | case T_A: |
335 | case T_AAAA: |
336 | if (strcasecmp(host.h_name, bp) != 0) { |
337 | cp += n; |
338 | continue; /* XXX - had_error++ ? */ |
339 | } |
340 | if (n != host.h_length) { |
341 | cp += n; |
342 | continue; |
343 | } |
344 | if (!haveanswer) { |
345 | int nn; |
346 | |
347 | host.h_name = bp; |
348 | nn = strlen(bp) + 1; /* for the \0 */ |
349 | bp += nn; |
350 | buflen -= nn; |
351 | } |
352 | |
353 | /* XXX: when incrementing bp, we have to decrement |
354 | * buflen by the same amount --okir */ |
355 | buflen -= sizeof(align) - ((u_long)bp % sizeof(align)); |
356 | |
357 | bp += sizeof(align) - ((u_long)bp % sizeof(align)); |
358 | |
359 | if (bp + n >= &hostbuf[sizeof hostbuf]) { |
360 | had_error++; |
361 | continue; |
362 | } |
363 | if (hap >= &h_addr_ptrs[MAXADDRS-1]) { |
364 | cp += n; |
365 | continue; |
366 | } |
367 | memmove(*hap++ = bp, cp, n); |
368 | bp += n; |
369 | buflen -= n; |
370 | cp += n; |
371 | if (cp != erdata) { |
372 | __set_h_errno (NO_RECOVERY); |
373 | return (NULL); |
374 | } |
375 | break; |
376 | default: |
377 | abort(); |
378 | } |
379 | if (!had_error) |
380 | haveanswer++; |
381 | } |
382 | if (haveanswer) { |
383 | *ap = NULL; |
384 | *hap = NULL; |
385 | /* |
386 | * Note: we sort even if host can take only one address |
387 | * in its return structures - should give it the "best" |
388 | * address in that case, not some random one |
389 | */ |
390 | if (_res.nsort && haveanswer > 1 && qtype == T_A) |
391 | addrsort(h_addr_ptrs, haveanswer); |
392 | if (!host.h_name) { |
393 | n = strlen(qname) + 1; /* for the \0 */ |
394 | if (n > buflen || n >= MAXHOSTNAMELEN) |
395 | goto no_recovery; |
396 | strcpy(bp, qname); |
397 | host.h_name = bp; |
398 | bp += n; |
399 | buflen -= n; |
400 | } |
401 | if (res_use_inet6 ()) |
402 | map_v4v6_hostent(&host, &bp, &buflen); |
403 | __set_h_errno (NETDB_SUCCESS); |
404 | return (&host); |
405 | } |
406 | no_recovery: |
407 | __set_h_errno (NO_RECOVERY); |
408 | return (NULL); |
409 | } |
410 | |
411 | extern struct hostent *res_gethostbyname2(const char *name, int af); |
412 | libresolv_hidden_proto (res_gethostbyname2) |
413 | |
414 | struct hostent * |
415 | res_gethostbyname (const char *name) |
416 | { |
417 | struct resolv_context *ctx = __resolv_context_get (); |
418 | if (ctx == NULL) |
419 | { |
420 | __set_h_errno (NETDB_INTERNAL); |
421 | return NULL; |
422 | } |
423 | |
424 | if (res_use_inet6 ()) |
425 | { |
426 | struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET6); |
427 | if (hp != NULL) |
428 | { |
429 | __resolv_context_put (ctx); |
430 | return hp; |
431 | } |
432 | } |
433 | struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET); |
434 | __resolv_context_put (ctx); |
435 | return hp; |
436 | } |
437 | compat_symbol (libresolv, res_gethostbyname, res_gethostbyname, GLIBC_2_0); |
438 | |
439 | static struct hostent * |
440 | res_gethostbyname2_context (struct resolv_context *ctx, |
441 | const char *name, int af) |
442 | { |
443 | union |
444 | { |
445 | querybuf *buf; |
446 | u_char *ptr; |
447 | } buf; |
448 | querybuf *origbuf; |
449 | const char *cp; |
450 | char *bp; |
451 | int n, size, type, len; |
452 | struct hostent *ret; |
453 | |
454 | switch (af) { |
455 | case AF_INET: |
456 | size = INADDRSZ; |
457 | type = T_A; |
458 | break; |
459 | case AF_INET6: |
460 | size = IN6ADDRSZ; |
461 | type = T_AAAA; |
462 | break; |
463 | default: |
464 | __set_h_errno (NETDB_INTERNAL); |
465 | __set_errno (EAFNOSUPPORT); |
466 | return (NULL); |
467 | } |
468 | |
469 | host.h_addrtype = af; |
470 | host.h_length = size; |
471 | |
472 | /* |
473 | * if there aren't any dots, it could be a user-level alias. |
474 | * this is also done in res_query() since we are not the only |
475 | * function that looks up host names. |
476 | */ |
477 | char abuf[MAXDNAME]; |
478 | if (strchr (name, '.') != NULL |
479 | && (cp = __res_context_hostalias (ctx, name, abuf, sizeof (abuf)))) |
480 | name = cp; |
481 | |
482 | /* |
483 | * disallow names consisting only of digits/dots, unless |
484 | * they end in a dot. |
485 | */ |
486 | if (isdigit(name[0])) |
487 | for (cp = name;; ++cp) { |
488 | if (!*cp) { |
489 | if (*--cp == '.') |
490 | break; |
491 | /* |
492 | * All-numeric, no dot at the end. |
493 | * Fake up a hostent as if we'd actually |
494 | * done a lookup. |
495 | */ |
496 | if (inet_pton(af, name, host_addr) <= 0) { |
497 | __set_h_errno (HOST_NOT_FOUND); |
498 | return (NULL); |
499 | } |
500 | strncpy(hostbuf, name, MAXDNAME); |
501 | hostbuf[MAXDNAME] = '\0'; |
502 | bp = hostbuf + MAXDNAME; |
503 | len = sizeof hostbuf - MAXDNAME; |
504 | host.h_name = hostbuf; |
505 | host.h_aliases = host_aliases; |
506 | host_aliases[0] = NULL; |
507 | h_addr_ptrs[0] = (char *)host_addr; |
508 | h_addr_ptrs[1] = NULL; |
509 | host.h_addr_list = h_addr_ptrs; |
510 | if (res_use_inet6 ()) |
511 | map_v4v6_hostent(&host, &bp, &len); |
512 | __set_h_errno (NETDB_SUCCESS); |
513 | return (&host); |
514 | } |
515 | if (!isdigit(*cp) && *cp != '.') |
516 | break; |
517 | } |
518 | if ((isxdigit(name[0]) && strchr(name, ':') != NULL) || |
519 | name[0] == ':') |
520 | for (cp = name;; ++cp) { |
521 | if (!*cp) { |
522 | if (*--cp == '.') |
523 | break; |
524 | /* |
525 | * All-IPv6-legal, no dot at the end. |
526 | * Fake up a hostent as if we'd actually |
527 | * done a lookup. |
528 | */ |
529 | if (inet_pton(af, name, host_addr) <= 0) { |
530 | __set_h_errno (HOST_NOT_FOUND); |
531 | return (NULL); |
532 | } |
533 | strncpy(hostbuf, name, MAXDNAME); |
534 | hostbuf[MAXDNAME] = '\0'; |
535 | bp = hostbuf + MAXDNAME; |
536 | len = sizeof hostbuf - MAXDNAME; |
537 | host.h_name = hostbuf; |
538 | host.h_aliases = host_aliases; |
539 | host_aliases[0] = NULL; |
540 | h_addr_ptrs[0] = (char *)host_addr; |
541 | h_addr_ptrs[1] = NULL; |
542 | host.h_addr_list = h_addr_ptrs; |
543 | __set_h_errno (NETDB_SUCCESS); |
544 | return (&host); |
545 | } |
546 | if (!isxdigit(*cp) && *cp != ':' && *cp != '.') |
547 | break; |
548 | } |
549 | |
550 | buf.buf = origbuf = (querybuf *) alloca (1024); |
551 | |
552 | if ((n = __res_context_search |
553 | (ctx, name, C_IN, type, buf.buf->buf, 1024, |
554 | &buf.ptr, NULL, NULL, NULL, NULL)) < 0) { |
555 | if (buf.buf != origbuf) |
556 | free (buf.buf); |
557 | if (errno == ECONNREFUSED) |
558 | return (_gethtbyname2(name, af)); |
559 | return (NULL); |
560 | } |
561 | ret = getanswer(buf.buf, n, name, type); |
562 | if (buf.buf != origbuf) |
563 | free (buf.buf); |
564 | return ret; |
565 | } |
566 | |
567 | struct hostent * |
568 | res_gethostbyname2 (const char *name, int af) |
569 | { |
570 | struct resolv_context *ctx = __resolv_context_get (); |
571 | if (ctx == NULL) |
572 | { |
573 | __set_h_errno (NETDB_INTERNAL); |
574 | return NULL; |
575 | } |
576 | struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET); |
577 | __resolv_context_put (ctx); |
578 | return hp; |
579 | } |
580 | libresolv_hidden_def (res_gethostbyname2) |
581 | compat_symbol (libresolv, res_gethostbyname2, res_gethostbyname2, GLIBC_2_0); |
582 | |
583 | static struct hostent * |
584 | res_gethostbyaddr_context (struct resolv_context *ctx, |
585 | const void *addr, socklen_t len, int af) |
586 | { |
587 | const u_char *uaddr = (const u_char *)addr; |
588 | static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; |
589 | static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; |
590 | int n; |
591 | socklen_t size; |
592 | union |
593 | { |
594 | querybuf *buf; |
595 | u_char *ptr; |
596 | } buf; |
597 | querybuf *orig_buf; |
598 | struct hostent *hp; |
599 | char qbuf[MAXDNAME+1], *qp = NULL; |
600 | |
601 | if (af == AF_INET6 && len == IN6ADDRSZ && |
602 | (!memcmp(uaddr, mapped, sizeof mapped) || |
603 | !memcmp(uaddr, tunnelled, sizeof tunnelled))) { |
604 | /* Unmap. */ |
605 | addr += sizeof mapped; |
606 | uaddr += sizeof mapped; |
607 | af = AF_INET; |
608 | len = INADDRSZ; |
609 | } |
610 | switch (af) { |
611 | case AF_INET: |
612 | size = INADDRSZ; |
613 | break; |
614 | case AF_INET6: |
615 | size = IN6ADDRSZ; |
616 | break; |
617 | default: |
618 | __set_errno (EAFNOSUPPORT); |
619 | __set_h_errno (NETDB_INTERNAL); |
620 | return (NULL); |
621 | } |
622 | if (size != len) { |
623 | __set_errno (EINVAL); |
624 | __set_h_errno (NETDB_INTERNAL); |
625 | return (NULL); |
626 | } |
627 | switch (af) { |
628 | case AF_INET: |
629 | (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa" , |
630 | (uaddr[3] & 0xff), |
631 | (uaddr[2] & 0xff), |
632 | (uaddr[1] & 0xff), |
633 | (uaddr[0] & 0xff)); |
634 | break; |
635 | case AF_INET6: |
636 | qp = qbuf; |
637 | for (n = IN6ADDRSZ - 1; n >= 0; n--) { |
638 | qp += sprintf(qp, "%x.%x." , |
639 | uaddr[n] & 0xf, |
640 | (uaddr[n] >> 4) & 0xf); |
641 | } |
642 | strcpy(qp, "ip6.arpa" ); |
643 | break; |
644 | default: |
645 | abort(); |
646 | } |
647 | |
648 | buf.buf = orig_buf = (querybuf *) alloca (1024); |
649 | |
650 | n = __res_context_query (ctx, qbuf, C_IN, T_PTR, buf.buf->buf, 1024, |
651 | &buf.ptr, NULL, NULL, NULL, NULL); |
652 | if (n < 0) { |
653 | if (buf.buf != orig_buf) |
654 | free (buf.buf); |
655 | if (errno == ECONNREFUSED) |
656 | return (_gethtbyaddr(addr, len, af)); |
657 | return (NULL); |
658 | } |
659 | hp = getanswer(buf.buf, n, qbuf, T_PTR); |
660 | if (buf.buf != orig_buf) |
661 | free (buf.buf); |
662 | if (!hp) |
663 | return (NULL); /* h_errno was set by getanswer() */ |
664 | hp->h_addrtype = af; |
665 | hp->h_length = len; |
666 | memmove(host_addr, addr, len); |
667 | h_addr_ptrs[0] = (char *)host_addr; |
668 | h_addr_ptrs[1] = NULL; |
669 | if (af == AF_INET && res_use_inet6 ()) { |
670 | map_v4v6_address((char*)host_addr, (char*)host_addr); |
671 | hp->h_addrtype = AF_INET6; |
672 | hp->h_length = IN6ADDRSZ; |
673 | } |
674 | __set_h_errno (NETDB_SUCCESS); |
675 | return (hp); |
676 | } |
677 | |
678 | struct hostent * |
679 | res_gethostbyaddr (const void *addr, socklen_t len, int af) |
680 | { |
681 | struct resolv_context *ctx = __resolv_context_get (); |
682 | if (ctx == NULL) |
683 | { |
684 | __set_h_errno (NETDB_INTERNAL); |
685 | return NULL; |
686 | } |
687 | struct hostent *hp = res_gethostbyaddr_context (ctx, addr, len, af); |
688 | __resolv_context_put (ctx); |
689 | return hp; |
690 | } |
691 | compat_symbol (libresolv, res_gethostbyaddr, res_gethostbyaddr, GLIBC_2_0); |
692 | |
693 | void |
694 | _sethtent (int f) |
695 | { |
696 | if (!hostf) |
697 | hostf = fopen(_PATH_HOSTS, "rce" ); |
698 | else |
699 | rewind(hostf); |
700 | stayopen = f; |
701 | } |
702 | libresolv_hidden_def (_sethtent) |
703 | compat_symbol (libresolv, _sethtent, _sethtent, GLIBC_2_0); |
704 | |
705 | static void |
706 | _endhtent (void) |
707 | { |
708 | if (hostf && !stayopen) { |
709 | (void) fclose(hostf); |
710 | hostf = NULL; |
711 | } |
712 | } |
713 | |
714 | struct hostent * |
715 | _gethtent (void) |
716 | { |
717 | char *p; |
718 | char *cp, **q; |
719 | int af, len; |
720 | |
721 | if (!hostf && !(hostf = fopen(_PATH_HOSTS, "rce" ))) { |
722 | __set_h_errno (NETDB_INTERNAL); |
723 | return (NULL); |
724 | } |
725 | again: |
726 | if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { |
727 | __set_h_errno (HOST_NOT_FOUND); |
728 | return (NULL); |
729 | } |
730 | if (*p == '#') |
731 | goto again; |
732 | if (!(cp = strpbrk(p, "#\n" ))) |
733 | goto again; |
734 | *cp = '\0'; |
735 | if (!(cp = strpbrk(p, " \t" ))) |
736 | goto again; |
737 | *cp++ = '\0'; |
738 | if (inet_pton(AF_INET6, p, host_addr) > 0) { |
739 | af = AF_INET6; |
740 | len = IN6ADDRSZ; |
741 | } else if (inet_pton(AF_INET, p, host_addr) > 0) { |
742 | if (res_use_inet6 ()) { |
743 | map_v4v6_address((char*)host_addr, (char*)host_addr); |
744 | af = AF_INET6; |
745 | len = IN6ADDRSZ; |
746 | } else { |
747 | af = AF_INET; |
748 | len = INADDRSZ; |
749 | } |
750 | } else { |
751 | goto again; |
752 | } |
753 | h_addr_ptrs[0] = (char *)host_addr; |
754 | h_addr_ptrs[1] = NULL; |
755 | host.h_addr_list = h_addr_ptrs; |
756 | host.h_length = len; |
757 | host.h_addrtype = af; |
758 | while (*cp == ' ' || *cp == '\t') |
759 | cp++; |
760 | host.h_name = cp; |
761 | q = host.h_aliases = host_aliases; |
762 | if ((cp = strpbrk(cp, " \t" ))) |
763 | *cp++ = '\0'; |
764 | while (cp && *cp) { |
765 | if (*cp == ' ' || *cp == '\t') { |
766 | cp++; |
767 | continue; |
768 | } |
769 | if (q < &host_aliases[MAXALIASES - 1]) |
770 | *q++ = cp; |
771 | if ((cp = strpbrk(cp, " \t" ))) |
772 | *cp++ = '\0'; |
773 | } |
774 | *q = NULL; |
775 | __set_h_errno (NETDB_SUCCESS); |
776 | return (&host); |
777 | } |
778 | libresolv_hidden_def (_gethtent) |
779 | compat_symbol (libresolv, _gethtent, _gethtent, GLIBC_2_0); |
780 | |
781 | struct hostent * |
782 | _gethtbyname (const char *name) |
783 | { |
784 | struct hostent *hp; |
785 | |
786 | if (res_use_inet6 ()) { |
787 | hp = _gethtbyname2(name, AF_INET6); |
788 | if (hp) |
789 | return (hp); |
790 | } |
791 | return (_gethtbyname2(name, AF_INET)); |
792 | } |
793 | compat_symbol (libresolv, _gethtbyname, _gethtbyname, GLIBC_2_0); |
794 | |
795 | struct hostent * |
796 | _gethtbyname2 (const char *name, int af) |
797 | { |
798 | struct hostent *p; |
799 | char **cp; |
800 | |
801 | _sethtent(0); |
802 | while ((p = _gethtent())) { |
803 | if (p->h_addrtype != af) |
804 | continue; |
805 | if (strcasecmp(p->h_name, name) == 0) |
806 | break; |
807 | for (cp = p->h_aliases; *cp != 0; cp++) |
808 | if (strcasecmp(*cp, name) == 0) |
809 | goto found; |
810 | } |
811 | found: |
812 | _endhtent(); |
813 | return (p); |
814 | } |
815 | libresolv_hidden_def (_gethtbyname2) |
816 | compat_symbol (libresolv, _gethtbyname2, _gethtbyname2, GLIBC_2_0); |
817 | |
818 | struct hostent * |
819 | _gethtbyaddr (const char *addr, size_t len, int af) |
820 | { |
821 | struct hostent *p; |
822 | |
823 | _sethtent(0); |
824 | while ((p = _gethtent())) |
825 | if (p->h_addrtype == af && !memcmp(p->h_addr, addr, len)) |
826 | break; |
827 | _endhtent(); |
828 | return (p); |
829 | } |
830 | libresolv_hidden_def (_gethtbyaddr) |
831 | compat_symbol (libresolv, _gethtbyaddr, _gethtbyaddr, GLIBC_2_0); |
832 | |
833 | static void |
834 | map_v4v6_address (const char *src, char *dst) |
835 | { |
836 | u_char *p = (u_char *)dst; |
837 | char tmp[INADDRSZ]; |
838 | int i; |
839 | |
840 | /* Stash a temporary copy so our caller can update in place. */ |
841 | memcpy(tmp, src, INADDRSZ); |
842 | /* Mark this ipv6 addr as a mapped ipv4. */ |
843 | for (i = 0; i < 10; i++) |
844 | *p++ = 0x00; |
845 | *p++ = 0xff; |
846 | *p++ = 0xff; |
847 | /* Retrieve the saved copy and we're done. */ |
848 | memcpy((void*)p, tmp, INADDRSZ); |
849 | } |
850 | |
851 | static void |
852 | map_v4v6_hostent (struct hostent *hp, char **bpp, 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) - ((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 | extern void |
878 | addrsort (char **ap, int num) |
879 | { |
880 | int i, j; |
881 | char **p; |
882 | short aval[MAXADDRS]; |
883 | int needsort = 0; |
884 | |
885 | p = ap; |
886 | for (i = 0; i < num; i++, p++) { |
887 | for (j = 0 ; (unsigned)j < _res.nsort; j++) |
888 | if (_res.sort_list[j].addr.s_addr == |
889 | (((struct in_addr *)(*p))->s_addr & _res.sort_list[j].mask)) |
890 | break; |
891 | aval[i] = j; |
892 | if (needsort == 0 && i > 0 && j < aval[i-1]) |
893 | needsort = i; |
894 | } |
895 | if (!needsort) |
896 | return; |
897 | |
898 | while (needsort < num) { |
899 | for (j = needsort - 1; j >= 0; j--) { |
900 | if (aval[j] > aval[j+1]) { |
901 | char *hp; |
902 | |
903 | i = aval[j]; |
904 | aval[j] = aval[j+1]; |
905 | aval[j+1] = i; |
906 | |
907 | hp = ap[j]; |
908 | ap[j] = ap[j+1]; |
909 | ap[j+1] = hp; |
910 | |
911 | } else |
912 | break; |
913 | } |
914 | needsort++; |
915 | } |
916 | } |
917 | |
918 | #endif /* SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25) */ |
919 | |