2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
26 #include <mach/mach.h>
29 #include <rpc/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
35 #include <arpa/inet.h>
39 #include <sys/types.h>
40 #include <netinet/if_ether.h>
43 #define ENTRY_SIZE sizeof(struct hostent)
44 #define ENTRY_KEY _li_data_key_host
45 #define HOST_CACHE_SIZE 20
47 #define CACHE_BYNAME 0
48 #define CACHE_BYADDR 1
50 static pthread_mutex_t _host_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
52 static void *_host_byname_cache
[HOST_CACHE_SIZE
] = { NULL
};
53 static int _host_byname_cache_flavor
[HOST_CACHE_SIZE
] = { WANT_NOTHING
};
54 static unsigned int _host_byname_cache_index
= 0;
56 static void *_host_byaddr_cache
[HOST_CACHE_SIZE
] = { NULL
};
57 static int _host_byaddr_cache_flavor
[HOST_CACHE_SIZE
] = { WANT_NOTHING
};
58 static unsigned int _host_byaddr_cache_index
= 0;
60 static unsigned int _host_cache_init
= 0;
62 static pthread_mutex_t _host_lock
= PTHREAD_MUTEX_INITIALIZER
;
64 __private_extern__
struct hostent
*LI_files_gethostbyname(const char *name
);
65 __private_extern__
struct hostent
*LI_files_gethostbyname2(const char *name
, int af
);
66 __private_extern__
struct hostent
*LI_files_gethostbyaddr(const void *addr
, socklen_t len
, int type
);
67 __private_extern__
struct hostent
*LI_files_gethostent();
68 __private_extern__
void LI_files_sethostent(int stayopen
);
69 __private_extern__
void LI_files_endhostent();
71 extern int _old_ether_hostton(const char *, struct ether_addr
*);
72 extern int _old_ether_ntohost(char *, const struct ether_addr
*);
76 #define IPV6_ADDR_LEN 16
77 #define IPV4_ADDR_LEN 4
80 freehostent(struct hostent
*h
)
85 if (LI_ils_free(h
, ENTRY_SIZE
) == 0) return;
87 if (h
->h_name
!= NULL
) free(h
->h_name
);
89 aliases
= h
->h_aliases
;
92 while (*aliases
!= NULL
) free(*aliases
++);
96 if (h
->h_addr_list
!= NULL
)
98 for (i
= 0; h
->h_addr_list
[i
] != NULL
; i
++) free(h
->h_addr_list
[i
]);
104 static struct hostent
*
105 copy_host(struct hostent
*in
)
107 if (in
== NULL
) return NULL
;
109 if (in
->h_addrtype
== AF_INET
)
110 return (struct hostent
*)LI_ils_create("s*44a", in
->h_name
, in
->h_aliases
, in
->h_addrtype
, in
->h_length
, in
->h_addr_list
);
112 if (in
->h_addrtype
== AF_INET6
)
113 return (struct hostent
*)LI_ils_create("s*44c", in
->h_name
, in
->h_aliases
, in
->h_addrtype
, in
->h_length
, in
->h_addr_list
);
119 _free_addr_list(char **l
)
123 if (l
== NULL
) return;
124 for (i
= 0; l
[i
] != NULL
; i
++) free(l
[i
]);
128 /* map ipv4 addresses and append to v6 list */
130 _map_v4(char ***v6
, uint32_t n6
, char **v4
, uint32_t n4
)
135 a6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
136 a6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
137 a6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
141 *v6
= (char **)calloc(n4
+ 1, sizeof(char *));
145 *v6
= (char **)reallocf(*v6
, (n6
+ n4
+ 1) * sizeof(char *));
148 if (*v6
== NULL
) return -1;
150 for (i
= 0; i
< n4
; i
++)
152 (*v6
)[n6
] = (char *)calloc(1, IPV6_ADDR_LEN
);
153 if ((*v6
)[n6
] == NULL
) return -1;
155 memcpy(&(a6
.__u6_addr
.__u6_addr32
[3]), v4
[i
], IPV4_ADDR_LEN
);
156 memcpy((*v6
)[n6
], &(a6
.__u6_addr
.__u6_addr32
[0]), IPV6_ADDR_LEN
);
164 __private_extern__
struct hostent
*
165 extract_host(kvarray_t
*in
, int want
)
167 struct hostent tmp
, *out
;
168 uint32_t i
, d
, k
, kcount
, vcount
, v4count
, v6count
;
169 int status
, addr_len
;
170 int family
, addr_count
;
173 char **v4addrs
, **v6addrs
;
181 addr_len
= sizeof(void *);
183 if (in
== NULL
) return NULL
;
188 if (d
>= in
->count
) return NULL
;
191 memset(&tmp
, 0, ENTRY_SIZE
);
194 tmp
.h_length
= IPV4_ADDR_LEN
;
196 if (want
!= WANT_A4_ONLY
)
199 tmp
.h_length
= IPV6_ADDR_LEN
;
202 tmp
.h_addrtype
= family
;
204 kcount
= in
->dict
[d
].kcount
;
206 for (k
= 0; k
< kcount
; k
++)
208 if (!strcmp(in
->dict
[d
].key
[k
], "h_name"))
210 if (tmp
.h_name
!= NULL
) continue;
212 vcount
= in
->dict
[d
].vcount
[k
];
213 if (vcount
== 0) continue;
215 tmp
.h_name
= (char *)in
->dict
[d
].val
[k
][0];
217 else if (!strcmp(in
->dict
[d
].key
[k
], "h_aliases"))
219 if (tmp
.h_aliases
!= NULL
) continue;
221 vcount
= in
->dict
[d
].vcount
[k
];
222 if (vcount
== 0) continue;
224 tmp
.h_aliases
= (char **)in
->dict
[d
].val
[k
];
226 else if (!strcmp(in
->dict
[d
].key
[k
], "h_ipv4_addr_list"))
228 if (v4addrs
!= NULL
) continue;
230 v4count
= in
->dict
[d
].vcount
[k
];
231 if (v4count
== 0) continue;
233 v4addrs
= (char **)calloc(v4count
+ 1, sizeof(char *));
236 _free_addr_list(v6addrs
);
240 for (i
= 0; i
< v4count
; i
++)
242 v4addrs
[i
] = calloc(1, IPV4_ADDR_LEN
);
243 if (v4addrs
[i
] == NULL
)
245 _free_addr_list(v4addrs
);
246 _free_addr_list(v6addrs
);
250 memset(&a4
, 0, sizeof(struct in_addr
));
251 status
= inet_pton(AF_INET
, in
->dict
[d
].val
[k
][i
], &a4
);
254 _free_addr_list(v4addrs
);
255 _free_addr_list(v6addrs
);
259 memcpy(v4addrs
[i
], &a4
, IPV4_ADDR_LEN
);
262 else if (!strcmp(in
->dict
[d
].key
[k
], "h_ipv6_addr_list"))
264 if (v6addrs
!= NULL
) continue;
266 v6count
= in
->dict
[d
].vcount
[k
];
267 if (v6count
== 0) continue;
269 v6addrs
= (char **)calloc(v6count
+ 1, sizeof(char *));
272 _free_addr_list(v4addrs
);
276 for (i
= 0; i
< v6count
; i
++)
278 v6addrs
[i
] = calloc(1, IPV6_ADDR_LEN
);
279 if (v6addrs
[i
] == NULL
)
281 _free_addr_list(v4addrs
);
282 _free_addr_list(v6addrs
);
286 memset(&a6
, 0, sizeof(struct in6_addr
));
287 status
= inet_pton(AF_INET6
, in
->dict
[d
].val
[k
][i
], &a6
);
290 _free_addr_list(v4addrs
);
291 _free_addr_list(v6addrs
);
295 memcpy(v6addrs
[i
], &(a6
.__u6_addr
.__u6_addr32
[0]), IPV6_ADDR_LEN
);
300 if (tmp
.h_name
== NULL
) tmp
.h_name
= "";
301 if (tmp
.h_aliases
== NULL
) tmp
.h_aliases
= empty
;
303 if (want
== WANT_A4_ONLY
)
305 _free_addr_list(v6addrs
);
306 if (v4addrs
== NULL
) return NULL
;
308 tmp
.h_addr_list
= v4addrs
;
309 out
= copy_host(&tmp
);
310 _free_addr_list(v4addrs
);
314 else if ((want
== WANT_A6_ONLY
) || ((want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) && (v6count
> 0)))
316 _free_addr_list(v4addrs
);
317 if (v6addrs
== NULL
) return NULL
;
319 tmp
.h_addr_list
= v6addrs
;
320 out
= copy_host(&tmp
);
321 _free_addr_list(v6addrs
);
327 * At this point, want is WANT_A6_PLUS_MAPPED_A4, WANT_MAPPED_A4_ONLY,
328 * or WANT_A6_OR_MAPPED_A4_IF_NO_A6. In the last case, there are no ipv6
329 * addresses, so that case degenerates into WANT_MAPPED_A4_ONLY.
331 if (want
== WANT_A6_OR_MAPPED_A4_IF_NO_A6
) want
= WANT_MAPPED_A4_ONLY
;
333 if (want
== WANT_MAPPED_A4_ONLY
)
335 _free_addr_list(v6addrs
);
340 status
= _map_v4(&v6addrs
, v6count
, v4addrs
, v4count
);
341 _free_addr_list(v4addrs
);
344 _free_addr_list(v6addrs
);
348 if (v6addrs
== NULL
) return NULL
;
350 tmp
.h_addr_list
= v6addrs
;
351 out
= copy_host(&tmp
);
352 _free_addr_list(v6addrs
);
357 __private_extern__
struct hostent
*
358 fake_hostent(const char *name
, struct in_addr addr
)
364 if (name
== NULL
) return NULL
;
366 memset(&tmp
, 0, ENTRY_SIZE
);
368 tmp
.h_name
= (char *)name
;
369 tmp
.h_addrtype
= AF_INET
;
370 tmp
.h_length
= IPV4_ADDR_LEN
;
371 tmp
.h_addr_list
= addrs
;
372 addrs
[0] = (char *)&(addr
.s_addr
);
374 tmp
.h_aliases
= aliases
;
377 return copy_host(&tmp
);
380 __private_extern__
struct hostent
*
381 fake_hostent6(const char *name
, struct in6_addr addr
)
387 if (name
== NULL
) return NULL
;
389 memset(&tmp
, 0, ENTRY_SIZE
);
391 tmp
.h_name
= (char *)name
;
392 tmp
.h_addrtype
= AF_INET6
;
393 tmp
.h_length
= IPV6_ADDR_LEN
;
394 tmp
.h_addr_list
= addrs
;
395 addrs
[0] = (char *)&(addr
.__u6_addr
.__u6_addr32
[0]);
397 tmp
.h_aliases
= aliases
;
400 return copy_host(&tmp
);
404 cache_host(struct hostent
*h
, int want
, int how
)
406 struct hostent
*hcache
;
408 if (h
== NULL
) return;
410 pthread_mutex_lock(&_host_cache_lock
);
412 hcache
= copy_host(h
);
414 if (how
== CACHE_BYNAME
)
416 if (_host_byname_cache
[_host_byname_cache_index
] != NULL
) LI_ils_free(_host_byname_cache
[_host_byname_cache_index
], ENTRY_SIZE
);
418 _host_byname_cache
[_host_byname_cache_index
] = hcache
;
419 _host_byname_cache_flavor
[_host_byname_cache_index
] = want
;
420 _host_byname_cache_index
= (_host_byname_cache_index
+ 1) % HOST_CACHE_SIZE
;
424 if (_host_byaddr_cache
[_host_byaddr_cache_index
] != NULL
) LI_ils_free(_host_byaddr_cache
[_host_byaddr_cache_index
], ENTRY_SIZE
);
426 _host_byaddr_cache
[_host_byaddr_cache_index
] = hcache
;
427 _host_byaddr_cache_flavor
[_host_byaddr_cache_index
] = want
;
428 _host_byaddr_cache_index
= (_host_byaddr_cache_index
+ 1) % HOST_CACHE_SIZE
;
431 _host_cache_init
= 1;
433 pthread_mutex_unlock(&_host_cache_lock
);
441 /* don't consult cache if it has not been initialized */
442 if (_host_cache_init
== 0) return 1;
444 status
= LI_L1_cache_check(ENTRY_KEY
);
446 /* don't consult cache if it is disabled or if we can't validate */
447 if ((status
== LI_L1_CACHE_DISABLED
) || (status
== LI_L1_CACHE_FAILED
)) return 1;
449 /* return 0 if cache is OK */
450 if (status
== LI_L1_CACHE_OK
) return 0;
453 pthread_mutex_lock(&_host_cache_lock
);
455 for (i
= 0; i
< HOST_CACHE_SIZE
; i
++)
457 LI_ils_free(_host_byname_cache
[i
], ENTRY_SIZE
);
458 _host_byname_cache
[i
] = NULL
;
459 _host_byname_cache_flavor
[i
] = WANT_NOTHING
;
461 LI_ils_free(_host_byaddr_cache
[i
], ENTRY_SIZE
);
462 _host_byaddr_cache
[i
] = NULL
;
463 _host_byaddr_cache_flavor
[i
] = WANT_NOTHING
;
466 _host_byname_cache_index
= 0;
467 _host_byaddr_cache_index
= 0;
469 pthread_mutex_unlock(&_host_cache_lock
);
471 /* don't consult cache - it's now empty */
476 static struct hostent
*
477 cache_gethostbyname(const char *name
, int want
)
480 struct hostent
*h
, *res
;
483 if (name
== NULL
) return NULL
;
484 if (host_cache_check() != 0) return NULL
;
486 pthread_mutex_lock(&_host_cache_lock
);
488 for (i
= 0; i
< HOST_CACHE_SIZE
; i
++)
490 if (_host_byname_cache_flavor
[i
] != want
) continue;
492 h
= (struct hostent
*)_host_byname_cache
[i
];
493 if (h
== NULL
) continue;
495 if (h
->h_name
!= NULL
)
497 if (!strcmp(name
, h
->h_name
))
500 pthread_mutex_unlock(&_host_cache_lock
);
505 aliases
= h
->h_aliases
;
508 pthread_mutex_unlock(&_host_cache_lock
);
512 for (; *aliases
!= NULL
; *aliases
++)
514 if (!strcmp(name
, *aliases
))
517 pthread_mutex_unlock(&_host_cache_lock
);
523 pthread_mutex_unlock(&_host_cache_lock
);
527 static struct hostent
*
528 cache_gethostbyaddr(const char *addr
, int want
)
531 struct hostent
*h
, *res
;
533 if (addr
== NULL
) return NULL
;
534 if (host_cache_check() != 0) return NULL
;
536 pthread_mutex_lock(&_host_cache_lock
);
539 if (want
> WANT_A4_ONLY
) len
= IPV6_ADDR_LEN
;
541 for (i
= 0; i
< HOST_CACHE_SIZE
; i
++)
543 if (_host_byaddr_cache_flavor
[i
] != want
) continue;
545 h
= (struct hostent
*)_host_byaddr_cache
[i
];
546 if (h
== NULL
) continue;
548 if (h
->h_addr_list
== NULL
) continue;
550 for (j
= 0; h
->h_addr_list
[j
] != NULL
; j
++)
552 if (memcmp(addr
, h
->h_addr_list
[j
], len
) == 0)
555 pthread_mutex_unlock(&_host_cache_lock
);
561 pthread_mutex_unlock(&_host_cache_lock
);
565 static struct hostent
*
566 ds_gethostbyaddr(const char *paddr
, uint32_t family
, int *err
)
568 struct hostent
*entry
;
571 kern_return_t status
;
572 static int proc
= -1;
573 struct in_addr addr4
;
574 struct in6_addr addr6
;
580 if (err
!= NULL
) *err
= NO_RECOVERY
;
586 status
= LI_DSLookupGetProcedureNumber("gethostbyaddr", &proc
);
587 if (status
!= KERN_SUCCESS
)
589 if (err
!= NULL
) *err
= NO_RECOVERY
;
594 memset(&addr4
, 0, sizeof(struct in_addr
));
595 memset(&addr6
, 0, sizeof(struct in6_addr
));
596 memset(tmp
, 0, sizeof(tmp
));
599 if (family
== AF_INET
)
602 memcpy(&(addr4
.s_addr
), paddr
, IPV4_ADDR_LEN
);
603 if (inet_ntop(family
, &addr4
, tmp
, sizeof(tmp
)) == NULL
)
605 if (err
!= NULL
) *err
= NO_RECOVERY
;
609 else if (family
== AF_INET6
)
612 memcpy(addr6
.s6_addr
, paddr
, IPV6_ADDR_LEN
);
613 if (inet_ntop(family
, &addr6
, tmp
, sizeof(tmp
)) == NULL
)
615 if (err
!= NULL
) *err
= NO_RECOVERY
;
621 if (err
!= NULL
) *err
= NO_RECOVERY
;
625 request
= kvbuf_query("ksku", "address", tmp
, "family", family
);
628 if (err
!= NULL
) *err
= NO_RECOVERY
;
633 status
= LI_DSLookupQuery(proc
, request
, &reply
);
636 if (status
!= KERN_SUCCESS
)
638 if (err
!= NULL
) *err
= NO_RECOVERY
;
642 if (err
!= NULL
) *err
= 0;
643 entry
= extract_host(reply
, want
);
645 if ((entry
== NULL
) && (err
!= NULL
)) *err
= HOST_NOT_FOUND
;
651 static struct hostent
*
652 ds_gethostbyname(const char *name
, uint32_t want
, int *err
)
654 struct hostent
*entry
;
657 kern_return_t status
;
658 static int proc
= -1;
659 uint32_t want4
, want6
;
664 if (want
== WANT_A4_ONLY
) want6
= 0;
665 else if (want
== WANT_A6_ONLY
) want4
= 0;
666 else if (WANT_MAPPED_A4_ONLY
) want6
= 0;
670 if (err
!= NULL
) *err
= NO_RECOVERY
;
676 status
= LI_DSLookupGetProcedureNumber("gethostbyname", &proc
);
677 if (status
!= KERN_SUCCESS
)
679 if (err
!= NULL
) *err
= NO_RECOVERY
;
684 request
= kvbuf_query("kskuku", "name", name
, "ipv4", want4
, "ipv6", want6
);
687 if (err
!= NULL
) *err
= NO_RECOVERY
;
692 status
= LI_DSLookupQuery(proc
, request
, &reply
);
695 if (status
!= KERN_SUCCESS
)
697 if (err
!= NULL
) *err
= NO_RECOVERY
;
701 if (err
!= NULL
) *err
= 0;
702 entry
= extract_host(reply
, want
);
703 if ((entry
== NULL
) && (err
!= NULL
)) *err
= HOST_NOT_FOUND
;
712 LI_data_free_kvarray(LI_data_find_key(ENTRY_KEY
));
721 static struct hostent
*
722 ds_gethostent(int *err
)
724 struct hostent
*entry
;
725 struct li_thread_info
*tdata
;
726 kvarray_t
*reply
, *vma
;
727 kern_return_t status
;
728 static int proc
= -1;
730 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
733 if (err
!= NULL
) *err
= NO_RECOVERY
;
737 if (tdata
->li_vm
== NULL
)
741 status
= LI_DSLookupGetProcedureNumber("gethostent", &proc
);
742 if (status
!= KERN_SUCCESS
)
744 if (err
!= NULL
) *err
= NO_RECOVERY
;
745 LI_data_free_kvarray(tdata
);
752 status
= LI_DSLookupQuery(proc
, NULL
, &reply
);
754 if (status
!= KERN_SUCCESS
)
756 if (err
!= NULL
) *err
= NO_RECOVERY
;
757 LI_data_free_kvarray(tdata
);
762 tdata
->li_vm
= (char *)reply
;
765 if (err
!= NULL
) *err
= 0;
767 vma
= (kvarray_t
*)(tdata
->li_vm
);
770 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
775 * gethostent only returns IPv4 addresses, but the reply
776 * from Directory Service may contain a mix of IPv4 and Ipv6
777 * entries. extract_host will return NULL if the current
778 * dictionary is not the family we want, so we loop until
779 * we get the next IPv4 entry or we run out of entries.
782 while ((vma
->curr
< vma
->count
) && (entry
== NULL
))
784 entry
= extract_host(vma
, WANT_A4_ONLY
);
789 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
790 LI_data_free_kvarray(tdata
);
798 static struct hostent
*
799 gethostbyaddrerrno(const char *addr
, int len
, uint32_t family
, int *err
)
801 struct hostent
*res
= NULL
;
802 int want
, add_to_cache
;
804 if (err
!= NULL
) *err
= 0;
807 if (family
== AF_INET6
) want
= WANT_A6_ONLY
;
809 if ((family
== AF_INET6
) && (len
== IPV6_ADDR_LEN
) && (is_a4_mapped((const char *)addr
) || is_a4_compat((const char *)addr
)))
814 want
= WANT_MAPPED_A4_ONLY
;
818 res
= cache_gethostbyaddr(addr
, want
);
823 else if (_ds_running())
825 res
= ds_gethostbyaddr(addr
, family
, err
);
826 if (res
!= NULL
) add_to_cache
= 1;
830 pthread_mutex_lock(&_host_lock
);
831 res
= copy_host(LI_files_gethostbyaddr(addr
, len
, family
));
832 if (err
!= NULL
) *err
= h_errno
;
833 pthread_mutex_unlock(&_host_lock
);
836 if (add_to_cache
== 1) cache_host(res
, want
, CACHE_BYADDR
);
842 gethostbyaddr(const void *addr
, socklen_t len
, int type
)
845 struct li_thread_info
*tdata
;
847 res
= gethostbyaddrerrno(addr
, len
, type
, &h_errno
);
848 if (res
== NULL
) return NULL
;
850 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
851 if (tdata
== NULL
) return NULL
;
853 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
854 return (struct hostent
*)tdata
->li_entry
;
858 gethostbynameerrno(const char *name
, int *err
)
860 struct hostent
*res
= NULL
;
862 int i
, is_addr
, add_to_cache
;
864 if (err
!= NULL
) *err
= 0;
867 * If name is all dots and digits without a trailing dot,
868 * call inet_aton. If it's OK, return a fake entry.
869 * Otherwise, return an error.
871 * If name has alpha or ends with a dot, proceed as usual...
875 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
881 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
886 for (i
= 0; name
[i
] != '\0'; i
++)
888 if (name
[i
] == '.') continue;
889 if ((name
[i
] >= '0') && (name
[i
] <= '9')) continue;
894 if ((is_addr
== 1) && (name
[i
-1] == '.')) is_addr
= 0;
901 if (inet_aton(name
, &addr
) == 0)
903 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
906 res
= fake_hostent(name
, addr
);
911 res
= cache_gethostbyname(name
, WANT_A4_ONLY
);
917 else if (_ds_running())
919 res
= ds_gethostbyname(name
, WANT_A4_ONLY
, err
);
920 if (res
!= NULL
) add_to_cache
= 1;
924 pthread_mutex_lock(&_host_lock
);
925 res
= copy_host(LI_files_gethostbyname(name
));
926 if (err
!= NULL
) *err
= h_errno
;
927 pthread_mutex_unlock(&_host_lock
);
932 if (inet_aton(name
, &addr
) == 0)
934 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
938 res
= gethostbyaddrerrno((char *)&addr
, sizeof(addr
), AF_INET
, err
);
941 res
= fake_hostent(name
, addr
);
945 if (add_to_cache
== 1) cache_host(res
, WANT_A4_ONLY
, CACHE_BYNAME
);
951 gethostbyname(const char *name
)
954 struct li_thread_info
*tdata
;
956 res
= gethostbynameerrno(name
, &h_errno
);
957 if (res
== NULL
) return NULL
;
959 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
960 if (tdata
== NULL
) return NULL
;
962 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
963 return (struct hostent
*)tdata
->li_entry
;
967 gethostbyname2(const char *name
, int family
)
970 struct li_thread_info
*tdata
;
972 res
= getipnodebyname(name
, family
, 0, &h_errno
);
975 errno
= EAFNOSUPPORT
;
979 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
980 if (tdata
== NULL
) return NULL
;
982 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
983 return (struct hostent
*)tdata
->li_entry
;
989 struct hostent
*res
= NULL
;
990 struct li_thread_info
*tdata
;
992 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
993 if (tdata
== NULL
) return NULL
;
997 res
= ds_gethostent(&h_errno
);
1001 pthread_mutex_lock(&_host_lock
);
1002 res
= copy_host(LI_files_gethostent());
1003 pthread_mutex_unlock(&_host_lock
);
1006 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
1007 return (struct hostent
*)tdata
->li_entry
;
1011 sethostent(int stayopen
)
1013 if (_ds_running()) ds_sethostent();
1014 else LI_files_sethostent(stayopen
);
1020 if (_ds_running()) ds_endhostent();
1021 else LI_files_endhostent();
1024 __private_extern__
int
1025 is_a4_mapped(const char *s
)
1030 if (s
== NULL
) return 0;
1032 for (i
= 0; i
< 10; i
++)
1035 if (c
!= 0x0) return 0;
1038 for (i
= 10; i
< 12; i
++)
1041 if (c
!= 0xff) return 0;
1047 __private_extern__
int
1048 is_a4_compat(const char *s
)
1053 if (s
== NULL
) return 0;
1055 for (i
= 0; i
< 12; i
++)
1058 if (c
!= 0x0) return 0;
1061 /* Check for :: and ::1 */
1062 for (i
= 13; i
< 15; i
++)
1064 /* anything non-zero in these 3 bytes means it's a V4 address */
1066 if (c
!= 0x0) return 1;
1069 /* Leading 15 bytes are all zero */
1071 if (c
== 0x0) return 0;
1072 if (c
== 0x1) return 0;
1078 getipnodebyaddr(const void *src
, size_t len
, int family
, int *err
)
1080 struct hostent
*res
;
1082 if (err
!= NULL
) *err
= 0;
1084 res
= gethostbyaddrerrno((const char *)src
, len
, family
, err
);
1085 if (res
== NULL
) return NULL
;
1087 if (res
->h_name
== NULL
)
1097 getipnodebyname(const char *name
, int family
, int flags
, int *err
)
1099 int status
, want
, if4
, if6
, add_to_cache
;
1100 struct hostent
*res
;
1101 struct ifaddrs
*ifa
, *ifap
;
1102 struct in_addr addr4
;
1103 struct in6_addr addr6
;
1105 memset(&addr4
, 0, sizeof(struct in_addr
));
1106 memset(&addr6
, 0, sizeof(struct in6_addr
));
1108 if (err
!= NULL
) *err
= 0;
1110 if (family
== AF_INET
)
1112 status
= inet_aton(name
, &addr4
);
1115 /* return a fake hostent */
1116 res
= fake_hostent(name
, addr4
);
1120 else if (family
== AF_INET6
)
1122 status
= inet_pton(family
, name
, &addr6
);
1125 /* return a fake hostent */
1126 res
= fake_hostent6(name
, addr6
);
1130 status
= inet_aton(name
, &addr4
);
1133 if (!(flags
& (AI_V4MAPPED
|AI_V4MAPPED_CFG
)))
1135 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
1139 addr6
.__u6_addr
.__u6_addr32
[0] = 0x00000000;
1140 addr6
.__u6_addr
.__u6_addr32
[1] = 0x00000000;
1141 addr6
.__u6_addr
.__u6_addr32
[2] = htonl(0x0000ffff);
1142 memmove(&(addr6
.__u6_addr
.__u6_addr32
[3]), &(addr4
.s_addr
), IPV4_ADDR_LEN
);
1144 /* return a fake hostent */
1145 res
= fake_hostent6(name
, addr6
);
1151 if (err
!= NULL
) *err
= NO_RECOVERY
;
1156 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1162 if (flags
& AI_ADDRCONFIG
)
1164 if (getifaddrs(&ifa
) < 0)
1166 if (err
!= NULL
) *err
= NO_RECOVERY
;
1170 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
)
1172 if (ifap
->ifa_addr
== NULL
) continue;
1173 if ((ifap
->ifa_flags
& IFF_UP
) == 0) continue;
1174 if (ifap
->ifa_addr
->sa_family
== AF_INET
) if4
++;
1175 else if (ifap
->ifa_addr
->sa_family
== AF_INET6
) if6
++;
1180 /* Bail out if there are no interfaces */
1181 if ((if4
== 0) && (if6
== 0))
1183 if (err
!= NULL
) *err
= NO_ADDRESS
;
1189 * Figure out what we want.
1190 * If user asked for AF_INET, we only want V4 addresses.
1192 want
= WANT_A4_ONLY
;
1194 if (family
== AF_INET
)
1196 if ((flags
& AI_ADDRCONFIG
) && (if4
== 0))
1198 if (err
!= NULL
) *err
= NO_ADDRESS
;
1204 /* family == AF_INET6 */
1205 want
= WANT_A6_ONLY
;
1207 if (flags
& (AI_V4MAPPED
| AI_V4MAPPED_CFG
))
1211 want
= WANT_A6_PLUS_MAPPED_A4
;
1215 want
= WANT_A6_OR_MAPPED_A4_IF_NO_A6
;
1220 if ((flags
& AI_ADDRCONFIG
) && (if6
== 0))
1222 if (err
!= NULL
) *err
= NO_ADDRESS
;
1229 res
= cache_gethostbyname(name
, want
);
1234 else if (_ds_running())
1236 res
= ds_gethostbyname(name
, want
, err
);
1237 if (res
!= NULL
) add_to_cache
= 1;
1241 pthread_mutex_lock(&_host_lock
);
1242 res
= copy_host(LI_files_gethostbyname2(name
, family
));
1243 if (err
!= NULL
) *err
= h_errno
;
1244 pthread_mutex_unlock(&_host_lock
);
1249 if (err
!= NULL
) *err
= HOST_NOT_FOUND
;
1253 if (add_to_cache
== 1) cache_host(res
, want
, CACHE_BYNAME
);
1259 ether_extract_mac(kvarray_t
*in
, struct ether_addr
*e
)
1261 uint32_t d
, k
, kcount
, t
[6];
1264 if (in
== NULL
) return -1;
1265 if (e
== NULL
) return -1;
1270 if (d
>= in
->count
) return -1;
1272 kcount
= in
->dict
[d
].kcount
;
1274 for (k
= 0; k
< kcount
; k
++)
1276 if (!strcmp(in
->dict
[d
].key
[k
], "mac"))
1278 if (in
->dict
[d
].vcount
[k
] == 0) continue;
1279 i
= sscanf(in
->dict
[d
].val
[k
][0], " %x:%x:%x:%x:%x:%x", &t
[0], &t
[1], &t
[2], &t
[3], &t
[4], &t
[5]);
1280 if (i
!= 6) return -1;
1281 for (i
= 0; i
< 6; i
++) e
->ether_addr_octet
[i
] = t
[i
];
1290 * Given a host's name, this routine returns its 48 bit ethernet address.
1291 * Returns zero if successful, non-zero otherwise.
1294 ds_ether_hostton(const char *host
, struct ether_addr
*e
)
1296 static int proc
= -1;
1299 kern_return_t status
;
1301 if (host
== NULL
) return -1;
1305 status
= LI_DSLookupGetProcedureNumber("getmacbyname", &proc
);
1306 if (status
!= KERN_SUCCESS
) return -1;
1309 request
= kvbuf_query_key_val("name", host
);
1310 if (request
== NULL
) return -1;
1313 status
= LI_DSLookupQuery(proc
, request
, &reply
);
1314 kvbuf_free(request
);
1316 if (status
!= KERN_SUCCESS
) return -1;
1318 status
= ether_extract_mac(reply
, e
);
1319 kvarray_free(reply
);
1325 ether_extract_name(kvarray_t
*in
, char *name
)
1327 uint32_t d
, k
, kcount
;
1329 if (in
== NULL
) return -1;
1330 if (name
== NULL
) return -1;
1335 if (d
>= in
->count
) return -1;
1337 kcount
= in
->dict
[d
].kcount
;
1339 for (k
= 0; k
< kcount
; k
++)
1341 if (!strcmp(in
->dict
[d
].key
[k
], "name"))
1343 memcpy(name
, in
->dict
[d
].val
[k
][0], strlen(in
->dict
[d
].val
[k
][0]) + 1);
1352 * Given a 48 bit ethernet address, this routine return its host name.
1353 * Returns zero if successful, non-zero otherwise.
1356 ds_ether_ntohost(char *host
, const struct ether_addr
*e
)
1360 static int proc
= -1;
1363 kern_return_t status
;
1365 if (host
== NULL
) return -1;
1366 if (e
== NULL
) return -1;
1370 status
= LI_DSLookupGetProcedureNumber("gethostbymac", &proc
);
1371 if (status
!= KERN_SUCCESS
) return -1;
1374 for (i
= 0; i
< 6; i
++) x
[i
] = e
->ether_addr_octet
[i
];
1375 sprintf(str
, "%x:%x:%x:%x:%x:%x", x
[0], x
[1], x
[2], x
[3], x
[4], x
[5]);
1377 request
= kvbuf_query_key_val("mac", str
);
1378 if (request
== NULL
) return -1;
1381 status
= LI_DSLookupQuery(proc
, request
, &reply
);
1382 kvbuf_free(request
);
1384 if (status
!= KERN_SUCCESS
) return -1;
1386 status
= ether_extract_name(reply
, host
);
1387 kvarray_free(reply
);
1393 ether_hostton(const char *host
, struct ether_addr
*e
)
1395 if (_ds_running()) return ds_ether_hostton(host
, e
);
1396 return _old_ether_hostton(host
, e
);
1400 ether_ntohost(char *host
, const struct ether_addr
*e
)
1402 if (_ds_running()) return ds_ether_ntohost(host
, e
);
1403 return _old_ether_ntohost(host
, e
);