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