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