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