Libinfo-173.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include <stdlib.h>
27 #include <mach/mach.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <rpc/types.h>
31 #include <rpc/xdr.h>
32 #include <netdb.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <net/if.h>
36 #include <arpa/inet.h>
37 #include <pthread.h>
38 #include <ifaddrs.h>
39
40 #include "_lu_types.h"
41 #include "lookup.h"
42 #include "lu_host.h"
43 #include "lu_utils.h"
44
45 #define HOST_CACHE_SIZE 10
46 #define DEFAULT_HOST_CACHE_TTL 10
47
48 #define CACHE_BYNAME 0
49 #define CACHE_BYADDR 1
50
51 static pthread_mutex_t _host_cache_lock = PTHREAD_MUTEX_INITIALIZER;
52 static unsigned int _host_cache_ttl = DEFAULT_HOST_CACHE_TTL;
53
54 static void *_host_byname_cache[HOST_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
55 static int _host_byname_cache_flavor[HOST_CACHE_SIZE] = { WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING };
56 static unsigned int _host_byname_cache_best_before[HOST_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
57 static unsigned int _host_byname_cache_index = 0;
58
59 static void *_host_byaddr_cache[HOST_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
60 static int _host_byaddr_cache_flavor[HOST_CACHE_SIZE] = { WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING, WANT_NOTHING };
61 static unsigned int _host_byaddr_cache_best_before[HOST_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
62 static unsigned int _host_byaddr_cache_index = 0;
63
64 static pthread_mutex_t _host_lock = PTHREAD_MUTEX_INITIALIZER;
65
66 extern struct hostent *_res_gethostbyaddr();
67 extern struct hostent *_res_gethostbyname();
68 extern struct hostent *_old_gethostbyaddr();
69 extern struct hostent *_old_gethostbyname();
70 extern struct hostent *_old_gethostent();
71 extern void _old_sethostent();
72 extern void _old_endhostent();
73 extern void _old_sethostfile();
74
75 extern mach_port_t _lu_port;
76 extern int _lu_running(void);
77
78 extern int h_errno;
79
80 #define IPV6_ADDR_LEN 16
81 #define IPV4_ADDR_LEN 4
82
83 __private_extern__ void
84 free_host_data(struct hostent *h)
85 {
86 char **aliases;
87 int i;
88
89 if (h == NULL) return;
90
91 if (h->h_name != NULL) free(h->h_name);
92
93 aliases = h->h_aliases;
94 if (aliases != NULL)
95 {
96 while (*aliases != NULL) free(*aliases++);
97 free(h->h_aliases);
98 }
99
100 if (h->h_addr_list != NULL)
101 {
102 for (i = 0; h->h_addr_list[i] != NULL; i++) free(h->h_addr_list[i]);
103 free(h->h_addr_list);
104 }
105 }
106
107 void
108 freehostent(struct hostent *h)
109 {
110 if (h == NULL) return;
111 free_host_data(h);
112 free(h);
113 }
114
115 static void
116 free_lu_thread_info_host(void *x)
117 {
118 struct lu_thread_info *tdata;
119
120 if (x == NULL) return;
121
122 tdata = (struct lu_thread_info *)x;
123
124 if (tdata->lu_entry != NULL)
125 {
126 freehostent((struct hostent *)tdata->lu_entry);
127 tdata->lu_entry = NULL;
128 }
129
130 _lu_data_free_vm_xdr(tdata);
131
132 free(tdata);
133 }
134
135 __private_extern__ struct hostent *
136 extract_host(XDR *xdr, int want, int *err)
137 {
138 struct hostent *h;
139 int i, j, nvals, nkeys, status, addr_len;
140 int family, addr_count, map_count;
141 struct in_addr addr;
142 struct in6_addr addr6;
143 char *key, **vals, **mapvals;
144
145 mapvals = NULL;
146 map_count = 0;
147 addr_count = 0;
148 addr_len = sizeof(u_long *);
149
150 if (xdr == NULL)
151 {
152 *err = NO_RECOVERY;
153 return NULL;
154 }
155
156 if (!xdr_int(xdr, &nkeys))
157 {
158 *err = NO_RECOVERY;
159 return NULL;
160 }
161
162 h = (struct hostent *)calloc(1, sizeof(struct hostent));
163
164 family = AF_INET;
165 h->h_length = IPV4_ADDR_LEN;
166
167 if (want > WANT_A4_ONLY)
168 {
169 family = AF_INET6;
170 h->h_length = IPV6_ADDR_LEN;
171 }
172
173 h->h_addrtype = family;
174
175 for (i = 0; i < nkeys; i++)
176 {
177 key = NULL;
178 vals = NULL;
179 nvals = 0;
180
181 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
182 if (status < 0)
183 {
184 freehostent(h);
185 *err = NO_RECOVERY;
186 return NULL;
187 }
188
189 if (nvals == 0)
190 {
191 free(key);
192 continue;
193 }
194
195 j = 0;
196
197 if ((h->h_name == NULL) && (!strcmp("name", key)))
198 {
199 h->h_name = vals[0];
200 if (nvals > 1)
201 {
202 h->h_aliases = (char **)calloc(nvals, sizeof(char *));
203 for (j = 1; j < nvals; j++) h->h_aliases[j-1] = vals[j];
204 }
205 j = nvals;
206 }
207 else if ((family == AF_INET) && (h->h_addr_list == NULL) && (!strcmp("ip_address", key)))
208 {
209 addr_count = nvals;
210 h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
211
212 for (j = 0; j < nvals; j++)
213 {
214 addr.s_addr = 0;
215 inet_aton(vals[j], &addr);
216 h->h_addr_list[j] = (char *)calloc(1, IPV4_ADDR_LEN);
217 memmove(h->h_addr_list[j], &(addr.s_addr), IPV4_ADDR_LEN);
218 }
219
220 h->h_addr_list[nvals] = NULL;
221 j = 0;
222 }
223 else if ((family == AF_INET6) && (h->h_addr_list == NULL) && (!strcmp("ipv6_address", key)))
224 {
225 addr_count = nvals;
226 h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
227
228 for (j = 0; j < nvals; j++)
229 {
230 memset(&addr6, 0, sizeof(struct in6_addr));
231 inet_pton(family, vals[j], &addr6);
232 h->h_addr_list[j] = (char *)calloc(1, IPV6_ADDR_LEN);
233 memmove(h->h_addr_list[j], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
234 }
235
236 h->h_addr_list[nvals] = NULL;
237 j = 0;
238 }
239 else if ((family == AF_INET6) && (mapvals == NULL) && (!strcmp("ip_address", key)))
240 {
241 map_count = nvals;
242 mapvals = vals;
243 vals = NULL;
244 }
245
246 free(key);
247 if (vals != NULL)
248 {
249 for (; j < nvals; j++) free(vals[j]);
250 free(vals);
251 }
252 }
253
254 if ((mapvals != NULL) && (want > WANT_A6_ONLY))
255 {
256 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
257 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
258 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
259
260 if (addr_count == 0)
261 {
262 h->h_addr_list = (char **)calloc(map_count + 1, addr_len);
263 }
264 else
265 {
266 h->h_addr_list = (char **)realloc(h->h_addr_list, (addr_count + map_count + 1) * addr_len);
267 }
268
269 for (i = 0; i < map_count; i++)
270 {
271 addr.s_addr = 0;
272 inet_aton(mapvals[i], &addr);
273 h->h_addr_list[addr_count] = (char *)calloc(1, IPV6_ADDR_LEN);
274 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr.s_addr), IPV4_ADDR_LEN);
275 memcpy(h->h_addr_list[addr_count++], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
276 }
277
278 h->h_addr_list[addr_count] = NULL;
279 }
280
281 if (mapvals != NULL)
282 {
283 for (i = 0; i < map_count; i++) free(mapvals[i]);
284 free(mapvals);
285 }
286
287 if (h->h_addr_list == NULL)
288 {
289 freehostent(h);
290 *err = NO_DATA;
291 return NULL;
292 }
293
294 if (h->h_name == NULL) h->h_name = strdup("");
295 if (h->h_aliases == NULL) h->h_aliases = (char **)calloc(1, sizeof(char *));
296
297 return h;
298 }
299
300 static struct hostent *
301 copy_host(struct hostent *in)
302 {
303 int i, len, addr_len;
304 struct hostent *h;
305
306 if (in == NULL) return NULL;
307
308 h = (struct hostent *)calloc(1, sizeof(struct hostent));
309
310 h->h_name = LU_COPY_STRING(in->h_name);
311
312 len = 0;
313 if (in->h_aliases != NULL)
314 {
315 for (len = 0; in->h_aliases[len] != NULL; len++);
316 }
317
318 h->h_aliases = (char **)calloc(len + 1, sizeof(char *));
319 for (i = 0; i < len; i++)
320 {
321 h->h_aliases[i] = strdup(in->h_aliases[i]);
322 }
323
324 h->h_addrtype = in->h_addrtype;
325 h->h_length = in->h_length;
326
327 len = 0;
328 if (in->h_addr_list != NULL)
329 {
330 for (len = 0; in->h_addr_list[len] != NULL; len++);
331 }
332
333 addr_len = sizeof(u_long *);
334 h->h_addr_list = (char **)calloc(len + 1, addr_len);
335 for (i = 0; i < len; i++)
336 {
337 h->h_addr_list[i] = (char *)malloc(h->h_length);
338 memmove(h->h_addr_list[i], in->h_addr_list[i], h->h_length);
339 }
340
341 return h;
342 }
343
344 static void
345 recycle_host(struct lu_thread_info *tdata, struct hostent *in)
346 {
347 struct hostent *h;
348
349 if (tdata == NULL) return;
350 h = (struct hostent *)tdata->lu_entry;
351
352 if (in == NULL)
353 {
354 freehostent(h);
355 tdata->lu_entry = NULL;
356 }
357
358 if (tdata->lu_entry == NULL)
359 {
360 tdata->lu_entry = in;
361 return;
362 }
363
364 free_host_data(h);
365
366 h->h_name = in->h_name;
367 h->h_aliases = in->h_aliases;
368 h->h_addrtype = in->h_addrtype;
369 h->h_length = in->h_length;
370 h->h_addr_list = in->h_addr_list;
371
372 free(in);
373 }
374
375 __private_extern__ struct hostent *
376 fake_hostent(const char *name, struct in_addr addr)
377 {
378 int addr_len;
379 struct hostent *h;
380
381 if (name == NULL) return NULL;
382
383 h = (struct hostent *)calloc(1, sizeof(struct hostent));
384
385 h->h_name = strdup(name);
386
387 h->h_aliases = (char **)calloc(1, sizeof(char *));
388
389 h->h_addrtype = AF_INET;
390 h->h_length = sizeof(long);
391
392 addr_len = sizeof(u_long *);
393 h->h_addr_list = (char **)calloc(2, addr_len);
394
395 h->h_addr_list[0] = (char *)malloc(h->h_length);
396 memmove(h->h_addr_list[0], &(addr.s_addr), h->h_length);
397
398 return h;
399 }
400
401 __private_extern__ struct hostent *
402 fake_hostent6(const char *name, struct in6_addr addr)
403 {
404 int addr_len;
405 struct hostent *h;
406
407 if (name == NULL) return NULL;
408
409 h = (struct hostent *)calloc(1, sizeof(struct hostent));
410
411 h->h_name = strdup(name);
412
413 h->h_aliases = (char **)calloc(1, sizeof(char *));
414
415 h->h_addrtype = AF_INET6;
416 h->h_length = 16;
417
418 addr_len = sizeof(u_long *);
419 h->h_addr_list = (char **)calloc(2, addr_len);
420
421 h->h_addr_list[0] = (char *)malloc(h->h_length);
422 memmove(h->h_addr_list[0], &(addr.__u6_addr.__u6_addr32[0]), h->h_length);
423
424 return h;
425 }
426
427 __private_extern__ unsigned int
428 get_host_cache_ttl()
429 {
430 return _host_cache_ttl;
431 }
432
433 __private_extern__ void
434 set_host_cache_ttl(unsigned int ttl)
435 {
436 int i;
437
438 pthread_mutex_lock(&_host_cache_lock);
439
440 _host_cache_ttl = ttl;
441
442 if (ttl == 0)
443 {
444 for (i = 0; i < HOST_CACHE_SIZE; i++)
445 {
446 if (_host_byname_cache[i] == NULL) continue;
447
448 freehostent((struct hostent *)_host_byname_cache[i]);
449 _host_byname_cache[i] = NULL;
450 _host_byname_cache_flavor[i] = WANT_NOTHING;
451 _host_byname_cache_best_before[i] = 0;
452 }
453
454 for (i = 0; i < HOST_CACHE_SIZE; i++)
455 {
456 if (_host_byaddr_cache[i] == NULL) continue;
457
458 freehostent((struct hostent *)_host_byaddr_cache[i]);
459 _host_byaddr_cache[i] = NULL;
460 _host_byaddr_cache_flavor[i] = WANT_NOTHING;
461 _host_byaddr_cache_best_before[i] = 0;
462 }
463 }
464
465 pthread_mutex_unlock(&_host_cache_lock);
466 }
467
468 static void
469 cache_host(struct hostent *h, int want, int how)
470 {
471 struct timeval now;
472 struct hostent *hcache;
473
474 if (_host_cache_ttl == 0) return;
475 if (h == NULL) return;
476
477 pthread_mutex_lock(&_host_cache_lock);
478
479 hcache = copy_host(h);
480
481 gettimeofday(&now, NULL);
482
483 if (how == CACHE_BYNAME)
484 {
485 if (_host_byname_cache[_host_byname_cache_index] != NULL)
486 freehostent((struct hostent *)_host_byname_cache[_host_byname_cache_index]);
487
488 _host_byname_cache[_host_byname_cache_index] = hcache;
489 _host_byname_cache_flavor[_host_byname_cache_index] = want;
490 _host_byname_cache_best_before[_host_byname_cache_index] = now.tv_sec + _host_cache_ttl;
491 _host_byname_cache_index = (_host_byname_cache_index + 1) % HOST_CACHE_SIZE;
492 }
493 else
494 {
495 if (_host_byaddr_cache[_host_byaddr_cache_index] != NULL)
496 freehostent((struct hostent *)_host_byaddr_cache[_host_byaddr_cache_index]);
497
498 _host_byaddr_cache[_host_byaddr_cache_index] = hcache;
499 _host_byaddr_cache_flavor[_host_byaddr_cache_index] = want;
500 _host_byaddr_cache_best_before[_host_byaddr_cache_index] = now.tv_sec + _host_cache_ttl;
501 _host_byaddr_cache_index = (_host_byaddr_cache_index + 1) % HOST_CACHE_SIZE;
502 }
503
504 pthread_mutex_unlock(&_host_cache_lock);
505 }
506
507 static struct hostent *
508 cache_gethostbyname(const char *name, int want)
509 {
510 int i;
511 struct hostent *h, *res;
512 char **aliases;
513 struct timeval now;
514
515 if (_host_cache_ttl == 0) return NULL;
516 if (name == NULL) return NULL;
517
518 pthread_mutex_lock(&_host_cache_lock);
519
520 gettimeofday(&now, NULL);
521
522 for (i = 0; i < HOST_CACHE_SIZE; i++)
523 {
524 if (_host_byname_cache_best_before[i] == 0) continue;
525 if ((unsigned int)now.tv_sec > _host_byname_cache_best_before[i]) continue;
526
527 if (_host_byname_cache_flavor[i] != want) continue;
528
529 h = (struct hostent *)_host_byname_cache[i];
530
531 if (h->h_name != NULL)
532 {
533 if (!strcmp(name, h->h_name))
534 {
535 res = copy_host(h);
536 pthread_mutex_unlock(&_host_cache_lock);
537 return res;
538 }
539 }
540
541 aliases = h->h_aliases;
542 if (aliases == NULL)
543 {
544 pthread_mutex_unlock(&_host_cache_lock);
545 return NULL;
546 }
547
548 for (; *aliases != NULL; *aliases++)
549 {
550 if (!strcmp(name, *aliases))
551 {
552 res = copy_host(h);
553 pthread_mutex_unlock(&_host_cache_lock);
554 return res;
555 }
556 }
557 }
558
559 pthread_mutex_unlock(&_host_cache_lock);
560 return NULL;
561 }
562
563 static struct hostent *
564 cache_gethostbyaddr(const char *addr, int want)
565 {
566 int i, j, len;
567 struct hostent *h, *res;
568 struct timeval now;
569
570 if (addr == NULL) return NULL;
571 if (_host_cache_ttl == 0) return NULL;
572
573 pthread_mutex_lock(&_host_cache_lock);
574
575 gettimeofday(&now, NULL);
576
577 len = IPV4_ADDR_LEN;
578 if (want > WANT_A4_ONLY) len = IPV6_ADDR_LEN;
579
580 for (i = 0; i < HOST_CACHE_SIZE; i++)
581 {
582 if (_host_byaddr_cache_best_before[i] == 0) continue;
583 if ((unsigned int)now.tv_sec > _host_byaddr_cache_best_before[i]) continue;
584
585 if (_host_byaddr_cache_flavor[i] != want) continue;
586
587 h = (struct hostent *)_host_byaddr_cache[i];
588
589 if (h->h_addr_list == NULL) continue;
590
591 for (j = 0; h->h_addr_list[j] != NULL; j++)
592 {
593 if (memcmp(addr, h->h_addr_list[j], len) == 0)
594 {
595 res = copy_host(h);
596 pthread_mutex_unlock(&_host_cache_lock);
597 return res;
598 }
599 }
600 }
601
602 pthread_mutex_unlock(&_host_cache_lock);
603 return NULL;
604 }
605
606 static struct hostent *
607 lu_gethostbyaddr(const char *addr, int want, int *err)
608 {
609 struct hostent *h;
610 unsigned int datalen;
611 XDR inxdr;
612 static int proc4 = -1;
613 static int proc6 = -1;
614 char *lookup_buf, *address;
615 int proc, count, len, family;
616 struct in_addr addr4;
617 struct in6_addr addr6;
618
619 family = AF_INET;
620 len = IPV4_ADDR_LEN;
621 if ((want == WANT_A6_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4))
622 {
623 family = AF_INET6;
624 len = IPV6_ADDR_LEN;
625 }
626
627 if ((family == AF_INET) && (proc4 < 0))
628 {
629 if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS)
630 {
631 *err = NO_RECOVERY;
632 return NULL;
633 }
634 }
635 else if ((family == AF_INET6) && (proc6 < 0))
636 {
637 if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS)
638 {
639 *err = NO_RECOVERY;
640 return NULL;
641 }
642 }
643
644 address = NULL;
645
646 if (family == AF_INET)
647 {
648 memmove(&(addr4.s_addr), addr, IPV4_ADDR_LEN);
649 addr4.s_addr = htonl(addr4.s_addr);
650 address = (char *)&(addr4.s_addr);
651 proc = proc4;
652 }
653 else
654 {
655 memmove(&(addr6.__u6_addr.__u6_addr32[0]), addr, IPV6_ADDR_LEN);
656 addr6.__u6_addr.__u6_addr32[0] = htonl(addr6.__u6_addr.__u6_addr32[0]);
657 addr6.__u6_addr.__u6_addr32[1] = htonl(addr6.__u6_addr.__u6_addr32[1]);
658 addr6.__u6_addr.__u6_addr32[2] = htonl(addr6.__u6_addr.__u6_addr32[2]);
659 addr6.__u6_addr.__u6_addr32[3] = htonl(addr6.__u6_addr.__u6_addr32[3]);
660 address = (char *)&(addr6.__u6_addr.__u6_addr32[0]);
661 proc = proc6;
662 }
663
664 datalen = 0;
665 lookup_buf = NULL;
666
667 if (_lookup_all(_lu_port, proc, (unit *)address, len / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
668 {
669 *err = NO_RECOVERY;
670 return NULL;
671 }
672
673 datalen *= BYTES_PER_XDR_UNIT;
674 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
675
676 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
677
678 count = 0;
679 if (!xdr_int(&inxdr, &count))
680 {
681 xdr_destroy(&inxdr);
682 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
683 *err = NO_RECOVERY;
684 return NULL;
685 }
686
687 if (count == 0)
688 {
689 xdr_destroy(&inxdr);
690 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
691 *err = HOST_NOT_FOUND;
692 return NULL;
693 }
694
695 *err = 0;
696
697 h = extract_host(&inxdr, want, err);
698 xdr_destroy(&inxdr);
699 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
700
701 return h;
702 }
703
704 static struct hostent *
705 lu_gethostbyname(const char *name, int want, int *err)
706 {
707 struct hostent *h;
708 unsigned int datalen;
709 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
710 XDR outxdr;
711 XDR inxdr;
712 static int proc4 = -1;
713 static int proc6 = -1;
714 char *lookup_buf;
715 int proc, count, family;
716
717 family = AF_INET;
718 if (want > WANT_A4_ONLY) family = AF_INET6;
719
720 if (((want == WANT_MAPPED_A4_ONLY) || (family == AF_INET)) && (proc4 < 0))
721 {
722 if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
723 {
724 *err = NO_RECOVERY;
725 return NULL;
726 }
727 }
728 else if ((family == AF_INET6) && (proc6 < 0))
729 {
730 if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
731 {
732 *err = NO_RECOVERY;
733 return NULL;
734 }
735 }
736
737 proc = proc4;
738 if ((family == AF_INET6) && (want != WANT_MAPPED_A4_ONLY)) proc = proc6;
739
740 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
741 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
742 {
743 xdr_destroy(&outxdr);
744 *err = NO_RECOVERY;
745 return NULL;
746 }
747
748 datalen = 0;
749 lookup_buf = NULL;
750
751 if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
752 {
753 xdr_destroy(&outxdr);
754 *err = NO_RECOVERY;
755 return NULL;
756 }
757
758 xdr_destroy(&outxdr);
759
760 datalen *= BYTES_PER_XDR_UNIT;
761 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
762
763 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
764
765 count = 0;
766 if (!xdr_int(&inxdr, &count))
767 {
768 xdr_destroy(&inxdr);
769 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
770 *err = NO_RECOVERY;
771 return NULL;
772 }
773
774 if (count == 0)
775 {
776 xdr_destroy(&inxdr);
777 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
778 *err = HOST_NOT_FOUND;
779 return NULL;
780 }
781
782 *err = 0;
783
784 h = extract_host(&inxdr, want, err);
785 xdr_destroy(&inxdr);
786 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
787
788 return h;
789 }
790
791 static void
792 lu_endhostent()
793 {
794 struct lu_thread_info *tdata;
795
796 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
797 _lu_data_free_vm_xdr(tdata);
798 }
799
800 static void
801 lu_sethostent()
802 {
803 lu_endhostent();
804 }
805
806 static struct hostent *
807 lu_gethostent(int want, int *err)
808 {
809 static int proc = -1;
810 struct lu_thread_info *tdata;
811 struct hostent *h;
812
813 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
814 if (tdata == NULL)
815 {
816 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
817 _lu_data_set_key(_lu_data_key_host, tdata);
818 }
819
820 if (tdata->lu_vm == NULL)
821 {
822 if (proc < 0)
823 {
824 if (_lookup_link(_lu_port, "gethostent", &proc) != KERN_SUCCESS)
825 {
826 lu_endhostent();
827 *err = NO_RECOVERY;
828 return NULL;
829 }
830 }
831
832 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
833 {
834 lu_endhostent();
835 *err = NO_RECOVERY;
836 return NULL;
837 }
838
839 /* mig stubs measure size in words (4 bytes) */
840 tdata->lu_vm_length *= 4;
841
842 if (tdata->lu_xdr != NULL)
843 {
844 xdr_destroy(tdata->lu_xdr);
845 free(tdata->lu_xdr);
846 }
847 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
848
849 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
850 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
851 {
852 lu_endhostent();
853 *err = NO_RECOVERY;
854 return NULL;
855 }
856 }
857
858 if (tdata->lu_vm_cursor == 0)
859 {
860 lu_endhostent();
861 *err = HOST_NOT_FOUND;
862 return NULL;
863 }
864
865 h = extract_host(tdata->lu_xdr, want, err);
866 if (h == NULL)
867 {
868 lu_endhostent();
869 *err = HOST_NOT_FOUND;
870 return NULL;
871 }
872
873 *err = 0;
874 tdata->lu_vm_cursor--;
875
876 return h;
877 }
878
879 static struct hostent *
880 gethostbyaddrerrno(const char *addr, int len, int type, int *err)
881 {
882 struct hostent *res = NULL;
883 int want, from_cache;
884
885 *err = 0;
886
887 want = WANT_A4_ONLY;
888 if (type == AF_INET6) want = WANT_A6_ONLY;
889
890 if ((type == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr)))
891 {
892 addr += 12;
893 len = 4;
894 type = AF_INET;
895 want = WANT_MAPPED_A4_ONLY;
896 }
897
898 from_cache = 0;
899 res = cache_gethostbyaddr(addr, want);
900
901 if (res != NULL)
902 {
903 from_cache = 1;
904 }
905 else if (_lu_running())
906 {
907 res = lu_gethostbyaddr(addr, want, err);
908 }
909 else
910 {
911 pthread_mutex_lock(&_host_lock);
912 res = copy_host(_res_gethostbyaddr(addr, len, type));
913 if (res == NULL) res = copy_host(_old_gethostbyaddr(addr, len, type));
914 *err = h_errno;
915 pthread_mutex_unlock(&_host_lock);
916 }
917
918 if (from_cache == 0) cache_host(res, want, CACHE_BYADDR);
919
920 return res;
921 }
922
923 struct hostent *
924 gethostbyaddr(const char *addr, int len, int type)
925 {
926 struct hostent *res;
927 struct lu_thread_info *tdata;
928
929 res = gethostbyaddrerrno(addr, len, type, &h_errno);
930 if (res == NULL)
931 {
932 return NULL;
933 }
934
935 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
936 if (tdata == NULL)
937 {
938 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
939 _lu_data_set_key(_lu_data_key_host, tdata);
940 }
941
942 recycle_host(tdata, res);
943 return (struct hostent *)tdata->lu_entry;
944 }
945
946 struct hostent *
947 gethostbynameerrno(const char *name, int *err)
948 {
949 struct hostent *res = NULL;
950 struct in_addr addr;
951 int i, is_addr, from_cache;
952
953 *err = 0;
954
955 /*
956 * If name is all dots and digits without a trailing dot,
957 * call inet_aton. If it's OK, return a fake entry.
958 * Otherwise, return an error.
959 *
960 * If name has alpha or ends with a dot, proceed as usual...
961 */
962 if (name == NULL)
963 {
964 *err = HOST_NOT_FOUND;
965 return NULL;
966 }
967
968 if (name[0] == '\0')
969 {
970 *err = HOST_NOT_FOUND;
971 return NULL;
972 }
973
974 is_addr = 1;
975 for (i = 0; name[i] != '\0'; i++)
976 {
977 if (name[i] == '.') continue;
978 if ((name[i] >= '0') && (name[i] <= '9')) continue;
979 is_addr = 0;
980 break;
981 }
982
983 if ((is_addr == 1) && (name[i-1] == '.')) is_addr = 0;
984
985 res = NULL;
986 from_cache = 0;
987
988 if (is_addr == 1)
989 {
990 if (inet_aton(name, &addr) == 0)
991 {
992 *err = HOST_NOT_FOUND;
993 return NULL;
994 }
995 res = fake_hostent(name, addr);
996 }
997
998 if (res == NULL)
999 {
1000 res = cache_gethostbyname(name, WANT_A4_ONLY);
1001 }
1002
1003 if (res != NULL)
1004 {
1005 from_cache = 1;
1006 }
1007 else if (_lu_running())
1008 {
1009 res = lu_gethostbyname(name, WANT_A4_ONLY, err);
1010 }
1011 else
1012 {
1013 pthread_mutex_lock(&_host_lock);
1014 res = copy_host(_res_gethostbyname(name));
1015 if (res == NULL) res = copy_host(_old_gethostbyname(name));
1016 *err = h_errno;
1017 pthread_mutex_unlock(&_host_lock);
1018 }
1019
1020 if (res == NULL)
1021 {
1022 if (inet_aton(name, &addr) == 0)
1023 {
1024 *err = HOST_NOT_FOUND;
1025 return NULL;
1026 }
1027
1028 res = gethostbyaddrerrno((char *)&addr, sizeof(addr), AF_INET, err);
1029 if (res == NULL)
1030 {
1031 res = fake_hostent(name, addr);
1032 }
1033 }
1034
1035 if (from_cache == 0) cache_host(res, WANT_A4_ONLY, CACHE_BYNAME);
1036
1037 return res;
1038 }
1039
1040 struct hostent *
1041 gethostbyname(const char *name)
1042 {
1043 struct hostent *res;
1044 struct lu_thread_info *tdata;
1045
1046 res = gethostbynameerrno(name, &h_errno);
1047 if (res == NULL)
1048 {
1049 return NULL;
1050 }
1051
1052 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
1053 if (tdata == NULL)
1054 {
1055 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
1056 _lu_data_set_key(_lu_data_key_host, tdata);
1057 }
1058
1059 recycle_host(tdata, res);
1060 return (struct hostent *)tdata->lu_entry;
1061 }
1062
1063 struct hostent *
1064 gethostbyname2(const char *name, int af)
1065 {
1066 struct hostent *res;
1067 struct lu_thread_info *tdata;
1068
1069 res = getipnodebyname(name, af, 0, &h_errno);
1070 if (res == NULL)
1071 {
1072 errno = EAFNOSUPPORT;
1073 h_errno = NETDB_INTERNAL;
1074 return NULL;
1075 }
1076
1077 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
1078 if (tdata == NULL)
1079 {
1080 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
1081 _lu_data_set_key(_lu_data_key_host, tdata);
1082 }
1083
1084 recycle_host(tdata, res);
1085 return (struct hostent *)tdata->lu_entry;
1086 }
1087
1088 struct hostent *
1089 gethostent(void)
1090 {
1091 struct hostent *res = NULL;
1092 struct lu_thread_info *tdata;
1093
1094 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
1095 if (tdata == NULL)
1096 {
1097 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
1098 _lu_data_set_key(_lu_data_key_host, tdata);
1099 }
1100
1101 if (_lu_running())
1102 {
1103 res = lu_gethostent(WANT_A4_ONLY, &h_errno);
1104 }
1105 else
1106 {
1107 pthread_mutex_lock(&_host_lock);
1108 res = copy_host(_old_gethostent());
1109 pthread_mutex_unlock(&_host_lock);
1110 }
1111
1112 recycle_host(tdata, res);
1113 return (struct hostent *)tdata->lu_entry;
1114 }
1115
1116 void
1117 sethostent(int stayopen)
1118 {
1119 if (_lu_running()) lu_sethostent();
1120 else _old_sethostent(stayopen);
1121 }
1122
1123 void
1124 endhostent(void)
1125 {
1126 if (_lu_running()) lu_endhostent();
1127 else _old_endhostent();
1128 }
1129
1130 __private_extern__ int
1131 is_a4_mapped(const char *s)
1132 {
1133 int i;
1134 u_int8_t c;
1135
1136 if (s == NULL) return 0;
1137
1138 for (i = 0; i < 10; i++)
1139 {
1140 c = s[i];
1141 if (c != 0x0) return 0;
1142 }
1143
1144 for (i = 10; i < 12; i++)
1145 {
1146 c = s[i];
1147 if (c != 0xff) return 0;
1148 }
1149
1150 return 1;
1151 }
1152
1153 __private_extern__ int
1154 is_a4_compat(const char *s)
1155 {
1156 int i;
1157 u_int8_t c;
1158
1159 if (s == NULL) return 0;
1160
1161 for (i = 0; i < 12; i++)
1162 {
1163 c = s[i];
1164 if (c != 0x0) return 0;
1165 }
1166
1167 /* Check for :: and ::1 */
1168 for (i = 13; i < 15; i++)
1169 {
1170 /* anything non-zero in these 3 bytes means it's a V4 address */
1171 c = s[i];
1172 if (c != 0x0) return 1;
1173 }
1174
1175 /* Leading 15 bytes are all zero */
1176 c = s[15];
1177 if (c == 0x0) return 0;
1178 if (c == 0x1) return 0;
1179
1180 return 1;
1181 }
1182
1183 struct hostent *
1184 getipnodebyaddr(const void *src, size_t len, int af, int *err)
1185 {
1186 struct hostent *res;
1187
1188 *err = 0;
1189
1190 res = gethostbyaddrerrno((const char *)src, len, af, err);
1191 if (res == NULL)
1192 {
1193 return NULL;
1194 }
1195
1196 if (res->h_name == NULL)
1197 {
1198 freehostent(res);
1199 return NULL;
1200 }
1201
1202 return res;
1203 }
1204
1205 struct hostent *
1206 getipnodebyname(const char *name, int af, int flags, int *err)
1207 {
1208 int status, want, really_want, if4, if6, from_cache;
1209 struct hostent *res;
1210 struct ifaddrs *ifa, *ifap;
1211 struct in_addr addr4;
1212 struct in6_addr addr6;
1213
1214 memset(&addr4, 0, sizeof(struct in_addr));
1215 memset(&addr6, 0, sizeof(struct in6_addr));
1216
1217 *err = 0;
1218
1219 if (af == AF_INET)
1220 {
1221 status = inet_aton(name, &addr4);
1222 if (status == 1)
1223 {
1224 /* return a fake hostent */
1225 res = fake_hostent(name, addr4);
1226 return res;
1227 }
1228 }
1229 else if (af == AF_INET6)
1230 {
1231 status = inet_pton(af, name, &addr6);
1232 if (status == 1)
1233 {
1234 /* return a fake hostent */
1235 res = fake_hostent6(name, addr6);
1236 return res;
1237 }
1238 status = inet_aton(name, &addr4);
1239 if (status == 1)
1240 {
1241 if (!(flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)))
1242 {
1243 *err = HOST_NOT_FOUND;
1244 return NULL;
1245 }
1246
1247 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1248 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1249 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1250 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
1251
1252 /* return a fake hostent */
1253 res = fake_hostent6(name, addr6);
1254 return res;
1255 }
1256 }
1257 else
1258 {
1259 *err = NO_RECOVERY;
1260 return NULL;
1261 }
1262
1263 /*
1264 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1265 */
1266
1267 if4 = 0;
1268 if6 = 0;
1269
1270 if (flags & AI_ADDRCONFIG)
1271 {
1272 if (getifaddrs(&ifa) < 0)
1273 {
1274 *err = NO_RECOVERY;
1275 return NULL;
1276 }
1277
1278 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
1279 {
1280 if (ifap->ifa_addr == NULL) continue;
1281 if ((ifap->ifa_flags & IFF_UP) == 0) continue;
1282 if (ifap->ifa_addr->sa_family == AF_INET) if4++;
1283 else if (ifap->ifa_addr->sa_family == AF_INET6) if6++;
1284 }
1285
1286 freeifaddrs(ifa);
1287
1288 /* Bail out if there are no interfaces */
1289 if ((if4 == 0) && (if6 == 0))
1290 {
1291 *err = NO_ADDRESS;
1292 return NULL;
1293 }
1294 }
1295
1296 /*
1297 * Figure out what we want.
1298 * If user asked for AF_INET, we only want V4 addresses.
1299 */
1300 want = WANT_A4_ONLY;
1301 really_want = want;
1302
1303 if (af == AF_INET)
1304 {
1305 want = WANT_A4_ONLY;
1306 if ((flags & AI_ADDRCONFIG) && (if4 == 0))
1307 {
1308 *err = NO_ADDRESS;
1309 return NULL;
1310 }
1311 }
1312 else
1313 {
1314 /* af == AF_INET6 */
1315 want = WANT_A6_ONLY;
1316 really_want = want;
1317 if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG))
1318 {
1319 if (flags & AI_ALL)
1320 {
1321 want = WANT_A6_PLUS_MAPPED_A4;
1322 really_want = want;
1323 }
1324 else
1325 {
1326 want = WANT_A6_ONLY;
1327 really_want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
1328 }
1329 }
1330 else
1331 {
1332 if ((flags & AI_ADDRCONFIG) && (if6 == 0))
1333 {
1334 *err = NO_ADDRESS;
1335 return NULL;
1336 }
1337 }
1338 }
1339
1340 from_cache = 0;
1341 res = cache_gethostbyname(name, want);
1342
1343 if (res != NULL)
1344 {
1345 from_cache = 1;
1346 }
1347 else if (_lu_running())
1348 {
1349 res = lu_gethostbyname(name, want, err);
1350 if ((res == NULL) &&
1351 ((really_want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) ||
1352 (really_want == WANT_A6_PLUS_MAPPED_A4 )))
1353 {
1354 res = lu_gethostbyname(name, WANT_MAPPED_A4_ONLY, err);
1355 }
1356 }
1357 else
1358 {
1359 pthread_mutex_lock(&_host_lock);
1360 res = copy_host(_res_gethostbyname(name));
1361 if (res == NULL) res = copy_host(_old_gethostbyname(name));
1362 *err = h_errno;
1363 pthread_mutex_unlock(&_host_lock);
1364 }
1365
1366 if (res == NULL)
1367 {
1368 *err = HOST_NOT_FOUND;
1369 return NULL;
1370 }
1371
1372 if (from_cache == 0) cache_host(res, want, CACHE_BYNAME);
1373
1374 return res;
1375 }