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 extern int _ht_gethostbyname(void *, void *, va_list);
51 extern int _dns_gethostbyname(void *, void *, va_list);
52 extern int _nis_gethostbyname(void *, void *, va_list);
53 extern int _ht_gethostbyaddr(void *, void *, va_list);
54 extern int _dns_gethostbyaddr(void *, void *, va_list);
55 extern int _nis_gethostbyaddr(void *, void *, va_list);
57 static int gethostbyname_internal(const char *, int, struct hostent
*, char *,
58 size_t, struct hostent
**, int *, res_state
);
60 /* Host lookup order if nsswitch.conf is broken or nonexistant */
61 static const ns_src default_src
[] = {
62 { NSSRC_FILES
, NS_SUCCESS
},
63 { NSSRC_DNS
, NS_SUCCESS
},
67 static int host_id_func(char *, size_t *, va_list, void *);
68 static int host_marshal_func(char *, size_t *, void *, va_list, void *);
69 static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
72 NETDB_THREAD_ALLOC(hostent
)
73 NETDB_THREAD_ALLOC(hostent_data
)
74 NETDB_THREAD_ALLOC(hostdata
)
77 hostent_free(void *ptr
)
83 hostent_data_free(void *ptr
)
85 struct hostent_data
*hed
= ptr
;
95 hostdata_free(void *ptr
)
101 __copy_hostent(struct hostent
*he
, struct hostent
*hptr
, char *buf
,
109 /* Find out the amount of space required to store the answer. */
110 nptr
= 2; /* NULL ptrs */
111 len
= (char *)ALIGN(buf
) - buf
;
112 for (i
= 0; he
->h_addr_list
[i
]; i
++, nptr
++) {
115 for (i
= 0; he
->h_aliases
[i
]; i
++, nptr
++) {
116 len
+= strlen(he
->h_aliases
[i
]) + 1;
118 len
+= strlen(he
->h_name
) + 1;
119 len
+= nptr
* sizeof(char*);
126 /* copy address size and type */
127 hptr
->h_addrtype
= he
->h_addrtype
;
128 n
= hptr
->h_length
= he
->h_length
;
130 ptr
= (char **)ALIGN(buf
);
131 cp
= (char *)ALIGN(buf
) + nptr
* sizeof(char *);
133 /* copy address list */
134 hptr
->h_addr_list
= ptr
;
135 for (i
= 0; he
->h_addr_list
[i
]; i
++ , ptr
++) {
136 memcpy(cp
, he
->h_addr_list
[i
], n
);
137 hptr
->h_addr_list
[i
] = cp
;
140 hptr
->h_addr_list
[i
] = NULL
;
143 /* copy official name */
144 n
= strlen(he
->h_name
) + 1;
145 strcpy(cp
, he
->h_name
);
150 hptr
->h_aliases
= ptr
;
151 for (i
= 0 ; he
->h_aliases
[i
]; i
++) {
152 n
= strlen(he
->h_aliases
[i
]) + 1;
153 strcpy(cp
, he
->h_aliases
[i
]);
154 hptr
->h_aliases
[i
] = cp
;
157 hptr
->h_aliases
[i
] = NULL
;
164 host_id_func(char *buffer
, size_t *buffer_size
, va_list ap
, void *cache_mdata
)
175 size_t desired_size
, size
;
176 enum nss_lookup_type lookup_type
;
178 int res
= NS_UNAVAIL
;
180 statp
= __res_state();
181 res_options
= statp
->options
& (RES_RECURSE
| RES_DEFNAMES
|
182 RES_DNSRCH
| RES_NOALIASES
| RES_USE_INET6
);
184 lookup_type
= (enum nss_lookup_type
)cache_mdata
;
185 switch (lookup_type
) {
187 str
= va_arg(ap
, char *);
188 type
= va_arg(ap
, int);
191 desired_size
= sizeof(res_options
) + sizeof(int) +
192 sizeof(enum nss_lookup_type
) + sizeof(int) + size
+ 1;
194 if (desired_size
> *buffer_size
) {
201 memcpy(p
, &res_options
, sizeof(res_options
));
202 p
+= sizeof(res_options
);
204 memcpy(p
, &op_id
, sizeof(int));
207 memcpy(p
, &lookup_type
, sizeof(enum nss_lookup_type
));
210 memcpy(p
, &type
, sizeof(int));
213 memcpy(p
, str
, size
+ 1);
218 addr
= va_arg(ap
, void *);
219 len
= va_arg(ap
, socklen_t
);
220 type
= va_arg(ap
, int);
222 desired_size
= sizeof(res_options
) + sizeof(int) +
223 sizeof(enum nss_lookup_type
) + sizeof(int) +
224 sizeof(socklen_t
) + len
;
226 if (desired_size
> *buffer_size
) {
232 memcpy(p
, &res_options
, sizeof(res_options
));
233 p
+= sizeof(res_options
);
235 memcpy(p
, &op_id
, sizeof(int));
238 memcpy(p
, &lookup_type
, sizeof(enum nss_lookup_type
));
241 memcpy(p
, &type
, sizeof(int));
244 memcpy(p
, &len
, sizeof(socklen_t
));
245 p
+= sizeof(socklen_t
);
247 memcpy(p
, addr
, len
);
252 /* should be unreachable */
257 *buffer_size
= desired_size
;
262 host_marshal_func(char *buffer
, size_t *buffer_size
, void *retval __unused
,
263 va_list ap
, void *cache_mdata
)
267 socklen_t len __unused
;
271 struct hostent new_ht
;
272 size_t desired_size
, aliases_size
, addr_size
, size
;
275 switch ((enum nss_lookup_type
)cache_mdata
) {
277 str
= va_arg(ap
, char *);
278 type
= va_arg(ap
, int);
281 addr
= va_arg(ap
, void *);
282 len
= va_arg(ap
, socklen_t
);
283 type
= va_arg(ap
, int);
286 /* should be unreachable */
289 ht
= va_arg(ap
, struct hostent
*);
291 desired_size
= _ALIGNBYTES
+ sizeof(struct hostent
) + sizeof(char *);
292 if (ht
->h_name
!= NULL
)
293 desired_size
+= strlen(ht
->h_name
) + 1;
295 if (ht
->h_aliases
!= NULL
) {
297 for (iter
= ht
->h_aliases
; *iter
; ++iter
) {
298 desired_size
+= strlen(*iter
) + 1;
302 desired_size
+= _ALIGNBYTES
+
303 (aliases_size
+ 1) * sizeof(char *);
306 if (ht
->h_addr_list
!= NULL
) {
308 for (iter
= ht
->h_addr_list
; *iter
; ++iter
)
311 desired_size
+= addr_size
* _ALIGN(ht
->h_length
);
312 desired_size
+= _ALIGNBYTES
+ (addr_size
+ 1) * sizeof(char *);
315 if (desired_size
> *buffer_size
) {
316 /* this assignment is here for future use */
317 *buffer_size
= desired_size
;
321 memcpy(&new_ht
, ht
, sizeof(struct hostent
));
322 memset(buffer
, 0, desired_size
);
324 *buffer_size
= desired_size
;
325 p
= buffer
+ sizeof(struct hostent
) + sizeof(char *);
326 memcpy(buffer
+ sizeof(struct hostent
), &p
, sizeof(char *));
327 p
= (char *)_ALIGN(p
);
329 if (new_ht
.h_name
!= NULL
) {
330 size
= strlen(new_ht
.h_name
);
331 memcpy(p
, new_ht
.h_name
, size
);
336 if (new_ht
.h_aliases
!= NULL
) {
337 p
= (char *)_ALIGN(p
);
338 memcpy(p
, new_ht
.h_aliases
, sizeof(char *) * aliases_size
);
339 new_ht
.h_aliases
= (char **)p
;
340 p
+= sizeof(char *) * (aliases_size
+ 1);
342 for (iter
= new_ht
.h_aliases
; *iter
; ++iter
) {
343 size
= strlen(*iter
);
344 memcpy(p
, *iter
, size
);
350 if (new_ht
.h_addr_list
!= NULL
) {
351 p
= (char *)_ALIGN(p
);
352 memcpy(p
, new_ht
.h_addr_list
, sizeof(char *) * addr_size
);
353 new_ht
.h_addr_list
= (char **)p
;
354 p
+= sizeof(char *) * (addr_size
+ 1);
356 size
= _ALIGN(new_ht
.h_length
);
357 for (iter
= new_ht
.h_addr_list
; *iter
; ++iter
) {
358 memcpy(p
, *iter
, size
);
363 memcpy(buffer
, &new_ht
, sizeof(struct hostent
));
368 host_unmarshal_func(char *buffer
, size_t buffer_size
, void *retval
, va_list ap
,
373 socklen_t len __unused
;
380 size_t orig_buf_size
;
382 switch ((enum nss_lookup_type
)cache_mdata
) {
384 str
= va_arg(ap
, char *);
385 type
= va_arg(ap
, int);
388 addr
= va_arg(ap
, void *);
389 len
= va_arg(ap
, socklen_t
);
390 type
= va_arg(ap
, int);
393 /* should be unreachable */
397 ht
= va_arg(ap
, struct hostent
*);
398 orig_buf
= va_arg(ap
, char *);
399 orig_buf_size
= va_arg(ap
, size_t);
402 buffer_size
- sizeof(struct hostent
) - sizeof(char *)) {
407 memcpy(ht
, buffer
, sizeof(struct hostent
));
408 memcpy(&p
, buffer
+ sizeof(struct hostent
), sizeof(char *));
410 orig_buf
= (char *)_ALIGN(orig_buf
);
411 memcpy(orig_buf
, buffer
+ sizeof(struct hostent
) + sizeof(char *) +
412 _ALIGN(p
) - (size_t)p
,
413 buffer_size
- sizeof(struct hostent
) - sizeof(char *) -
414 _ALIGN(p
) + (size_t)p
);
415 p
= (char *)_ALIGN(p
);
417 NS_APPLY_OFFSET(ht
->h_name
, orig_buf
, p
, char *);
418 if (ht
->h_aliases
!= NULL
) {
419 NS_APPLY_OFFSET(ht
->h_aliases
, orig_buf
, p
, char **);
421 for (iter
= ht
->h_aliases
; *iter
; ++iter
)
422 NS_APPLY_OFFSET(*iter
, orig_buf
, p
, char *);
425 if (ht
->h_addr_list
!= NULL
) {
426 NS_APPLY_OFFSET(ht
->h_addr_list
, orig_buf
, p
, char **);
428 for (iter
= ht
->h_addr_list
; *iter
; ++iter
)
429 NS_APPLY_OFFSET(*iter
, orig_buf
, p
, char *);
432 *((struct hostent
**)retval
) = ht
;
435 #endif /* NS_CACHING */
438 fakeaddr(const char *name
, int af
, struct hostent
*hp
, char *buf
,
439 size_t buflen
, res_state statp
)
441 struct hostent_data
*hed
;
444 if ((hed
= __hostent_data_init()) == NULL
) {
446 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
450 if ((af
!= AF_INET
||
451 inet_aton(name
, (struct in_addr
*)hed
->host_addr
) != 1) &&
452 inet_pton(af
, name
, hed
->host_addr
) != 1) {
453 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
456 strncpy(hed
->hostbuf
, name
, MAXDNAME
);
457 hed
->hostbuf
[MAXDNAME
] = '\0';
458 if (af
== AF_INET
&& (statp
->options
& RES_USE_INET6
) != 0U) {
459 _map_v4v6_address((char *)hed
->host_addr
,
460 (char *)hed
->host_addr
);
466 he
.h_length
= NS_INADDRSZ
;
469 he
.h_length
= NS_IN6ADDRSZ
;
472 errno
= EAFNOSUPPORT
;
473 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
476 he
.h_name
= hed
->hostbuf
;
477 he
.h_aliases
= hed
->host_aliases
;
478 hed
->host_aliases
[0] = NULL
;
479 hed
->h_addr_ptrs
[0] = (char *)hed
->host_addr
;
480 hed
->h_addr_ptrs
[1] = NULL
;
481 he
.h_addr_list
= hed
->h_addr_ptrs
;
482 RES_SET_H_ERRNO(statp
, NETDB_SUCCESS
);
483 return (__copy_hostent(&he
, hp
, buf
, buflen
));
487 gethostbyname_r(const char *name
, struct hostent
*he
, char *buffer
,
488 size_t buflen
, struct hostent
**result
, int *h_errnop
)
492 statp
= __res_state();
493 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
494 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
497 if (statp
->options
& RES_USE_INET6
) {
498 if (fakeaddr(name
, AF_INET
, he
, buffer
, buflen
, statp
) == 0) {
502 if (gethostbyname_internal(name
, AF_INET6
, he
, buffer
, buflen
,
503 result
, h_errnop
, statp
) == 0)
506 return (gethostbyname_internal(name
, AF_INET
, he
, buffer
, buflen
,
507 result
, h_errnop
, statp
));
511 gethostbyname2_r(const char *name
, int af
, struct hostent
*he
, char *buffer
,
512 size_t buflen
, struct hostent
**result
, int *h_errnop
)
516 statp
= __res_state();
517 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
518 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
521 return (gethostbyname_internal(name
, af
, he
, buffer
, buflen
, result
,
526 gethostbyname_internal(const char *name
, int af
, struct hostent
*hp
, char *buf
,
527 size_t buflen
, struct hostent
**result
, int *h_errnop
,
535 static const nss_cache_info cache_info
=
536 NS_COMMON_CACHE_INFO_INITIALIZER(
537 hosts
, (void *)nss_lt_name
,
538 host_id_func
, host_marshal_func
, host_unmarshal_func
);
540 static const ns_dtab dtab
[] = {
541 NS_FILES_CB(_ht_gethostbyname
, NULL
)
542 { NSSRC_DNS
, _dns_gethostbyname
, NULL
},
543 NS_NIS_CB(_nis_gethostbyname
, NULL
) /* force -DHESIOD */
545 NS_CACHE_CB(&cache_info
)
555 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
556 *h_errnop
= statp
->res_h_errno
;
557 errno
= EAFNOSUPPORT
;
562 * if there aren't any dots, it could be a user-level alias.
563 * this is also done in res_query() since we are not the only
564 * function that looks up host names.
566 if (!strchr(name
, '.') &&
567 (cp
= res_hostalias(statp
, name
, abuf
, sizeof abuf
)))
570 if (fakeaddr(name
, af
, hp
, buf
, buflen
, statp
) == 0) {
575 rval
= _nsdispatch((void *)result
, dtab
, NSDB_HOSTS
,
576 "gethostbyname2_r", default_src
, name
, af
, hp
, buf
, buflen
,
577 &ret_errno
, h_errnop
);
579 return ((rval
== NS_SUCCESS
) ? 0 : -1);
583 gethostbyaddr_r(const void *addr
, socklen_t len
, int af
, struct hostent
*hp
,
584 char *buf
, size_t buflen
, struct hostent
**result
,
587 const u_char
*uaddr
= (const u_char
*)addr
;
588 const struct in6_addr
*addr6
;
594 static const nss_cache_info cache_info
=
595 NS_COMMON_CACHE_INFO_INITIALIZER(
596 hosts
, (void *)nss_lt_id
,
597 host_id_func
, host_marshal_func
, host_unmarshal_func
);
599 static const ns_dtab dtab
[] = {
600 NS_FILES_CB(_ht_gethostbyaddr
, NULL
)
601 { NSSRC_DNS
, _dns_gethostbyaddr
, NULL
},
602 NS_NIS_CB(_nis_gethostbyaddr
, NULL
) /* force -DHESIOD */
604 NS_CACHE_CB(&cache_info
)
609 statp
= __res_state();
610 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1) {
611 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
612 *h_errnop
= statp
->res_h_errno
;
616 if (af
== AF_INET6
&& len
== NS_IN6ADDRSZ
) {
617 addr6
= (const struct in6_addr
*)addr
;
618 if (IN6_IS_ADDR_LINKLOCAL(addr6
)) {
619 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
620 *h_errnop
= statp
->res_h_errno
;
623 if (IN6_IS_ADDR_V4MAPPED(addr6
) ||
624 IN6_IS_ADDR_V4COMPAT(addr6
)) {
626 uaddr
+= NS_IN6ADDRSZ
- NS_INADDRSZ
;
639 errno
= EAFNOSUPPORT
;
640 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
641 *h_errnop
= statp
->res_h_errno
;
646 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
647 *h_errnop
= statp
->res_h_errno
;
651 rval
= _nsdispatch((void *)result
, dtab
, NSDB_HOSTS
,
652 "gethostbyaddr_r", default_src
, uaddr
, len
, af
, hp
, buf
, buflen
,
653 &ret_errno
, h_errnop
);
655 return ((rval
== NS_SUCCESS
) ? 0 : -1);
659 gethostbyname(const char *name
)
662 struct hostent
*rval
;
665 if ((hd
= __hostdata_init()) == NULL
)
667 if (gethostbyname_r(name
, &hd
->host
, hd
->data
, sizeof(hd
->data
), &rval
,
674 gethostbyname2(const char *name
, int af
)
677 struct hostent
*rval
;
680 if ((hd
= __hostdata_init()) == NULL
)
682 if (gethostbyname2_r(name
, af
, &hd
->host
, hd
->data
, sizeof(hd
->data
),
683 &rval
, &ret_h_errno
) != 0)
689 gethostbyaddr(const void *addr
, socklen_t len
, int af
)
692 struct hostent
*rval
;
695 if ((hd
= __hostdata_init()) == NULL
)
697 if (gethostbyaddr_r(addr
, len
, af
, &hd
->host
, hd
->data
,
698 sizeof(hd
->data
), &rval
, &ret_h_errno
) != 0)
704 sethostent(int stayopen
)
706 struct hostent_data
*hed
;
708 if ((hed
= __hostent_data_init()) == NULL
)
710 _sethosthtent(stayopen
, hed
);
711 _sethostdnsent(stayopen
);
717 struct hostent_data
*hed
;
719 if ((hed
= __hostent_data_init()) == NULL
)