Libinfo-222.4.6.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 address = (char *)&(addr4.s_addr);
653 proc = proc4;
654 }
655 else
656 {
657 memmove(&(addr6.__u6_addr.__u6_addr32[0]), addr, IPV6_ADDR_LEN);
658 addr6.__u6_addr.__u6_addr32[0] = htonl(addr6.__u6_addr.__u6_addr32[0]);
659 addr6.__u6_addr.__u6_addr32[1] = htonl(addr6.__u6_addr.__u6_addr32[1]);
660 addr6.__u6_addr.__u6_addr32[2] = htonl(addr6.__u6_addr.__u6_addr32[2]);
661 addr6.__u6_addr.__u6_addr32[3] = htonl(addr6.__u6_addr.__u6_addr32[3]);
662 address = (char *)&(addr6.__u6_addr.__u6_addr32[0]);
663 proc = proc6;
664 }
665
666 datalen = 0;
667 lookup_buf = NULL;
668
669 if (_lookup_all(_lu_port, proc, (unit *)address, len / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
670 {
671 *err = HOST_NOT_FOUND;
672 return NULL;
673 }
674
675 datalen *= BYTES_PER_XDR_UNIT;
676 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
677
678 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
679
680 count = 0;
681 if (!xdr_int(&inxdr, &count))
682 {
683 xdr_destroy(&inxdr);
684 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
685 *err = NO_RECOVERY;
686 return NULL;
687 }
688
689 if (count == 0)
690 {
691 xdr_destroy(&inxdr);
692 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
693 *err = HOST_NOT_FOUND;
694 return NULL;
695 }
696
697 *err = 0;
698
699 h = extract_host(&inxdr, want, err);
700 xdr_destroy(&inxdr);
701 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
702
703 return h;
704 }
705
706 static struct hostent *
707 lu_gethostbyname(const char *name, int want, int *err)
708 {
709 struct hostent *h;
710 unsigned int datalen;
711 char namebuf[_LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT];
712 XDR outxdr;
713 XDR inxdr;
714 static int proc4 = -1;
715 static int proc6 = -1;
716 char *lookup_buf;
717 int proc, count, family;
718
719 family = AF_INET;
720 if (want > WANT_A4_ONLY) family = AF_INET6;
721
722 if (((want == WANT_MAPPED_A4_ONLY) || (family == AF_INET)) && (proc4 < 0))
723 {
724 if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS)
725 {
726 *err = NO_RECOVERY;
727 return NULL;
728 }
729 }
730 else if ((family == AF_INET6) && (proc6 < 0))
731 {
732 if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
733 {
734 *err = NO_RECOVERY;
735 return NULL;
736 }
737 }
738
739 proc = proc4;
740 if ((family == AF_INET6) && (want != WANT_MAPPED_A4_ONLY)) proc = proc6;
741
742 xdrmem_create(&outxdr, namebuf, sizeof(namebuf), XDR_ENCODE);
743 if (!xdr__lu_string(&outxdr, (_lu_string *)&name))
744 {
745 xdr_destroy(&outxdr);
746 *err = NO_RECOVERY;
747 return NULL;
748 }
749
750 datalen = 0;
751 lookup_buf = NULL;
752
753 if (_lookup_all(_lu_port, proc, (unit *)namebuf, xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT, &lookup_buf, &datalen) != KERN_SUCCESS)
754 {
755 xdr_destroy(&outxdr);
756 *err = HOST_NOT_FOUND;
757 return NULL;
758 }
759
760 xdr_destroy(&outxdr);
761
762 datalen *= BYTES_PER_XDR_UNIT;
763 if ((lookup_buf == NULL) || (datalen == 0)) return NULL;
764
765 xdrmem_create(&inxdr, lookup_buf, datalen, XDR_DECODE);
766
767 count = 0;
768 if (!xdr_int(&inxdr, &count))
769 {
770 xdr_destroy(&inxdr);
771 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
772 *err = NO_RECOVERY;
773 return NULL;
774 }
775
776 if (count == 0)
777 {
778 xdr_destroy(&inxdr);
779 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
780 *err = HOST_NOT_FOUND;
781 return NULL;
782 }
783
784 *err = 0;
785
786 h = extract_host(&inxdr, want, err);
787 xdr_destroy(&inxdr);
788 vm_deallocate(mach_task_self(), (vm_address_t)lookup_buf, datalen);
789
790 return h;
791 }
792
793 static void
794 lu_endhostent()
795 {
796 struct lu_thread_info *tdata;
797
798 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
799 _lu_data_free_vm_xdr(tdata);
800 }
801
802 static void
803 lu_sethostent()
804 {
805 lu_endhostent();
806 }
807
808 static struct hostent *
809 lu_gethostent(int want, int *err)
810 {
811 static int proc = -1;
812 struct lu_thread_info *tdata;
813 struct hostent *h;
814
815 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
816 if (tdata == NULL)
817 {
818 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
819 _lu_data_set_key(_lu_data_key_host, tdata);
820 }
821
822 if (tdata->lu_vm == NULL)
823 {
824 if (proc < 0)
825 {
826 if (_lookup_link(_lu_port, "gethostent", &proc) != KERN_SUCCESS)
827 {
828 lu_endhostent();
829 *err = NO_RECOVERY;
830 return NULL;
831 }
832 }
833
834 if (_lookup_all(_lu_port, proc, NULL, 0, &(tdata->lu_vm), &(tdata->lu_vm_length)) != KERN_SUCCESS)
835 {
836 lu_endhostent();
837 *err = HOST_NOT_FOUND;
838 return NULL;
839 }
840
841 /* mig stubs measure size in words (4 bytes) */
842 tdata->lu_vm_length *= 4;
843
844 if (tdata->lu_xdr != NULL)
845 {
846 xdr_destroy(tdata->lu_xdr);
847 free(tdata->lu_xdr);
848 }
849 tdata->lu_xdr = (XDR *)calloc(1, sizeof(XDR));
850
851 xdrmem_create(tdata->lu_xdr, tdata->lu_vm, tdata->lu_vm_length, XDR_DECODE);
852 if (!xdr_int(tdata->lu_xdr, &tdata->lu_vm_cursor))
853 {
854 lu_endhostent();
855 *err = NO_RECOVERY;
856 return NULL;
857 }
858 }
859
860 if (tdata->lu_vm_cursor == 0)
861 {
862 lu_endhostent();
863 *err = HOST_NOT_FOUND;
864 return NULL;
865 }
866
867 h = extract_host(tdata->lu_xdr, want, err);
868 if (h == NULL)
869 {
870 lu_endhostent();
871 *err = HOST_NOT_FOUND;
872 return NULL;
873 }
874
875 *err = 0;
876 tdata->lu_vm_cursor--;
877
878 return h;
879 }
880
881 static struct hostent *
882 gethostbyaddrerrno(const char *addr, int len, int type, int *err)
883 {
884 struct hostent *res = NULL;
885 int want, from_cache;
886
887 *err = 0;
888
889 want = WANT_A4_ONLY;
890 if (type == AF_INET6) want = WANT_A6_ONLY;
891
892 if ((type == AF_INET6) && (len == 16) && (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr)))
893 {
894 addr += 12;
895 len = 4;
896 type = AF_INET;
897 want = WANT_MAPPED_A4_ONLY;
898 }
899
900 from_cache = 0;
901 res = cache_gethostbyaddr(addr, want);
902
903 if (res != NULL)
904 {
905 from_cache = 1;
906 }
907 else if (_lu_running())
908 {
909 res = lu_gethostbyaddr(addr, want, err);
910 }
911 else
912 {
913 pthread_mutex_lock(&_host_lock);
914 res = copy_host(_old_gethostbyaddr(addr, len, type));
915 *err = h_errno;
916 pthread_mutex_unlock(&_host_lock);
917 }
918
919 if (from_cache == 0) cache_host(res, want, CACHE_BYADDR);
920
921 return res;
922 }
923
924 struct hostent *
925 gethostbyaddr(const void *addr, socklen_t len, int type)
926 {
927 struct hostent *res;
928 struct lu_thread_info *tdata;
929
930 res = gethostbyaddrerrno(addr, len, type, &h_errno);
931 if (res == NULL)
932 {
933 return NULL;
934 }
935
936 tdata = _lu_data_create_key(_lu_data_key_host, free_lu_thread_info_host);
937 if (tdata == NULL)
938 {
939 tdata = (struct lu_thread_info *)calloc(1, sizeof(struct lu_thread_info));
940 _lu_data_set_key(_lu_data_key_host, tdata);
941 }
942
943 recycle_host(tdata, res);
944 return (struct hostent *)tdata->lu_entry;
945 }
946
947 struct hostent *
948 gethostbynameerrno(const char *name, int *err)
949 {
950 struct hostent *res = NULL;
951 struct in_addr addr;
952 int i, is_addr, from_cache;
953
954 *err = 0;
955
956 /*
957 * If name is all dots and digits without a trailing dot,
958 * call inet_aton. If it's OK, return a fake entry.
959 * Otherwise, return an error.
960 *
961 * If name has alpha or ends with a dot, proceed as usual...
962 */
963 if (name == NULL)
964 {
965 *err = HOST_NOT_FOUND;
966 return NULL;
967 }
968
969 if (name[0] == '\0')
970 {
971 *err = HOST_NOT_FOUND;
972 return NULL;
973 }
974
975 is_addr = 1;
976 for (i = 0; name[i] != '\0'; i++)
977 {
978 if (name[i] == '.') continue;
979 if ((name[i] >= '0') && (name[i] <= '9')) continue;
980 is_addr = 0;
981 break;
982 }
983
984 if ((is_addr == 1) && (name[i-1] == '.')) is_addr = 0;
985
986 res = NULL;
987 from_cache = 0;
988
989 if (is_addr == 1)
990 {
991 if (inet_aton(name, &addr) == 0)
992 {
993 *err = HOST_NOT_FOUND;
994 return NULL;
995 }
996 res = fake_hostent(name, addr);
997 }
998
999 if (res == NULL)
1000 {
1001 res = cache_gethostbyname(name, WANT_A4_ONLY);
1002 }
1003
1004 if (res != NULL)
1005 {
1006 from_cache = 1;
1007 }
1008 else if (_lu_running())
1009 {
1010 res = lu_gethostbyname(name, WANT_A4_ONLY, err);
1011 }
1012 else
1013 {
1014 pthread_mutex_lock(&_host_lock);
1015 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 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(_old_gethostbyname(name));
1360 *err = h_errno;
1361 pthread_mutex_unlock(&_host_lock);
1362 }
1363
1364 if (res == NULL)
1365 {
1366 *err = HOST_NOT_FOUND;
1367 return NULL;
1368 }
1369
1370 if (from_cache == 0) cache_host(res, want, CACHE_BYNAME);
1371
1372 return res;
1373 }
1374
1375 /*
1376 * Given a host's name, this routine returns its 48 bit ethernet address.
1377 * Returns zero if successful, non-zero otherwise.
1378 */
1379 int
1380 lu_ether_hostton(const char *host, struct ether_addr *e)
1381 {
1382 unsigned int i, n, j, x[6];
1383 ni_proplist *q, **r;
1384 char *s;
1385
1386 if (host == NULL) return -1;
1387 if (e == NULL) return -1;
1388
1389 q = lookupd_make_query("2", "kvk", "name", host, "en_address");
1390 if (q == NULL) return -1;
1391
1392 n = lookupd_query(q, &r);
1393 ni_proplist_free(q);
1394 free(q);
1395
1396 if (n == 0) return -1;
1397 if (r[0] == NULL) return -1;
1398
1399 i = ni_proplist_match(*r[0], "en_address", NULL);
1400 if (i == (unsigned int)NI_INDEX_NULL) return -1;
1401
1402 if (r[0]->ni_proplist_val[i].nip_val.ni_namelist_len == 0) return -1;
1403
1404 s = r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0];
1405 j = sscanf(s, " %x:%x:%x:%x:%x:%x", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);
1406 if (j != 6)
1407 {
1408 for (i = 0; i < n; i++)
1409 {
1410 ni_proplist_free(r[i]);
1411 free(r[i]);
1412 }
1413 free(r);
1414 return -1;
1415 }
1416
1417 for (i = 0; i < 6; i++) e->ether_addr_octet[i] = x[i];
1418
1419 for (i = 0; i < n; i++)
1420 {
1421 ni_proplist_free(r[i]);
1422 free(r[i]);
1423 }
1424
1425 free(r);
1426 return 0;
1427 }
1428
1429 /*
1430 * Given a 48 bit ethernet address, this routine return its host name.
1431 * Returns zero if successful, non-zero otherwise.
1432 */
1433 int
1434 lu_ether_ntohost(char *host, const struct ether_addr *e)
1435 {
1436 unsigned int i, n, len, x[6];
1437 ni_proplist *q, **r;
1438 char str[256];
1439
1440 if (host == NULL) return -1;
1441 if (e == NULL) return -1;
1442
1443 for (i = 0; i < 6; i++) x[i] = e->ether_addr_octet[i];
1444 sprintf(str, "%x:%x:%x:%x:%x:%x", x[0], x[1], x[2], x[3], x[4], x[5]);
1445
1446 q = lookupd_make_query("2", "kv", "en_address", str);
1447 if (q == NULL) return -1;
1448
1449 n = lookupd_query(q, &r);
1450 ni_proplist_free(q);
1451 free(q);
1452 if (n == 0) return -1;
1453 if (r[0] == NULL) return -1;
1454
1455 i = ni_proplist_match(*r[0], "name", NULL);
1456 if (i == (unsigned int)NI_INDEX_NULL) return -1;
1457
1458 if (r[0]->ni_proplist_val[i].nip_val.ni_namelist_len == 0) return -1;
1459
1460 len = strlen(r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0]) + 1;
1461 memcpy(host, r[0]->ni_proplist_val[i].nip_val.ni_namelist_val[0], len);
1462
1463 for (i = 0; i < n; i++) ni_proplist_free(r[i]);
1464 free(r);
1465 return 0;
1466 }
1467
1468 int
1469 ether_hostton(const char *host, struct ether_addr *e)
1470 {
1471 if (_lu_running()) return lu_ether_hostton(host, e);
1472 return _old_ether_hostton(host, e);
1473 }
1474
1475 int
1476 ether_ntohost(char *host, const struct ether_addr *e)
1477 {
1478 if (_lu_running()) return lu_ether_ntohost(host, e);
1479 return _old_ether_ntohost(host, e);
1480 }