Libinfo-221.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
42 #include "_lu_types.h"
43 #include "lookup.h"
44 #include "lu_host.h"
45 #include "lu_utils.h"
46
47 #define HOST_CACHE_SIZE 10
48 #define DEFAULT_HOST_CACHE_TTL 10
49
50 #define CACHE_BYNAME 0
51 #define CACHE_BYADDR 1
52
53 static pthread_mutex_t _host_cache_lock = PTHREAD_MUTEX_INITIALIZER;
54 static unsigned int _host_cache_ttl = DEFAULT_HOST_CACHE_TTL;
55
56 static void *_host_byname_cache[HOST_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
57 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 };
58 static unsigned int _host_byname_cache_best_before[HOST_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
59 static unsigned int _host_byname_cache_index = 0;
60
61 static void *_host_byaddr_cache[HOST_CACHE_SIZE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
62 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 };
63 static unsigned int _host_byaddr_cache_best_before[HOST_CACHE_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
64 static unsigned int _host_byaddr_cache_index = 0;
65
66 static pthread_mutex_t _host_lock = PTHREAD_MUTEX_INITIALIZER;
67
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 int _old_ether_hostton(const char *, struct ether_addr *);
76 extern int _old_ether_ntohost(char *, const struct ether_addr *);
77
78 extern mach_port_t _lu_port;
79 extern int _lu_running(void);
80
81 extern int h_errno;
82
83 #define IPV6_ADDR_LEN 16
84 #define IPV4_ADDR_LEN 4
85
86 __private_extern__ void
87 free_host_data(struct hostent *h)
88 {
89 char **aliases;
90 int i;
91
92 if (h == NULL) return;
93
94 if (h->h_name != NULL) free(h->h_name);
95
96 aliases = h->h_aliases;
97 if (aliases != NULL)
98 {
99 while (*aliases != NULL) free(*aliases++);
100 free(h->h_aliases);
101 }
102
103 if (h->h_addr_list != NULL)
104 {
105 for (i = 0; h->h_addr_list[i] != NULL; i++) free(h->h_addr_list[i]);
106 free(h->h_addr_list);
107 }
108 }
109
110 void
111 freehostent(struct hostent *h)
112 {
113 if (h == NULL) return;
114 free_host_data(h);
115 free(h);
116 }
117
118 static void
119 free_lu_thread_info_host(void *x)
120 {
121 struct lu_thread_info *tdata;
122
123 if (x == NULL) return;
124
125 tdata = (struct lu_thread_info *)x;
126
127 if (tdata->lu_entry != NULL)
128 {
129 freehostent((struct hostent *)tdata->lu_entry);
130 tdata->lu_entry = NULL;
131 }
132
133 _lu_data_free_vm_xdr(tdata);
134
135 free(tdata);
136 }
137
138 __private_extern__ struct hostent *
139 extract_host(XDR *xdr, int want, int *err)
140 {
141 struct hostent *h;
142 int i, j, nvals, nkeys, status, addr_len;
143 int family, addr_count, map_count;
144 struct in_addr addr;
145 struct in6_addr addr6;
146 char *key, **vals, **mapvals;
147
148 mapvals = NULL;
149 map_count = 0;
150 addr_count = 0;
151 addr_len = sizeof(u_long *);
152
153 if (xdr == NULL)
154 {
155 *err = NO_RECOVERY;
156 return NULL;
157 }
158
159 if (!xdr_int(xdr, &nkeys))
160 {
161 *err = NO_RECOVERY;
162 return NULL;
163 }
164
165 h = (struct hostent *)calloc(1, sizeof(struct hostent));
166
167 family = AF_INET;
168 h->h_length = IPV4_ADDR_LEN;
169
170 if (want > WANT_A4_ONLY)
171 {
172 family = AF_INET6;
173 h->h_length = IPV6_ADDR_LEN;
174 }
175
176 h->h_addrtype = family;
177
178 for (i = 0; i < nkeys; i++)
179 {
180 key = NULL;
181 vals = NULL;
182 nvals = 0;
183
184 status = _lu_xdr_attribute(xdr, &key, &vals, &nvals);
185 if (status < 0)
186 {
187 freehostent(h);
188 *err = NO_RECOVERY;
189 return NULL;
190 }
191
192 if (nvals == 0)
193 {
194 free(key);
195 continue;
196 }
197
198 j = 0;
199
200 if ((h->h_name == NULL) && (!strcmp("name", key)))
201 {
202 h->h_name = vals[0];
203 if (nvals > 1)
204 {
205 h->h_aliases = (char **)calloc(nvals, sizeof(char *));
206 for (j = 1; j < nvals; j++) h->h_aliases[j-1] = vals[j];
207 }
208 j = nvals;
209 }
210 else if ((family == AF_INET) && (h->h_addr_list == NULL) && (!strcmp("ip_address", key)))
211 {
212 addr_count = nvals;
213 h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
214
215 for (j = 0; j < nvals; j++)
216 {
217 addr.s_addr = 0;
218 inet_aton(vals[j], &addr);
219 h->h_addr_list[j] = (char *)calloc(1, IPV4_ADDR_LEN);
220 memmove(h->h_addr_list[j], &(addr.s_addr), IPV4_ADDR_LEN);
221 }
222
223 h->h_addr_list[nvals] = NULL;
224 j = 0;
225 }
226 else if ((family == AF_INET6) && (h->h_addr_list == NULL) && (!strcmp("ipv6_address", key)))
227 {
228 addr_count = nvals;
229 h->h_addr_list = (char **)calloc(nvals + 1, addr_len);
230
231 for (j = 0; j < nvals; j++)
232 {
233 memset(&addr6, 0, sizeof(struct in6_addr));
234 inet_pton(family, vals[j], &addr6);
235 h->h_addr_list[j] = (char *)calloc(1, IPV6_ADDR_LEN);
236 memmove(h->h_addr_list[j], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
237 }
238
239 h->h_addr_list[nvals] = NULL;
240 j = 0;
241 }
242 else if ((family == AF_INET6) && (mapvals == NULL) && (!strcmp("ip_address", key)))
243 {
244 map_count = nvals;
245 mapvals = vals;
246 vals = NULL;
247 }
248
249 free(key);
250 if (vals != NULL)
251 {
252 for (; j < nvals; j++) free(vals[j]);
253 free(vals);
254 }
255 }
256
257 if ((mapvals != NULL) && (want > WANT_A6_ONLY))
258 {
259 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
260 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
261 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
262
263 if (addr_count == 0)
264 {
265 h->h_addr_list = (char **)calloc(map_count + 1, addr_len);
266 }
267 else
268 {
269 h->h_addr_list = (char **)realloc(h->h_addr_list, (addr_count + map_count + 1) * addr_len);
270 }
271
272 for (i = 0; i < map_count; i++)
273 {
274 addr.s_addr = 0;
275 inet_aton(mapvals[i], &addr);
276 h->h_addr_list[addr_count] = (char *)calloc(1, IPV6_ADDR_LEN);
277 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr.s_addr), IPV4_ADDR_LEN);
278 memcpy(h->h_addr_list[addr_count++], &(addr6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN);
279 }
280
281 h->h_addr_list[addr_count] = NULL;
282 }
283
284 if (mapvals != NULL)
285 {
286 for (i = 0; i < map_count; i++) free(mapvals[i]);
287 free(mapvals);
288 }
289
290 if (h->h_addr_list == NULL)
291 {
292 freehostent(h);
293 *err = NO_DATA;
294 return NULL;
295 }
296
297 if (h->h_name == NULL) h->h_name = strdup("");
298 if (h->h_aliases == NULL) h->h_aliases = (char **)calloc(1, sizeof(char *));
299
300 return h;
301 }
302
303 static struct hostent *
304 copy_host(struct hostent *in)
305 {
306 int i, len, addr_len;
307 struct hostent *h;
308
309 if (in == NULL) return NULL;
310
311 h = (struct hostent *)calloc(1, sizeof(struct hostent));
312
313 h->h_name = LU_COPY_STRING(in->h_name);
314
315 len = 0;
316 if (in->h_aliases != NULL)
317 {
318 for (len = 0; in->h_aliases[len] != NULL; len++);
319 }
320
321 h->h_aliases = (char **)calloc(len + 1, sizeof(char *));
322 for (i = 0; i < len; i++)
323 {
324 h->h_aliases[i] = strdup(in->h_aliases[i]);
325 }
326
327 h->h_addrtype = in->h_addrtype;
328 h->h_length = in->h_length;
329
330 len = 0;
331 if (in->h_addr_list != NULL)
332 {
333 for (len = 0; in->h_addr_list[len] != NULL; len++);
334 }
335
336 addr_len = sizeof(u_long *);
337 h->h_addr_list = (char **)calloc(len + 1, addr_len);
338 for (i = 0; i < len; i++)
339 {
340 h->h_addr_list[i] = (char *)malloc(h->h_length);
341 memmove(h->h_addr_list[i], in->h_addr_list[i], h->h_length);
342 }
343
344 return h;
345 }
346
347 static void
348 recycle_host(struct lu_thread_info *tdata, struct hostent *in)
349 {
350 struct hostent *h;
351
352 if (tdata == NULL) return;
353 h = (struct hostent *)tdata->lu_entry;
354
355 if (in == NULL)
356 {
357 freehostent(h);
358 tdata->lu_entry = NULL;
359 }
360
361 if (tdata->lu_entry == NULL)
362 {
363 tdata->lu_entry = in;
364 return;
365 }
366
367 free_host_data(h);
368
369 h->h_name = in->h_name;
370 h->h_aliases = in->h_aliases;
371 h->h_addrtype = in->h_addrtype;
372 h->h_length = in->h_length;
373 h->h_addr_list = in->h_addr_list;
374
375 free(in);
376 }
377
378 __private_extern__ struct hostent *
379 fake_hostent(const char *name, struct in_addr addr)
380 {
381 int addr_len;
382 struct hostent *h;
383
384 if (name == NULL) return NULL;
385
386 h = (struct hostent *)calloc(1, sizeof(struct hostent));
387
388 h->h_name = strdup(name);
389
390 h->h_aliases = (char **)calloc(1, sizeof(char *));
391
392 h->h_addrtype = AF_INET;
393 h->h_length = sizeof(long);
394
395 addr_len = sizeof(u_long *);
396 h->h_addr_list = (char **)calloc(2, addr_len);
397
398 h->h_addr_list[0] = (char *)malloc(h->h_length);
399 memmove(h->h_addr_list[0], &(addr.s_addr), h->h_length);
400
401 return h;
402 }
403
404 __private_extern__ struct hostent *
405 fake_hostent6(const char *name, struct in6_addr addr)
406 {
407 int addr_len;
408 struct hostent *h;
409
410 if (name == NULL) return NULL;
411
412 h = (struct hostent *)calloc(1, sizeof(struct hostent));
413
414 h->h_name = strdup(name);
415
416 h->h_aliases = (char **)calloc(1, sizeof(char *));
417
418 h->h_addrtype = AF_INET6;
419 h->h_length = 16;
420
421 addr_len = sizeof(u_long *);
422 h->h_addr_list = (char **)calloc(2, addr_len);
423
424 h->h_addr_list[0] = (char *)malloc(h->h_length);
425 memmove(h->h_addr_list[0], &(addr.__u6_addr.__u6_addr32[0]), h->h_length);
426
427 return h;
428 }
429
430 __private_extern__ unsigned int
431 get_host_cache_ttl()
432 {
433 return _host_cache_ttl;
434 }
435
436 __private_extern__ void
437 set_host_cache_ttl(unsigned int ttl)
438 {
439 int i;
440
441 pthread_mutex_lock(&_host_cache_lock);
442
443 _host_cache_ttl = ttl;
444
445 if (ttl == 0)
446 {
447 for (i = 0; i < HOST_CACHE_SIZE; i++)
448 {
449 if (_host_byname_cache[i] == NULL) continue;
450
451 freehostent((struct hostent *)_host_byname_cache[i]);
452 _host_byname_cache[i] = NULL;
453 _host_byname_cache_flavor[i] = WANT_NOTHING;
454 _host_byname_cache_best_before[i] = 0;
455 }
456
457 for (i = 0; i < HOST_CACHE_SIZE; i++)
458 {
459 if (_host_byaddr_cache[i] == NULL) continue;
460
461 freehostent((struct hostent *)_host_byaddr_cache[i]);
462 _host_byaddr_cache[i] = NULL;
463 _host_byaddr_cache_flavor[i] = WANT_NOTHING;
464 _host_byaddr_cache_best_before[i] = 0;
465 }
466 }
467
468 pthread_mutex_unlock(&_host_cache_lock);
469 }
470
471 static void
472 cache_host(struct hostent *h, int want, int how)
473 {
474 struct timeval now;
475 struct hostent *hcache;
476
477 if (_host_cache_ttl == 0) return;
478 if (h == NULL) return;
479
480 pthread_mutex_lock(&_host_cache_lock);
481
482 hcache = copy_host(h);
483
484 gettimeofday(&now, NULL);
485
486 if (how == CACHE_BYNAME)
487 {
488 if (_host_byname_cache[_host_byname_cache_index] != NULL)
489 freehostent((struct hostent *)_host_byname_cache[_host_byname_cache_index]);
490
491 _host_byname_cache[_host_byname_cache_index] = hcache;
492 _host_byname_cache_flavor[_host_byname_cache_index] = want;
493 _host_byname_cache_best_before[_host_byname_cache_index] = now.tv_sec + _host_cache_ttl;
494 _host_byname_cache_index = (_host_byname_cache_index + 1) % HOST_CACHE_SIZE;
495 }
496 else
497 {
498 if (_host_byaddr_cache[_host_byaddr_cache_index] != NULL)
499 freehostent((struct hostent *)_host_byaddr_cache[_host_byaddr_cache_index]);
500
501 _host_byaddr_cache[_host_byaddr_cache_index] = hcache;
502 _host_byaddr_cache_flavor[_host_byaddr_cache_index] = want;
503 _host_byaddr_cache_best_before[_host_byaddr_cache_index] = now.tv_sec + _host_cache_ttl;
504 _host_byaddr_cache_index = (_host_byaddr_cache_index + 1) % HOST_CACHE_SIZE;
505 }
506
507 pthread_mutex_unlock(&_host_cache_lock);
508 }
509
510 static struct hostent *
511 cache_gethostbyname(const char *name, int want)
512 {
513 int i;
514 struct hostent *h, *res;
515 char **aliases;
516 struct timeval now;
517
518 if (_host_cache_ttl == 0) return NULL;
519 if (name == NULL) return NULL;
520
521 pthread_mutex_lock(&_host_cache_lock);
522
523 gettimeofday(&now, NULL);
524
525 for (i = 0; i < HOST_CACHE_SIZE; i++)
526 {
527 if (_host_byname_cache_best_before[i] == 0) continue;
528 if ((unsigned int)now.tv_sec > _host_byname_cache_best_before[i]) continue;
529
530 if (_host_byname_cache_flavor[i] != want) continue;
531
532 h = (struct hostent *)_host_byname_cache[i];
533
534 if (h->h_name != NULL)
535 {
536 if (!strcmp(name, h->h_name))
537 {
538 res = copy_host(h);
539 pthread_mutex_unlock(&_host_cache_lock);
540 return res;
541 }
542 }
543
544 aliases = h->h_aliases;
545 if (aliases == NULL)
546 {
547 pthread_mutex_unlock(&_host_cache_lock);
548 return NULL;
549 }
550
551 for (; *aliases != NULL; *aliases++)
552 {
553 if (!strcmp(name, *aliases))
554 {
555 res = copy_host(h);
556 pthread_mutex_unlock(&_host_cache_lock);
557 return res;
558 }
559 }
560 }
561
562 pthread_mutex_unlock(&_host_cache_lock);
563 return NULL;
564 }
565
566 static struct hostent *
567 cache_gethostbyaddr(const char *addr, int want)
568 {
569 int i, j, len;
570 struct hostent *h, *res;
571 struct timeval now;
572
573 if (addr == NULL) return NULL;
574 if (_host_cache_ttl == 0) return NULL;
575
576 pthread_mutex_lock(&_host_cache_lock);
577
578 gettimeofday(&now, NULL);
579
580 len = IPV4_ADDR_LEN;
581 if (want > WANT_A4_ONLY) len = IPV6_ADDR_LEN;
582
583 for (i = 0; i < HOST_CACHE_SIZE; i++)
584 {
585 if (_host_byaddr_cache_best_before[i] == 0) continue;
586 if ((unsigned int)now.tv_sec > _host_byaddr_cache_best_before[i]) continue;
587
588 if (_host_byaddr_cache_flavor[i] != want) continue;
589
590 h = (struct hostent *)_host_byaddr_cache[i];
591
592 if (h->h_addr_list == NULL) continue;
593
594 for (j = 0; h->h_addr_list[j] != NULL; j++)
595 {
596 if (memcmp(addr, h->h_addr_list[j], len) == 0)
597 {
598 res = copy_host(h);
599 pthread_mutex_unlock(&_host_cache_lock);
600 return res;
601 }
602 }
603 }
604
605 pthread_mutex_unlock(&_host_cache_lock);
606 return NULL;
607 }
608
609 static struct hostent *
610 lu_gethostbyaddr(const char *addr, int want, int *err)
611 {
612 struct hostent *h;
613 unsigned int datalen;
614 XDR inxdr;
615 static int proc4 = -1;
616 static int proc6 = -1;
617 char *lookup_buf, *address;
618 int proc, count, len, family;
619 struct in_addr addr4;
620 struct in6_addr addr6;
621
622 family = AF_INET;
623 len = IPV4_ADDR_LEN;
624 if ((want == WANT_A6_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4))
625 {
626 family = AF_INET6;
627 len = IPV6_ADDR_LEN;
628 }
629
630 if ((family == AF_INET) && (proc4 < 0))
631 {
632 if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS)
633 {
634 *err = NO_RECOVERY;
635 return NULL;
636 }
637 }
638 else if ((family == AF_INET6) && (proc6 < 0))
639 {
640 if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS)
641 {
642 *err = NO_RECOVERY;
643 return NULL;
644 }
645 }
646
647 address = NULL;
648
649 if (family == AF_INET)
650 {
651 memmove(&(addr4.s_addr), addr, IPV4_ADDR_LEN);
652 addr4.s_addr = htonl(addr4.s_addr);
653 address = (char *)&(addr4.s_addr);
654 proc = proc4;
655 }
656 else
657 {
658 memmove(&(addr6.__u6_addr.__u6_addr32[0]), addr, IPV6_ADDR_LEN);
659 addr6.__u6_addr.__u6_addr32[0] = htonl(addr6.__u6_addr.__u6_addr32[0]);
660 addr6.__u6_addr.__u6_addr32[1] = htonl(addr6.__u6_addr.__u6_addr32[1]);
661 addr6.__u6_addr.__u6_addr32[2] = htonl(addr6.__u6_addr.__u6_addr32[2]);
662 addr6.__u6_addr.__u6_addr32[3] = htonl(addr6.__u6_addr.__u6_addr32[3]);
663 address = (char *)&(addr6.__u6_addr.__u6_addr32[0]);
664 proc = proc6;
665 }
666
667 datalen = 0;
668 lookup_buf = NULL;
669
670 if (_lookup_all(_lu_port, proc, (unit *)address, len / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
671 {
672 *err = HOST_NOT_FOUND;
673 return NULL;
674 }
675
676 datalen *= BYTES_PER_XDR_UNIT;
677 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
678
679 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
680
681 count = 0;
682 if (!xdr_int(&inxdr, &count))
683 {
684 xdr_destroy(&inxdr);
685 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
686 *err = NO_RECOVERY;
687 return NULL;
688 }
689
690 if (count == 0)
691 {
692 xdr_destroy(&inxdr);
693 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
694 *err = HOST_NOT_FOUND;
695 return NULL;
696 }
697
698 *err = 0;
699
700 h = extract_host(&inxdr, want, err);
701 xdr_destroy(&inxdr);
702 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
703
704 return h;
705 }
706
707 static struct hostent *
708 lu_gethostbyname(const char *name, int want, int *err)
709 {
710 struct hostent *h;
711 unsigned int datalen;
712 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
713 XDR outxdr;
714 XDR inxdr;
715 static int proc4 = -1;
716 static int proc6 = -1;
717 char *lookup_buf;
718 int proc, count, family;
719
720 family = AF_INET;
721 if (want > WANT_A4_ONLY) family = AF_INET6;
722
723 if (((want == WANT_MAPPED_A4_ONLY) || (family == AF_INET)) && (proc4 < 0))
724 {
725 if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
726 {
727 *err = NO_RECOVERY;
728 return NULL;
729 }
730 }
731 else if ((family == AF_INET6) && (proc6 < 0))
732 {
733 if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
734 {
735 *err = NO_RECOVERY;
736 return NULL;
737 }
738 }
739
740 proc = proc4;
741 if ((family == AF_INET6) && (want != WANT_MAPPED_A4_ONLY)) proc = proc6;
742
743 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
744 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
745 {
746 xdr_destroy(&outxdr);
747 *err = NO_RECOVERY;
748 return NULL;
749 }
750
751 datalen = 0;
752 lookup_buf = NULL;
753
754 if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
755 {
756 xdr_destroy(&outxdr);
757 *err = HOST_NOT_FOUND;
758 return NULL;
759 }
760
761 xdr_destroy(&outxdr);
762
763 datalen *= BYTES_PER_XDR_UNIT;
764 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
765
766 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
767
768 count = 0;
769 if (!xdr_int(&inxdr, &count))
770 {
771 xdr_destroy(&inxdr);
772 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
773 *err = NO_RECOVERY;
774 return NULL;
775 }
776
777 if (count == 0)
778 {
779 xdr_destroy(&inxdr);
780 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
781 *err = HOST_NOT_FOUND;
782 return NULL;
783 }
784
785 *err = 0;
786
787 h = extract_host(&inxdr, want, err);
788 xdr_destroy(&inxdr);
789 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
790
791 return h;
792 }
793
794 static void
795 lu_endhostent()
796 {
797 struct lu_thread_info *tdata;
798
799 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
800 _lu_data_free_vm_xdr(tdata);
801 }
802
803 static void
804 lu_sethostent()
805 {
806 lu_endhostent();
807 }
808
809 static struct hostent *
810 lu_gethostent(int want, int *err)
811 {
812 static int proc = -1;
813 struct lu_thread_info *tdata;
814 struct hostent *h;
815
816 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
817 if (tdata == NULL)
818 {
819 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
820 _lu_data_set_key(_lu_data_key_host, tdata);
821 }
822
823 if (tdata->lu_vm == NULL)
824 {
825 if (proc < 0)
826 {
827 if (_lookup_link(_lu_port, "gethostent", &proc) != KERN_SUCCESS)
828 {
829 lu_endhostent();
830 *err = NO_RECOVERY;
831 return NULL;
832 }
833 }
834
835 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
836 {
837 lu_endhostent();
838 *err = HOST_NOT_FOUND;
839 return NULL;
840 }
841
842 /* mig stubs measure size in words (4 bytes) */
843 tdata->lu_vm_length *= 4;
844
845 if (tdata->lu_xdr != NULL)
846 {
847 xdr_destroy(tdata->lu_xdr);
848 free(tdata->lu_xdr);
849 }
850 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
851
852 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
853 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
854 {
855 lu_endhostent();
856 *err = NO_RECOVERY;
857 return NULL;
858 }
859 }
860
861 if (tdata->lu_vm_cursor == 0)
862 {
863 lu_endhostent();
864 *err = HOST_NOT_FOUND;
865 return NULL;
866 }
867
868 h = extract_host(tdata->lu_xdr, want, err);
869 if (h == NULL)
870 {
871 lu_endhostent();
872 *err = HOST_NOT_FOUND;
873 return NULL;
874 }
875
876 *err = 0;
877 tdata->lu_vm_cursor--;
878
879 return h;
880 }
881
882 static struct hostent *
883 gethostbyaddrerrno(const char *addr, int len, int type, int *err)
884 {
885 struct hostent *res = NULL;
886 int want, from_cache;
887
888 *err = 0;
889
890 want = WANT_A4_ONLY;
891 if (type == AF_INET6) want = WANT_A6_ONLY;
892
893 if ((type == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr)))
894 {
895 addr += 12;
896 len = 4;
897 type = AF_INET;
898 want = WANT_MAPPED_A4_ONLY;
899 }
900
901 from_cache = 0;
902 res = cache_gethostbyaddr(addr, want);
903
904 if (res != NULL)
905 {
906 from_cache = 1;
907 }
908 else if (_lu_running())
909 {
910 res = lu_gethostbyaddr(addr, want, err);
911 }
912 else
913 {
914 pthread_mutex_lock(&_host_lock);
915 res = copy_host(_old_gethostbyaddr(addr, len, type));
916 *err = h_errno;
917 pthread_mutex_unlock(&_host_lock);
918 }
919
920 if (from_cache == 0) cache_host(res, want, CACHE_BYADDR);
921
922 return res;
923 }
924
925 struct hostent *
926 gethostbyaddr(const void *addr, socklen_t len, int type)
927 {
928 struct hostent *res;
929 struct lu_thread_info *tdata;
930
931 res = gethostbyaddrerrno(addr, len, type, &h_errno);
932 if (res == NULL)
933 {
934 return NULL;
935 }
936
937 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
938 if (tdata == NULL)
939 {
940 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
941 _lu_data_set_key(_lu_data_key_host, tdata);
942 }
943
944 recycle_host(tdata, res);
945 return (struct hostent *)tdata->lu_entry;
946 }
947
948 struct hostent *
949 gethostbynameerrno(const char *name, int *err)
950 {
951 struct hostent *res = NULL;
952 struct in_addr addr;
953 int i, is_addr, from_cache;
954
955 *err = 0;
956
957 /*
958 * If name is all dots and digits without a trailing dot,
959 * call inet_aton. If it's OK, return a fake entry.
960 * Otherwise, return an error.
961 *
962 * If name has alpha or ends with a dot, proceed as usual...
963 */
964 if (name == NULL)
965 {
966 *err = HOST_NOT_FOUND;
967 return NULL;
968 }
969
970 if (name[0] == '\0')
971 {
972 *err = HOST_NOT_FOUND;
973 return NULL;
974 }
975
976 is_addr = 1;
977 for (i = 0; name[i] != '\0'; i++)
978 {
979 if (name[i] == '.') continue;
980 if ((name[i] >= '0') && (name[i] <= '9')) continue;
981 is_addr = 0;
982 break;
983 }
984
985 if ((is_addr == 1) && (name[i-1] == '.')) is_addr = 0;
986
987 res = NULL;
988 from_cache = 0;
989
990 if (is_addr == 1)
991 {
992 if (inet_aton(name, &addr) == 0)
993 {
994 *err = HOST_NOT_FOUND;
995 return NULL;
996 }
997 res = fake_hostent(name, addr);
998 }
999
1000 if (res == NULL)
1001 {
1002 res = cache_gethostbyname(name, WANT_A4_ONLY);
1003 }
1004
1005 if (res != NULL)
1006 {
1007 from_cache = 1;
1008 }
1009 else if (_lu_running())
1010 {
1011 res = lu_gethostbyname(name, WANT_A4_ONLY, err);
1012 }
1013 else
1014 {
1015 pthread_mutex_lock(&_host_lock);
1016 res = copy_host(_old_gethostbyname(name));
1017 *err = h_errno;
1018 pthread_mutex_unlock(&_host_lock);
1019 }
1020
1021 if (res == NULL)
1022 {
1023 if (inet_aton(name, &addr) == 0)
1024 {
1025 *err = HOST_NOT_FOUND;
1026 return NULL;
1027 }
1028
1029 res = gethostbyaddrerrno((char *)&addr, sizeof(addr), AF_INET, err);
1030 if (res == NULL)
1031 {
1032 res = fake_hostent(name, addr);
1033 }
1034 }
1035
1036 if (from_cache == 0) cache_host(res, WANT_A4_ONLY, CACHE_BYNAME);
1037
1038 return res;
1039 }
1040
1041 struct hostent *
1042 gethostbyname(const char *name)
1043 {
1044 struct hostent *res;
1045 struct lu_thread_info *tdata;
1046
1047 res = gethostbynameerrno(name, &h_errno);
1048 if (res == NULL)
1049 {
1050 return NULL;
1051 }
1052
1053 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
1054 if (tdata == NULL)
1055 {
1056 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
1057 _lu_data_set_key(_lu_data_key_host, tdata);
1058 }
1059
1060 recycle_host(tdata, res);
1061 return (struct hostent *)tdata->lu_entry;
1062 }
1063
1064 struct hostent *
1065 gethostbyname2(const char *name, int af)
1066 {
1067 struct hostent *res;
1068 struct lu_thread_info *tdata;
1069
1070 res = getipnodebyname(name, af, 0, &h_errno);
1071 if (res == NULL)
1072 {
1073 errno = EAFNOSUPPORT;
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(_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 }
1375
1376 /*
1377 * Given a host's name, this routine returns its 48 bit ethernet address.
1378 * Returns zero if successful, non-zero otherwise.
1379 */
1380 int
1381 lu_ether_hostton(const char *host, struct ether_addr *e)
1382 {
1383 unsigned int i, n, j, x[6];
1384 ni_proplist *q, **r;
1385 char *s;
1386
1387 if (host == NULL) return -1;
1388 if (e == NULL) return -1;
1389
1390 q = lookupd_make_query("2", "kvk", "name", host, "en_address");
1391 if (q == NULL) return -1;
1392
1393 n = lookupd_query(q, &r);
1394 ni_proplist_free(q);
1395 free(q);
1396
1397 if (n == 0) return -1;
1398 if (r[0] == NULL) return -1;
1399
1400 i = ni_proplist_match(*r[0], "en_address", NULL);
1401 if (i == (unsigned int)NI_INDEX_NULL) return -1;
1402
1403 if (r[0]->ni_proplist_val[i].nip_val.ni_namelist_len == 0) return -1;
1404
1405 s = r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0];
1406 j = sscanf(s, " %x:%x:%x:%x:%x:%x", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);
1407 if (j != 6)
1408 {
1409 for (i = 0; i < n; i++)
1410 {
1411 ni_proplist_free(r[i]);
1412 free(r[i]);
1413 }
1414 free(r);
1415 return -1;
1416 }
1417
1418 for (i = 0; i < 6; i++) e->ether_addr_octet[i] = x[i];
1419
1420 for (i = 0; i < n; i++)
1421 {
1422 ni_proplist_free(r[i]);
1423 free(r[i]);
1424 }
1425
1426 free(r);
1427 return 0;
1428 }
1429
1430 /*
1431 * Given a 48 bit ethernet address, this routine return its host name.
1432 * Returns zero if successful, non-zero otherwise.
1433 */
1434 int
1435 lu_ether_ntohost(char *host, const struct ether_addr *e)
1436 {
1437 unsigned int i, n, len, x[6];
1438 ni_proplist *q, **r;
1439 char str[256];
1440
1441 if (host == NULL) return -1;
1442 if (e == NULL) return -1;
1443
1444 for (i = 0; i < 6; i++) x[i] = e->ether_addr_octet[i];
1445 sprintf(str, "%x:%x:%x:%x:%x:%x", x[0], x[1], x[2], x[3], x[4], x[5]);
1446
1447 q = lookupd_make_query("2", "kv", "en_address", str);
1448 if (q == NULL) return -1;
1449
1450 n = lookupd_query(q, &r);
1451 ni_proplist_free(q);
1452 free(q);
1453 if (n == 0) return -1;
1454 if (r[0] == NULL) return -1;
1455
1456 i = ni_proplist_match(*r[0], "name", NULL);
1457 if (i == (unsigned int)NI_INDEX_NULL) return -1;
1458
1459 if (r[0]->ni_proplist_val[i].nip_val.ni_namelist_len == 0) return -1;
1460
1461 len = strlen(r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0]) + 1;
1462 memcpy(host, r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0], len);
1463
1464 for (i = 0; i < n; i++) ni_proplist_free(r[i]);
1465 free(r);
1466 return 0;
1467 }
1468
1469 int
1470 ether_hostton(const char *host, struct ether_addr *e)
1471 {
1472 if (_lu_running()) return lu_ether_hostton(host, e);
1473 return _old_ether_hostton(host, e);
1474 }
1475
1476 int
1477 ether_ntohost(char *host, const struct ether_addr *e)
1478 {
1479 if (_lu_running()) return lu_ether_ntohost(host, e);
1480 return _old_ether_ntohost(host, e);
1481 }