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