2 * Copyright (c) 1994, Garrett Wollman
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * $FreeBSD: src/lib/libc/net/gethostnamadr.c,v 1.33 2006/05/21 11:27:28 ume Exp $
28 #include "namespace.h"
29 #include "reentrant.h"
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
42 #include <arpa/nameser.h> /* XXX hack for _res */
43 #include <resolv.h> /* XXX hack for _res */
44 #include "un-namespace.h"
45 #include "netdb_private.h"
50 static int gethostbyname_internal(const char *, int, struct hostent
*, char *,
51 size_t, struct hostent
**, int *, res_state
);
53 /* Host lookup order if nsswitch.conf is broken or nonexistant */
54 static const ns_src default_src
[] = {
55 { NSSRC_FILES
, NS_SUCCESS
},
56 { NSSRC_DNS
, NS_SUCCESS
},
60 static int host_id_func(char *, size_t *, va_list, void *);
61 static int host_marshal_func(char *, size_t *, void *, va_list, void *);
62 static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
65 NETDB_THREAD_ALLOC(hostent
)
66 NETDB_THREAD_ALLOC(hostent_data
)
67 NETDB_THREAD_ALLOC(hostdata
)
70 hostent_free(void *ptr
)
76 hostent_data_free(void *ptr
)
78 struct hostent_data
*hed
= ptr
;
88 hostdata_free(void *ptr
)
94 __copy_hostent(struct hostent
*he
, struct hostent
*hptr
, char *buf
,
102 /* Find out the amount of space required to store the answer. */
103 nptr
= 2; /* NULL ptrs */
104 len
= (char *)ALIGN(buf
) - buf
;
105 for (i
= 0; he
->h_addr_list
[i
]; i
++, nptr
++) {
108 for (i
= 0; he
->h_aliases
[i
]; i
++, nptr
++) {
109 len
+= strlen(he
->h_aliases
[i
]) + 1;
111 len
+= strlen(he
->h_name
) + 1;
112 len
+= nptr
* sizeof(char*);
119 /* copy address size and type */
120 hptr
->h_addrtype
= he
->h_addrtype
;
121 n
= hptr
->h_length
= he
->h_length
;
123 ptr
= (char **)ALIGN(buf
);
124 cp
= (char *)ALIGN(buf
) + nptr
* sizeof(char *);
126 /* copy address list */
127 hptr
->h_addr_list
= ptr
;
128 for (i
= 0; he
->h_addr_list
[i
]; i
++ , ptr
++) {
129 memcpy(cp
, he
->h_addr_list
[i
], n
);
130 hptr
->h_addr_list
[i
] = cp
;
133 hptr
->h_addr_list
[i
] = NULL
;
136 /* copy official name */
137 n
= strlen(he
->h_name
) + 1;
138 strcpy(cp
, he
->h_name
);
143 hptr
->h_aliases
= ptr
;
144 for (i
= 0 ; he
->h_aliases
[i
]; i
++) {
145 n
= strlen(he
->h_aliases
[i
]) + 1;
146 strcpy(cp
, he
->h_aliases
[i
]);
147 hptr
->h_aliases
[i
] = cp
;
150 hptr
->h_aliases
[i
] = NULL
;
157 host_id_func(char *buffer
, size_t *buffer_size
, va_list ap
, void *cache_mdata
)
168 size_t desired_size
, size
;
169 enum nss_lookup_type lookup_type
;
171 int res
= NS_UNAVAIL
;
173 statp
= __res_state();
174 res_options
= statp
->options
& (RES_RECURSE
| RES_DEFNAMES
|
175 RES_DNSRCH
| RES_NOALIASES
| RES_USE_INET6
);
177 lookup_type
= (enum nss_lookup_type
)cache_mdata
;
178 switch (lookup_type
) {
180 str
= va_arg(ap
, char *);
181 type
= va_arg(ap
, int);
184 desired_size
= sizeof(res_options
) + sizeof(int) +
185 sizeof(enum nss_lookup_type
) + sizeof(int) + size
+ 1;
187 if (desired_size
> *buffer_size
) {
194 memcpy(p
, &res_options
, sizeof(res_options
));
195 p
+= sizeof(res_options
);
197 memcpy(p
, &op_id
, sizeof(int));
200 memcpy(p
, &lookup_type
, sizeof(enum nss_lookup_type
));
203 memcpy(p
, &type
, sizeof(int));
206 memcpy(p
, str
, size
+ 1);
211 addr
= va_arg(ap
, void *);
212 len
= va_arg(ap
, socklen_t
);
213 type
= va_arg(ap
, int);
215 desired_size
= sizeof(res_options
) + sizeof(int) +
216 sizeof(enum nss_lookup_type
) + sizeof(int) +
217 sizeof(socklen_t
) + len
;
219 if (desired_size
> *buffer_size
) {
225 memcpy(p
, &res_options
, sizeof(res_options
));
226 p
+= sizeof(res_options
);
228 memcpy(p
, &op_id
, sizeof(int));
231 memcpy(p
, &lookup_type
, sizeof(enum nss_lookup_type
));
234 memcpy(p
, &type
, sizeof(int));
237 memcpy(p
, &len
, sizeof(socklen_t
));
238 p
+= sizeof(socklen_t
);
240 memcpy(p
, addr
, len
);
245 /* should be unreachable */
250 *buffer_size
= desired_size
;
255 host_marshal_func(char *buffer
, size_t *buffer_size
, void *retval __unused
,
256 va_list ap
, void *cache_mdata
)
260 socklen_t len __unused
;
264 struct hostent new_ht
;
265 size_t desired_size
, aliases_size
, addr_size
, size
;
268 switch ((enum nss_lookup_type
)cache_mdata
) {
270 str
= va_arg(ap
, char *);
271 type
= va_arg(ap
, int);
274 addr
= va_arg(ap
, void *);
275 len
= va_arg(ap
, socklen_t
);
276 type
= va_arg(ap
, int);
279 /* should be unreachable */
282 ht
= va_arg(ap
, struct hostent
*);
284 desired_size
= _ALIGNBYTES
+ sizeof(struct hostent
) + sizeof(char *);
285 if (ht
->h_name
!= NULL
)
286 desired_size
+= strlen(ht
->h_name
) + 1;
288 if (ht
->h_aliases
!= NULL
) {
290 for (iter
= ht
->h_aliases
; *iter
; ++iter
) {
291 desired_size
+= strlen(*iter
) + 1;
295 desired_size
+= _ALIGNBYTES
+
296 (aliases_size
+ 1) * sizeof(char *);
299 if (ht
->h_addr_list
!= NULL
) {
301 for (iter
= ht
->h_addr_list
; *iter
; ++iter
)
304 desired_size
+= addr_size
* _ALIGN(ht
->h_length
);
305 desired_size
+= _ALIGNBYTES
+ (addr_size
+ 1) * sizeof(char *);
308 if (desired_size
> *buffer_size
) {
309 /* this assignment is here for future use */
310 *buffer_size
= desired_size
;
314 memcpy(&new_ht
, ht
, sizeof(struct hostent
));
315 memset(buffer
, 0, desired_size
);
317 *buffer_size
= desired_size
;
318 p
= buffer
+ sizeof(struct hostent
) + sizeof(char *);
319 memcpy(buffer
+ sizeof(struct hostent
), &p
, sizeof(char *));
320 p
= (char *)_ALIGN(p
);
322 if (new_ht
.h_name
!= NULL
) {
323 size
= strlen(new_ht
.h_name
);
324 memcpy(p
, new_ht
.h_name
, size
);
329 if (new_ht
.h_aliases
!= NULL
) {
330 p
= (char *)_ALIGN(p
);
331 memcpy(p
, new_ht
.h_aliases
, sizeof(char *) * aliases_size
);
332 new_ht
.h_aliases
= (char **)p
;
333 p
+= sizeof(char *) * (aliases_size
+ 1);
335 for (iter
= new_ht
.h_aliases
; *iter
; ++iter
) {
336 size
= strlen(*iter
);
337 memcpy(p
, *iter
, size
);
343 if (new_ht
.h_addr_list
!= NULL
) {
344 p
= (char *)_ALIGN(p
);
345 memcpy(p
, new_ht
.h_addr_list
, sizeof(char *) * addr_size
);
346 new_ht
.h_addr_list
= (char **)p
;
347 p
+= sizeof(char *) * (addr_size
+ 1);
349 size
= _ALIGN(new_ht
.h_length
);
350 for (iter
= new_ht
.h_addr_list
; *iter
; ++iter
) {
351 memcpy(p
, *iter
, size
);
356 memcpy(buffer
, &new_ht
, sizeof(struct hostent
));
361 host_unmarshal_func(char *buffer
, size_t buffer_size
, void *retval
, va_list ap
,
366 socklen_t len __unused
;
373 size_t orig_buf_size
;
375 switch ((enum nss_lookup_type
)cache_mdata
) {
377 str
= va_arg(ap
, char *);
378 type
= va_arg(ap
, int);
381 addr
= va_arg(ap
, void *);
382 len
= va_arg(ap
, socklen_t
);
383 type
= va_arg(ap
, int);
386 /* should be unreachable */
390 ht
= va_arg(ap
, struct hostent
*);
391 orig_buf
= va_arg(ap
, char *);
392 orig_buf_size
= va_arg(ap
, size_t);
395 buffer_size
- sizeof(struct hostent
) - sizeof(char *)) {
400 memcpy(ht
, buffer
, sizeof(struct hostent
));
401 memcpy(&p
, buffer
+ sizeof(struct hostent
), sizeof(char *));
403 orig_buf
= (char *)_ALIGN(orig_buf
);
404 memcpy(orig_buf
, buffer
+ sizeof(struct hostent
) + sizeof(char *) +
405 _ALIGN(p
) - (size_t)p
,
406 buffer_size
- sizeof(struct hostent
) - sizeof(char *) -
407 _ALIGN(p
) + (size_t)p
);
408 p
= (char *)_ALIGN(p
);
410 NS_APPLY_OFFSET(ht
->h_name
, orig_buf
, p
, char *);
411 if (ht
->h_aliases
!= NULL
) {
412 NS_APPLY_OFFSET(ht
->h_aliases
, orig_buf
, p
, char **);
414 for (iter
= ht
->h_aliases
; *iter
; ++iter
)
415 NS_APPLY_OFFSET(*iter
, orig_buf
, p
, char *);
418 if (ht
->h_addr_list
!= NULL
) {
419 NS_APPLY_OFFSET(ht
->h_addr_list
, orig_buf
, p
, char **);
421 for (iter
= ht
->h_addr_list
; *iter
; ++iter
)
422 NS_APPLY_OFFSET(*iter
, orig_buf
, p
, char *);
425 *((struct hostent
**)retval
) = ht
;
428 #endif /* NS_CACHING */
431 fakeaddr(const char *name
, int af
, struct hostent
*hp
, char *buf
,
432 size_t buflen
, res_state statp
)
434 struct hostent_data
*hed
;
437 if ((hed
= __hostent_data_init()) == NULL
) {
439 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
443 if ((af
!= AF_INET
||
444 inet_aton(name
, (struct in_addr
*)hed
->host_addr
) != 1) &&
445 inet_pton(af
, name
, hed
->host_addr
) != 1) {
446 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
449 strncpy(hed
->hostbuf
, name
, MAXDNAME
);
450 hed
->hostbuf
[MAXDNAME
] = '\0';
451 if (af
== AF_INET
&& (statp
->options
& RES_USE_INET6
) != 0U) {
452 _map_v4v6_address((char *)hed
->host_addr
,
453 (char *)hed
->host_addr
);
459 he
.h_length
= NS_INADDRSZ
;
462 he
.h_length
= NS_IN6ADDRSZ
;
465 errno
= EAFNOSUPPORT
;
466 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
469 he
.h_name
= hed
->hostbuf
;
470 he
.h_aliases
= hed
->host_aliases
;
471 hed
->host_aliases
[0] = NULL
;
472 hed
->h_addr_ptrs
[0] = (char *)hed
->host_addr
;
473 hed
->h_addr_ptrs
[1] = NULL
;
474 he
.h_addr_list
= hed
->h_addr_ptrs
;
475 RES_SET_H_ERRNO(statp
, NETDB_SUCCESS
);
476 return (__copy_hostent(&he
, hp
, buf
, buflen
));
480 gethostbyname_r(const char *name
, struct hostent
*he
, char *buffer
,
481 size_t buflen
, struct hostent
**result
, int *h_errnop
)
485 statp
= __res_state();
486 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
487 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
490 if (statp
->options
& RES_USE_INET6
) {
491 if (fakeaddr(name
, AF_INET
, he
, buffer
, buflen
, statp
) == 0) {
495 if (gethostbyname_internal(name
, AF_INET6
, he
, buffer
, buflen
,
496 result
, h_errnop
, statp
) == 0)
499 return (gethostbyname_internal(name
, AF_INET
, he
, buffer
, buflen
,
500 result
, h_errnop
, statp
));
504 gethostbyname2_r(const char *name
, int af
, struct hostent
*he
, char *buffer
,
505 size_t buflen
, struct hostent
**result
, int *h_errnop
)
509 statp
= __res_state();
510 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
511 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
514 return (gethostbyname_internal(name
, af
, he
, buffer
, buflen
, result
,
519 gethostbyname_internal(const char *name
, int af
, struct hostent
*hp
, char *buf
,
520 size_t buflen
, struct hostent
**result
, int *h_errnop
,
528 static const nss_cache_info cache_info
=
529 NS_COMMON_CACHE_INFO_INITIALIZER(
530 hosts
, (void *)nss_lt_name
,
531 host_id_func
, host_marshal_func
, host_unmarshal_func
);
533 static const ns_dtab dtab
[] = {
534 NS_FILES_CB(_ht_gethostbyname
, NULL
)
535 { NSSRC_DNS
, _dns_gethostbyname
, NULL
},
536 NS_NIS_CB(_nis_gethostbyname
, NULL
) /* force -DHESIOD */
538 NS_CACHE_CB(&cache_info
)
548 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
549 *h_errnop
= statp
->res_h_errno
;
550 errno
= EAFNOSUPPORT
;
555 * if there aren't any dots, it could be a user-level alias.
556 * this is also done in res_query() since we are not the only
557 * function that looks up host names.
559 if (!strchr(name
, '.') &&
560 (cp
= res_hostalias(statp
, name
, abuf
, sizeof abuf
)))
563 if (fakeaddr(name
, af
, hp
, buf
, buflen
, statp
) == 0) {
568 rval
= _nsdispatch((void *)result
, dtab
, NSDB_HOSTS
,
569 "gethostbyname2_r", default_src
, name
, af
, hp
, buf
, buflen
,
570 &ret_errno
, h_errnop
);
572 return ((rval
== NS_SUCCESS
) ? 0 : -1);
576 gethostbyaddr_r(const void *addr
, socklen_t len
, int af
, struct hostent
*hp
,
577 char *buf
, size_t buflen
, struct hostent
**result
,
580 const u_char
*uaddr
= (const u_char
*)addr
;
581 const struct in6_addr
*addr6
;
587 static const nss_cache_info cache_info
=
588 NS_COMMON_CACHE_INFO_INITIALIZER(
589 hosts
, (void *)nss_lt_id
,
590 host_id_func
, host_marshal_func
, host_unmarshal_func
);
592 static const ns_dtab dtab
[] = {
593 NS_FILES_CB(_ht_gethostbyaddr
, NULL
)
594 { NSSRC_DNS
, _dns_gethostbyaddr
, NULL
},
595 NS_NIS_CB(_nis_gethostbyaddr
, NULL
) /* force -DHESIOD */
597 NS_CACHE_CB(&cache_info
)
602 statp
= __res_state();
603 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
604 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
605 *h_errnop
= statp
->res_h_errno
;
609 if (af
== AF_INET6
&& len
== NS_IN6ADDRSZ
) {
610 addr6
= (const struct in6_addr
*)addr
;
611 if (IN6_IS_ADDR_LINKLOCAL(addr6
)) {
612 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
613 *h_errnop
= statp
->res_h_errno
;
616 if (IN6_IS_ADDR_V4MAPPED(addr6
) ||
617 IN6_IS_ADDR_V4COMPAT(addr6
)) {
619 uaddr
+= NS_IN6ADDRSZ
- NS_INADDRSZ
;
632 errno
= EAFNOSUPPORT
;
633 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
634 *h_errnop
= statp
->res_h_errno
;
639 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
640 *h_errnop
= statp
->res_h_errno
;
644 rval
= _nsdispatch((void *)result
, dtab
, NSDB_HOSTS
,
645 "gethostbyaddr_r", default_src
, uaddr
, len
, af
, hp
, buf
, buflen
,
646 &ret_errno
, h_errnop
);
648 return ((rval
== NS_SUCCESS
) ? 0 : -1);
652 gethostbyname(const char *name
)
655 struct hostent
*rval
;
658 if ((hd
= __hostdata_init()) == NULL
)
660 if (gethostbyname_r(name
, &hd
->host
, hd
->data
, sizeof(hd
->data
), &rval
,
667 gethostbyname2(const char *name
, int af
)
670 struct hostent
*rval
;
673 if ((hd
= __hostdata_init()) == NULL
)
675 if (gethostbyname2_r(name
, af
, &hd
->host
, hd
->data
, sizeof(hd
->data
),
676 &rval
, &ret_h_errno
) != 0)
682 gethostbyaddr(const void *addr
, socklen_t len
, int af
)
685 struct hostent
*rval
;
688 if ((hd
= __hostdata_init()) == NULL
)
690 if (gethostbyaddr_r(addr
, len
, af
, &hd
->host
, hd
->data
,
691 sizeof(hd
->data
), &rval
, &ret_h_errno
) != 0)
697 sethostent(int stayopen
)
699 struct hostent_data
*hed
;
701 if ((hed
= __hostent_data_init()) == NULL
)
703 _sethosthtent(stayopen
, hed
);
704 _sethostdnsent(stayopen
);
710 struct hostent_data
*hed
;
712 if ((hed
= __hostent_data_init()) == NULL
)