Libinfo-278.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_host.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdlib.h>
26 #include <mach/mach.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <rpc/types.h>
30 #include <rpc/xdr.h>
31 #include <netdb.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <net/if.h>
35 #include <arpa/inet.h>
36 #include <pthread.h>
37 #include <errno.h>
38 #include <ifaddrs.h>
39 #include <sys/types.h>
40 #include <netinet/if_ether.h>
41 #include "lu_host.h"
42
43 #define ENTRY_SIZE sizeof(struct hostent)
44 #define ENTRY_KEY _li_data_key_host
45 #define HOST_CACHE_SIZE 20
46
47 #define CACHE_BYNAME 0
48 #define CACHE_BYADDR 1
49
50 static pthread_mutex_t _host_cache_lock = PTHREAD_MUTEX_INITIALIZER;
51
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;
55
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;
59
60 static unsigned int _host_cache_init = 0;
61
62 static pthread_mutex_t _host_lock = PTHREAD_MUTEX_INITIALIZER;
63
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();
70
71 extern int _old_ether_hostton(const char *, struct ether_addr *);
72 extern int _old_ether_ntohost(char *, const struct ether_addr *);
73
74 extern int h_errno;
75
76 #define IPV6_ADDR_LEN 16
77 #define IPV4_ADDR_LEN 4
78
79 void
80 freehostent(struct hostent *h)
81 {
82 char **aliases;
83 int i;
84
85 if (LI_ils_free(h, ENTRY_SIZE) == 0) return;
86
87 if (h->h_name != NULL) free(h->h_name);
88
89 aliases = h->h_aliases;
90 if (aliases != NULL)
91 {
92 while (*aliases != NULL) free(*aliases++);
93 free(h->h_aliases);
94 }
95
96 if (h->h_addr_list != NULL)
97 {
98 for (i = 0; h->h_addr_list[i] != NULL; i++) free(h->h_addr_list[i]);
99 free(h->h_addr_list);
100 }
101 free(h);
102 }
103
104 static struct hostent *
105 copy_host(struct hostent *in)
106 {
107 if (in == NULL) return NULL;
108
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);
111
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);
114
115 return NULL;
116 }
117
118 static void
119 _free_addr_list(char **l)
120 {
121 int i;
122
123 if (l == NULL) return;
124 for (i = 0; l[i] != NULL; i++) free(l[i]);
125 free(l);
126 }
127
128 /* map ipv4 addresses and append to v6 list */
129 static int
130 _map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4)
131 {
132 struct in6_addr a6;
133 uint32_t i;
134
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);
138
139 if (*v6 == NULL)
140 {
141 *v6 = (char **)calloc(n4 + 1, sizeof(char *));
142 }
143 else
144 {
145 *v6 = (char **)reallocf(*v6, (n6 + n4 + 1) * sizeof(char *));
146 }
147
148 if (*v6 == NULL) return -1;
149
150 for (i = 0; i < n4; i++)
151 {
152 (*v6)[n6] = (char *)calloc(1, IPV6_ADDR_LEN);
153 if ((*v6)[n6] == NULL) return -1;
154
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);
157
158 n6++;
159 }
160
161 return 0;
162 }
163
164 __private_extern__ struct hostent *
165 extract_host(kvarray_t *in, int want)
166 {
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;
171 struct in_addr a4;
172 struct in6_addr a6;
173 char **v4addrs, **v6addrs;
174 char *empty[1];
175
176 v4addrs = NULL;
177 v6addrs = NULL;
178 v4count = 0;
179 v6count = 0;
180 addr_count = 0;
181 addr_len = sizeof(void *);
182
183 if (in == NULL) return NULL;
184
185 d = in->curr;
186 in->curr++;
187
188 if (d >= in->count) return NULL;
189
190 empty[0] = NULL;
191 memset(&tmp, 0, ENTRY_SIZE);
192
193 family = AF_INET;
194 tmp.h_length = IPV4_ADDR_LEN;
195
196 if (want != WANT_A4_ONLY)
197 {
198 family = AF_INET6;
199 tmp.h_length = IPV6_ADDR_LEN;
200 }
201
202 tmp.h_addrtype = family;
203
204 kcount = in->dict[d].kcount;
205
206 for (k = 0; k < kcount; k++)
207 {
208 if (!strcmp(in->dict[d].key[k], "h_name"))
209 {
210 if (tmp.h_name != NULL) continue;
211
212 vcount = in->dict[d].vcount[k];
213 if (vcount == 0) continue;
214
215 tmp.h_name = (char *)in->dict[d].val[k][0];
216 }
217 else if (!strcmp(in->dict[d].key[k], "h_aliases"))
218 {
219 if (tmp.h_aliases != NULL) continue;
220
221 vcount = in->dict[d].vcount[k];
222 if (vcount == 0) continue;
223
224 tmp.h_aliases = (char **)in->dict[d].val[k];
225 }
226 else if (!strcmp(in->dict[d].key[k], "h_ipv4_addr_list"))
227 {
228 if (v4addrs != NULL) continue;
229
230 v4count = in->dict[d].vcount[k];
231 if (v4count == 0) continue;
232
233 v4addrs = (char **)calloc(v4count + 1, sizeof(char *));
234 if (v4addrs == NULL)
235 {
236 _free_addr_list(v6addrs);
237 return NULL;
238 }
239
240 for (i = 0; i < v4count; i++)
241 {
242 v4addrs[i] = calloc(1, IPV4_ADDR_LEN);
243 if (v4addrs[i] == NULL)
244 {
245 _free_addr_list(v4addrs);
246 _free_addr_list(v6addrs);
247 return NULL;
248 }
249
250 memset(&a4, 0, sizeof(struct in_addr));
251 status = inet_pton(AF_INET, in->dict[d].val[k][i], &a4);
252 if (status != 1)
253 {
254 _free_addr_list(v4addrs);
255 _free_addr_list(v6addrs);
256 return NULL;
257 }
258
259 memcpy(v4addrs[i], &a4, IPV4_ADDR_LEN);
260 }
261 }
262 else if (!strcmp(in->dict[d].key[k], "h_ipv6_addr_list"))
263 {
264 if (v6addrs != NULL) continue;
265
266 v6count = in->dict[d].vcount[k];
267 if (v6count == 0) continue;
268
269 v6addrs = (char **)calloc(v6count + 1, sizeof(char *));
270 if (v6addrs == NULL)
271 {
272 _free_addr_list(v4addrs);
273 return NULL;
274 }
275
276 for (i = 0; i < v6count; i++)
277 {
278 v6addrs[i] = calloc(1, IPV6_ADDR_LEN);
279 if (v6addrs[i] == NULL)
280 {
281 _free_addr_list(v4addrs);
282 _free_addr_list(v6addrs);
283 return NULL;
284 }
285
286 memset(&a6, 0, sizeof(struct in6_addr));
287 status = inet_pton(AF_INET6, in->dict[d].val[k][i], &a6);
288 if (status != 1)
289 {
290 _free_addr_list(v4addrs);
291 _free_addr_list(v6addrs);
292 return NULL;
293 }
294
295 memcpy(v6addrs[i], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
296 }
297 }
298 }
299
300 if (tmp.h_name == NULL) tmp.h_name = "";
301 if (tmp.h_aliases == NULL) tmp.h_aliases = empty;
302
303 if (want == WANT_A4_ONLY)
304 {
305 _free_addr_list(v6addrs);
306 if (v4addrs == NULL) return NULL;
307
308 tmp.h_addr_list = v4addrs;
309 out = copy_host(&tmp);
310 _free_addr_list(v4addrs);
311
312 return out;
313 }
314 else if ((want == WANT_A6_ONLY) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (v6count > 0)))
315 {
316 _free_addr_list(v4addrs);
317 if (v6addrs == NULL) return NULL;
318
319 tmp.h_addr_list = v6addrs;
320 out = copy_host(&tmp);
321 _free_addr_list(v6addrs);
322
323 return out;
324 }
325
326 /*
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.
330 */
331 if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_MAPPED_A4_ONLY;
332
333 if (want == WANT_MAPPED_A4_ONLY)
334 {
335 _free_addr_list(v6addrs);
336 v6addrs = NULL;
337 v6count = 0;
338 }
339
340 status = _map_v4(&v6addrs, v6count, v4addrs, v4count);
341 _free_addr_list(v4addrs);
342 if (status != 0)
343 {
344 _free_addr_list(v6addrs);
345 return NULL;
346 }
347
348 if (v6addrs == NULL) return NULL;
349
350 tmp.h_addr_list = v6addrs;
351 out = copy_host(&tmp);
352 _free_addr_list(v6addrs);
353
354 return out;
355 }
356
357 __private_extern__ struct hostent *
358 fake_hostent(const char *name, struct in_addr addr)
359 {
360 struct hostent tmp;
361 char *addrs[2];
362 char *aliases[1];
363
364 if (name == NULL) return NULL;
365
366 memset(&tmp, 0, ENTRY_SIZE);
367
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);
373 addrs[1] = NULL;
374 tmp.h_aliases = aliases;
375 aliases[0] = NULL;
376
377 return copy_host(&tmp);
378 }
379
380 __private_extern__ struct hostent *
381 fake_hostent6(const char *name, struct in6_addr addr)
382 {
383 struct hostent tmp;
384 char *addrs[2];
385 char *aliases[1];
386
387 if (name == NULL) return NULL;
388
389 memset(&tmp, 0, ENTRY_SIZE);
390
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]);
396 addrs[1] = NULL;
397 tmp.h_aliases = aliases;
398 aliases[0] = NULL;
399
400 return copy_host(&tmp);
401 }
402
403 static void
404 cache_host(struct hostent *h, int want, int how)
405 {
406 struct hostent *hcache;
407
408 if (h == NULL) return;
409
410 pthread_mutex_lock(&_host_cache_lock);
411
412 hcache = copy_host(h);
413
414 if (how == CACHE_BYNAME)
415 {
416 if (_host_byname_cache[_host_byname_cache_index] != NULL) LI_ils_free(_host_byname_cache[_host_byname_cache_index], ENTRY_SIZE);
417
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;
421 }
422 else
423 {
424 if (_host_byaddr_cache[_host_byaddr_cache_index] != NULL) LI_ils_free(_host_byaddr_cache[_host_byaddr_cache_index], ENTRY_SIZE);
425
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;
429 }
430
431 _host_cache_init = 1;
432
433 pthread_mutex_unlock(&_host_cache_lock);
434 }
435
436 static int
437 host_cache_check()
438 {
439 uint32_t i, status;
440
441 /* don't consult cache if it has not been initialized */
442 if (_host_cache_init == 0) return 1;
443
444 status = LI_L1_cache_check(ENTRY_KEY);
445
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;
448
449 /* return 0 if cache is OK */
450 if (status == LI_L1_CACHE_OK) return 0;
451
452 /* flush cache */
453 pthread_mutex_lock(&_host_cache_lock);
454
455 for (i = 0; i < HOST_CACHE_SIZE; i++)
456 {
457 LI_ils_free(_host_byname_cache[i], ENTRY_SIZE);
458 _host_byname_cache[i] = NULL;
459 _host_byname_cache_flavor[i] = WANT_NOTHING;
460
461 LI_ils_free(_host_byaddr_cache[i], ENTRY_SIZE);
462 _host_byaddr_cache[i] = NULL;
463 _host_byaddr_cache_flavor[i] = WANT_NOTHING;
464 }
465
466 _host_byname_cache_index = 0;
467 _host_byaddr_cache_index = 0;
468
469 pthread_mutex_unlock(&_host_cache_lock);
470
471 /* don't consult cache - it's now empty */
472 return 1;
473 }
474
475
476 static struct hostent *
477 cache_gethostbyname(const char *name, int want)
478 {
479 int i;
480 struct hostent *h, *res;
481 char **aliases;
482
483 if (name == NULL) return NULL;
484 if (host_cache_check() != 0) return NULL;
485
486 pthread_mutex_lock(&_host_cache_lock);
487
488 for (i = 0; i < HOST_CACHE_SIZE; i++)
489 {
490 if (_host_byname_cache_flavor[i] != want) continue;
491
492 h = (struct hostent *)_host_byname_cache[i];
493 if (h == NULL) continue;
494
495 if (h->h_name != NULL)
496 {
497 if (!strcmp(name, h->h_name))
498 {
499 res = copy_host(h);
500 pthread_mutex_unlock(&_host_cache_lock);
501 return res;
502 }
503 }
504
505 aliases = h->h_aliases;
506 if (aliases == NULL)
507 {
508 pthread_mutex_unlock(&_host_cache_lock);
509 return NULL;
510 }
511
512 for (; *aliases != NULL; *aliases++)
513 {
514 if (!strcmp(name, *aliases))
515 {
516 res = copy_host(h);
517 pthread_mutex_unlock(&_host_cache_lock);
518 return res;
519 }
520 }
521 }
522
523 pthread_mutex_unlock(&_host_cache_lock);
524 return NULL;
525 }
526
527 static struct hostent *
528 cache_gethostbyaddr(const char *addr, int want)
529 {
530 int i, j, len;
531 struct hostent *h, *res;
532
533 if (addr == NULL) return NULL;
534 if (host_cache_check() != 0) return NULL;
535
536 pthread_mutex_lock(&_host_cache_lock);
537
538 len = IPV4_ADDR_LEN;
539 if (want > WANT_A4_ONLY) len = IPV6_ADDR_LEN;
540
541 for (i = 0; i < HOST_CACHE_SIZE; i++)
542 {
543 if (_host_byaddr_cache_flavor[i] != want) continue;
544
545 h = (struct hostent *)_host_byaddr_cache[i];
546 if (h == NULL) continue;
547
548 if (h->h_addr_list == NULL) continue;
549
550 for (j = 0; h->h_addr_list[j] != NULL; j++)
551 {
552 if (memcmp(addr, h->h_addr_list[j], len) == 0)
553 {
554 res = copy_host(h);
555 pthread_mutex_unlock(&_host_cache_lock);
556 return res;
557 }
558 }
559 }
560
561 pthread_mutex_unlock(&_host_cache_lock);
562 return NULL;
563 }
564
565 static struct hostent *
566 ds_gethostbyaddr(const char *paddr, uint32_t family, int *err)
567 {
568 struct hostent *entry;
569 kvbuf_t *request;
570 kvarray_t *reply;
571 kern_return_t status;
572 static int proc = -1;
573 struct in_addr addr4;
574 struct in6_addr addr6;
575 char tmp[64];
576 int want;
577
578 if (paddr == NULL)
579 {
580 if (err != NULL) *err = NO_RECOVERY;
581 return NULL;
582 }
583
584 if (proc < 0)
585 {
586 status = LI_DSLookupGetProcedureNumber("gethostbyaddr", &proc);
587 if (status != KERN_SUCCESS)
588 {
589 if (err != NULL) *err = NO_RECOVERY;
590 return NULL;
591 }
592 }
593
594 memset(&addr4, 0, sizeof(struct in_addr));
595 memset(&addr6, 0, sizeof(struct in6_addr));
596 memset(tmp, 0, sizeof(tmp));
597 want = WANT_A4_ONLY;
598
599 if (family == AF_INET)
600 {
601 want = WANT_A4_ONLY;
602 memcpy(&(addr4.s_addr), paddr, IPV4_ADDR_LEN);
603 if (inet_ntop(family, &addr4, tmp, sizeof(tmp)) == NULL)
604 {
605 if (err != NULL) *err = NO_RECOVERY;
606 return NULL;
607 }
608 }
609 else if (family == AF_INET6)
610 {
611 want = WANT_A6_ONLY;
612 memcpy(addr6.s6_addr, paddr, IPV6_ADDR_LEN);
613 if (inet_ntop(family, &addr6, tmp, sizeof(tmp)) == NULL)
614 {
615 if (err != NULL) *err = NO_RECOVERY;
616 return NULL;
617 }
618 }
619 else
620 {
621 if (err != NULL) *err = NO_RECOVERY;
622 return NULL;
623 }
624
625 request = kvbuf_query("ksku", "address", tmp, "family", family);
626 if (request == NULL)
627 {
628 if (err != NULL) *err = NO_RECOVERY;
629 return NULL;
630 }
631
632 reply = NULL;
633 status = LI_DSLookupQuery(proc, request, &reply);
634 kvbuf_free(request);
635
636 if (status != KERN_SUCCESS)
637 {
638 if (err != NULL) *err = NO_RECOVERY;
639 return NULL;
640 }
641
642 if (err != NULL) *err = 0;
643 entry = extract_host(reply, want);
644
645 if ((entry == NULL) && (err != NULL)) *err = HOST_NOT_FOUND;
646 kvarray_free(reply);
647
648 return entry;
649 }
650
651 static struct hostent *
652 ds_gethostbyname(const char *name, uint32_t want, int *err)
653 {
654 struct hostent *entry;
655 kvbuf_t *request;
656 kvarray_t *reply;
657 kern_return_t status;
658 static int proc = -1;
659 uint32_t want4, want6;
660
661 want4 = 1;
662 want6 = 1;
663
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;
667
668 if (name == NULL)
669 {
670 if (err != NULL) *err = NO_RECOVERY;
671 return NULL;
672 }
673
674 if (proc < 0)
675 {
676 status = LI_DSLookupGetProcedureNumber("gethostbyname", &proc);
677 if (status != KERN_SUCCESS)
678 {
679 if (err != NULL) *err = NO_RECOVERY;
680 return NULL;
681 }
682 }
683
684 request = kvbuf_query("kskuku", "name", name, "ipv4", want4, "ipv6", want6);
685 if (request == NULL)
686 {
687 if (err != NULL) *err = NO_RECOVERY;
688 return NULL;
689 }
690
691 reply = NULL;
692 status = LI_DSLookupQuery(proc, request, &reply);
693 kvbuf_free(request);
694
695 if (status != KERN_SUCCESS)
696 {
697 if (err != NULL) *err = NO_RECOVERY;
698 return NULL;
699 }
700
701 if (err != NULL) *err = 0;
702 entry = extract_host(reply, want);
703 if ((entry == NULL) && (err != NULL)) *err = HOST_NOT_FOUND;
704 kvarray_free(reply);
705
706 return entry;
707 }
708
709 static void
710 ds_endhostent()
711 {
712 LI_data_free_kvarray(LI_data_find_key(ENTRY_KEY));
713 }
714
715 static void
716 ds_sethostent()
717 {
718 ds_endhostent();
719 }
720
721 static struct hostent *
722 ds_gethostent(int *err)
723 {
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;
729
730 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
731 if (tdata == NULL)
732 {
733 if (err != NULL) *err = NO_RECOVERY;
734 return NULL;
735 }
736
737 if (tdata->li_vm == NULL)
738 {
739 if (proc < 0)
740 {
741 status = LI_DSLookupGetProcedureNumber("gethostent", &proc);
742 if (status != KERN_SUCCESS)
743 {
744 if (err != NULL) *err = NO_RECOVERY;
745 LI_data_free_kvarray(tdata);
746 tdata->li_vm = NULL;
747 return NULL;
748 }
749 }
750
751 reply = NULL;
752 status = LI_DSLookupQuery(proc, NULL, &reply);
753
754 if (status != KERN_SUCCESS)
755 {
756 if (err != NULL) *err = NO_RECOVERY;
757 LI_data_free_kvarray(tdata);
758 tdata->li_vm = NULL;
759 return NULL;
760 }
761
762 tdata->li_vm = (char *)reply;
763 }
764
765 if (err != NULL) *err = 0;
766
767 vma = (kvarray_t *)(tdata->li_vm);
768 if (vma == NULL)
769 {
770 if (err != NULL) *err = HOST_NOT_FOUND;
771 return NULL;
772 }
773
774 /*
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.
780 */
781 entry = NULL;
782 while ((vma->curr < vma->count) && (entry == NULL))
783 {
784 entry = extract_host(vma, WANT_A4_ONLY);
785 }
786
787 if (entry == NULL)
788 {
789 if (err != NULL) *err = HOST_NOT_FOUND;
790 LI_data_free_kvarray(tdata);
791 tdata->li_vm = NULL;
792 return NULL;
793 }
794
795 return entry;
796 }
797
798 static struct hostent *
799 gethostbyaddrerrno(const char *addr, int len, uint32_t family, int *err)
800 {
801 struct hostent *res = NULL;
802 int want, add_to_cache;
803
804 if (err != NULL) *err = 0;
805
806 want = WANT_A4_ONLY;
807 if (family == AF_INET6) want = WANT_A6_ONLY;
808
809 if ((family == AF_INET6) && (len == IPV6_ADDR_LEN) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr)))
810 {
811 addr += 12;
812 len = 4;
813 family = AF_INET;
814 want = WANT_MAPPED_A4_ONLY;
815 }
816
817 add_to_cache = 0;
818 res = cache_gethostbyaddr(addr, want);
819
820 if (res != NULL)
821 {
822 }
823 else if (_ds_running())
824 {
825 res = ds_gethostbyaddr(addr, family, err);
826 if (res != NULL) add_to_cache = 1;
827 }
828 else
829 {
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);
834 }
835
836 if (add_to_cache == 1) cache_host(res, want, CACHE_BYADDR);
837
838 return res;
839 }
840
841 struct hostent *
842 gethostbyaddr(const void *addr, socklen_t len, int type)
843 {
844 struct hostent *res;
845 struct li_thread_info *tdata;
846
847 res = gethostbyaddrerrno(addr, len, type, &h_errno);
848 if (res == NULL) return NULL;
849
850 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
851 if (tdata == NULL) return NULL;
852
853 LI_data_recycle(tdata, res, ENTRY_SIZE);
854 return (struct hostent *)tdata->li_entry;
855 }
856
857 struct hostent *
858 gethostbynameerrno(const char *name, int *err)
859 {
860 struct hostent *res = NULL;
861 struct in_addr addr;
862 int i, is_addr, add_to_cache;
863
864 if (err != NULL) *err = 0;
865
866 /*
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.
870 *
871 * If name has alpha or ends with a dot, proceed as usual...
872 */
873 if (name == NULL)
874 {
875 if (err != NULL) *err = HOST_NOT_FOUND;
876 return NULL;
877 }
878
879 if (name[0] == '\0')
880 {
881 if (err != NULL) *err = HOST_NOT_FOUND;
882 return NULL;
883 }
884
885 is_addr = 1;
886 for (i = 0; name[i] != '\0'; i++)
887 {
888 if (name[i] == '.') continue;
889 if ((name[i] >= '0') && (name[i] <= '9')) continue;
890 is_addr = 0;
891 break;
892 }
893
894 if ((is_addr == 1) && (name[i-1] == '.')) is_addr = 0;
895
896 res = NULL;
897 add_to_cache = 0;
898
899 if (is_addr == 1)
900 {
901 if (inet_aton(name, &addr) == 0)
902 {
903 if (err != NULL) *err = HOST_NOT_FOUND;
904 return NULL;
905 }
906 res = fake_hostent(name, addr);
907 }
908
909 if (res == NULL)
910 {
911 res = cache_gethostbyname(name, WANT_A4_ONLY);
912 }
913
914 if (res != NULL)
915 {
916 }
917 else if (_ds_running())
918 {
919 res = ds_gethostbyname(name, WANT_A4_ONLY, err);
920 if (res != NULL) add_to_cache = 1;
921 }
922 else
923 {
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);
928 }
929
930 if (res == NULL)
931 {
932 if (inet_aton(name, &addr) == 0)
933 {
934 if (err != NULL) *err = HOST_NOT_FOUND;
935 return NULL;
936 }
937
938 res = gethostbyaddrerrno((char *)&addr, sizeof(addr), AF_INET, err);
939 if (res == NULL)
940 {
941 res = fake_hostent(name, addr);
942 }
943 }
944
945 if (add_to_cache == 1) cache_host(res, WANT_A4_ONLY, CACHE_BYNAME);
946
947 return res;
948 }
949
950 struct hostent *
951 gethostbyname(const char *name)
952 {
953 struct hostent *res;
954 struct li_thread_info *tdata;
955
956 res = gethostbynameerrno(name, &h_errno);
957 if (res == NULL) return NULL;
958
959 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
960 if (tdata == NULL) return NULL;
961
962 LI_data_recycle(tdata, res, ENTRY_SIZE);
963 return (struct hostent *)tdata->li_entry;
964 }
965
966 struct hostent *
967 gethostbyname2(const char *name, int family)
968 {
969 struct hostent *res;
970 struct li_thread_info *tdata;
971
972 res = getipnodebyname(name, family, 0, &h_errno);
973 if (res == NULL)
974 {
975 errno = EAFNOSUPPORT;
976 return NULL;
977 }
978
979 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
980 if (tdata == NULL) return NULL;
981
982 LI_data_recycle(tdata, res, ENTRY_SIZE);
983 return (struct hostent *)tdata->li_entry;
984 }
985
986 struct hostent *
987 gethostent(void)
988 {
989 struct hostent *res = NULL;
990 struct li_thread_info *tdata;
991
992 tdata = LI_data_create_key(ENTRY_KEY, ENTRY_SIZE);
993 if (tdata == NULL) return NULL;
994
995 if (_ds_running())
996 {
997 res = ds_gethostent(&h_errno);
998 }
999 else
1000 {
1001 pthread_mutex_lock(&_host_lock);
1002 res = copy_host(LI_files_gethostent());
1003 pthread_mutex_unlock(&_host_lock);
1004 }
1005
1006 LI_data_recycle(tdata, res, ENTRY_SIZE);
1007 return (struct hostent *)tdata->li_entry;
1008 }
1009
1010 void
1011 sethostent(int stayopen)
1012 {
1013 if (_ds_running()) ds_sethostent();
1014 else LI_files_sethostent(stayopen);
1015 }
1016
1017 void
1018 endhostent(void)
1019 {
1020 if (_ds_running()) ds_endhostent();
1021 else LI_files_endhostent();
1022 }
1023
1024 __private_extern__ int
1025 is_a4_mapped(const char *s)
1026 {
1027 int i;
1028 u_int8_t c;
1029
1030 if (s == NULL) return 0;
1031
1032 for (i = 0; i < 10; i++)
1033 {
1034 c = s[i];
1035 if (c != 0x0) return 0;
1036 }
1037
1038 for (i = 10; i < 12; i++)
1039 {
1040 c = s[i];
1041 if (c != 0xff) return 0;
1042 }
1043
1044 return 1;
1045 }
1046
1047 __private_extern__ int
1048 is_a4_compat(const char *s)
1049 {
1050 int i;
1051 u_int8_t c;
1052
1053 if (s == NULL) return 0;
1054
1055 for (i = 0; i < 12; i++)
1056 {
1057 c = s[i];
1058 if (c != 0x0) return 0;
1059 }
1060
1061 /* Check for :: and ::1 */
1062 for (i = 13; i < 15; i++)
1063 {
1064 /* anything non-zero in these 3 bytes means it's a V4 address */
1065 c = s[i];
1066 if (c != 0x0) return 1;
1067 }
1068
1069 /* Leading 15 bytes are all zero */
1070 c = s[15];
1071 if (c == 0x0) return 0;
1072 if (c == 0x1) return 0;
1073
1074 return 1;
1075 }
1076
1077 struct hostent *
1078 getipnodebyaddr(const void *src, size_t len, int family, int *err)
1079 {
1080 struct hostent *res;
1081
1082 if (err != NULL) *err = 0;
1083
1084 res = gethostbyaddrerrno((const char *)src, len, family, err);
1085 if (res == NULL) return NULL;
1086
1087 if (res->h_name == NULL)
1088 {
1089 freehostent(res);
1090 return NULL;
1091 }
1092
1093 return res;
1094 }
1095
1096 struct hostent *
1097 getipnodebyname(const char *name, int family, int flags, int *err)
1098 {
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;
1104
1105 memset(&addr4, 0, sizeof(struct in_addr));
1106 memset(&addr6, 0, sizeof(struct in6_addr));
1107
1108 if (err != NULL) *err = 0;
1109
1110 if (family == AF_INET)
1111 {
1112 status = inet_aton(name, &addr4);
1113 if (status == 1)
1114 {
1115 /* return a fake hostent */
1116 res = fake_hostent(name, addr4);
1117 return res;
1118 }
1119 }
1120 else if (family == AF_INET6)
1121 {
1122 status = inet_pton(family, name, &addr6);
1123 if (status == 1)
1124 {
1125 /* return a fake hostent */
1126 res = fake_hostent6(name, addr6);
1127 return res;
1128 }
1129
1130 status = inet_aton(name, &addr4);
1131 if (status == 1)
1132 {
1133 if (!(flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)))
1134 {
1135 if (err != NULL) *err = HOST_NOT_FOUND;
1136 return NULL;
1137 }
1138
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);
1143
1144 /* return a fake hostent */
1145 res = fake_hostent6(name, addr6);
1146 return res;
1147 }
1148 }
1149 else
1150 {
1151 if (err != NULL) *err = NO_RECOVERY;
1152 return NULL;
1153 }
1154
1155 /*
1156 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1157 */
1158
1159 if4 = 0;
1160 if6 = 0;
1161
1162 if (flags & AI_ADDRCONFIG)
1163 {
1164 if (getifaddrs(&ifa) < 0)
1165 {
1166 if (err != NULL) *err = NO_RECOVERY;
1167 return NULL;
1168 }
1169
1170 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
1171 {
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++;
1176 }
1177
1178 freeifaddrs(ifa);
1179
1180 /* Bail out if there are no interfaces */
1181 if ((if4 == 0) && (if6 == 0))
1182 {
1183 if (err != NULL) *err = NO_ADDRESS;
1184 return NULL;
1185 }
1186 }
1187
1188 /*
1189 * Figure out what we want.
1190 * If user asked for AF_INET, we only want V4 addresses.
1191 */
1192 want = WANT_A4_ONLY;
1193
1194 if (family == AF_INET)
1195 {
1196 if ((flags & AI_ADDRCONFIG) && (if4 == 0))
1197 {
1198 if (err != NULL) *err = NO_ADDRESS;
1199 return NULL;
1200 }
1201 }
1202 else
1203 {
1204 /* family == AF_INET6 */
1205 want = WANT_A6_ONLY;
1206
1207 if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
1208 {
1209 if (flags & AI_ALL)
1210 {
1211 want = WANT_A6_PLUS_MAPPED_A4;
1212 }
1213 else
1214 {
1215 want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
1216 }
1217 }
1218 else
1219 {
1220 if ((flags & AI_ADDRCONFIG) && (if6 == 0))
1221 {
1222 if (err != NULL) *err = NO_ADDRESS;
1223 return NULL;
1224 }
1225 }
1226 }
1227
1228 add_to_cache = 0;
1229 res = cache_gethostbyname(name, want);
1230
1231 if (res != NULL)
1232 {
1233 }
1234 else if (_ds_running())
1235 {
1236 res = ds_gethostbyname(name, want, err);
1237 if (res != NULL) add_to_cache = 1;
1238 }
1239 else
1240 {
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);
1245 }
1246
1247 if (res == NULL)
1248 {
1249 if (err != NULL) *err = HOST_NOT_FOUND;
1250 return NULL;
1251 }
1252
1253 if (add_to_cache == 1) cache_host(res, want, CACHE_BYNAME);
1254
1255 return res;
1256 }
1257
1258 static int
1259 ether_extract_mac(kvarray_t *in, struct ether_addr *e)
1260 {
1261 uint32_t d, k, kcount, t[6];
1262 int i;
1263
1264 if (in == NULL) return -1;
1265 if (e == NULL) return -1;
1266
1267 d = in->curr;
1268 in->curr++;
1269
1270 if (d >= in->count) return -1;
1271
1272 kcount = in->dict[d].kcount;
1273
1274 for (k = 0; k < kcount; k++)
1275 {
1276 if (!strcmp(in->dict[d].key[k], "mac"))
1277 {
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];
1282 return 0;
1283 }
1284 }
1285
1286 return -1;
1287 }
1288
1289 /*
1290 * Given a host's name, this routine returns its 48 bit ethernet address.
1291 * Returns zero if successful, non-zero otherwise.
1292 */
1293 static int
1294 ds_ether_hostton(const char *host, struct ether_addr *e)
1295 {
1296 static int proc = -1;
1297 kvbuf_t *request;
1298 kvarray_t *reply;
1299 kern_return_t status;
1300
1301 if (host == NULL) return -1;
1302
1303 if (proc < 0)
1304 {
1305 status = LI_DSLookupGetProcedureNumber("getmacbyname", &proc);
1306 if (status != KERN_SUCCESS) return -1;
1307 }
1308
1309 request = kvbuf_query_key_val("name", host);
1310 if (request == NULL) return -1;
1311
1312 reply = NULL;
1313 status = LI_DSLookupQuery(proc, request, &reply);
1314 kvbuf_free(request);
1315
1316 if (status != KERN_SUCCESS) return -1;
1317
1318 status = ether_extract_mac(reply, e);
1319 kvarray_free(reply);
1320
1321 return status;
1322 }
1323
1324 static int
1325 ether_extract_name(kvarray_t *in, char *name)
1326 {
1327 uint32_t d, k, kcount;
1328
1329 if (in == NULL) return -1;
1330 if (name == NULL) return -1;
1331
1332 d = in->curr;
1333 in->curr++;
1334
1335 if (d >= in->count) return -1;
1336
1337 kcount = in->dict[d].kcount;
1338
1339 for (k = 0; k < kcount; k++)
1340 {
1341 if (!strcmp(in->dict[d].key[k], "name"))
1342 {
1343 memcpy(name, in->dict[d].val[k][0], strlen(in->dict[d].val[k][0]) + 1);
1344 return 0;
1345 }
1346 }
1347
1348 return -1;
1349 }
1350
1351 /*
1352 * Given a 48 bit ethernet address, this routine return its host name.
1353 * Returns zero if successful, non-zero otherwise.
1354 */
1355 static int
1356 ds_ether_ntohost(char *host, const struct ether_addr *e)
1357 {
1358 uint32_t i, x[6];
1359 char str[256];
1360 static int proc = -1;
1361 kvbuf_t *request;
1362 kvarray_t *reply;
1363 kern_return_t status;
1364
1365 if (host == NULL) return -1;
1366 if (e == NULL) return -1;
1367
1368 if (proc < 0)
1369 {
1370 status = LI_DSLookupGetProcedureNumber("gethostbymac", &proc);
1371 if (status != KERN_SUCCESS) return -1;
1372 }
1373
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]);
1376
1377 request = kvbuf_query_key_val("mac", str);
1378 if (request == NULL) return -1;
1379
1380 reply = NULL;
1381 status = LI_DSLookupQuery(proc, request, &reply);
1382 kvbuf_free(request);
1383
1384 if (status != KERN_SUCCESS) return -1;
1385
1386 status = ether_extract_name(reply, host);
1387 kvarray_free(reply);
1388
1389 return status;
1390 }
1391
1392 int
1393 ether_hostton(const char *host, struct ether_addr *e)
1394 {
1395 if (_ds_running()) return ds_ether_hostton(host, e);
1396 return _old_ether_hostton(host, e);
1397 }
1398
1399 int
1400 ether_ntohost(char *host, const struct ether_addr *e)
1401 {
1402 if (_ds_running()) return ds_ether_ntohost(host, e);
1403 return _old_ether_ntohost(host, e);
1404 }