]> git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/si_getaddrinfo.c
bf852b99ce690e5063d1691292b7e7a455a12862
[apple/libinfo.git] / lookup.subproj / si_getaddrinfo.c
1 /*
2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <netdb.h>
25 #include <sys/types.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <sys/socket.h>
30 #include <net/if.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <ifaddrs.h>
34 #include <net/if.h>
35 #include <string.h>
36 #include <sys/param.h>
37 #include <notify.h>
38 #include <notify_keys.h>
39 #include <pthread.h>
40 #include <TargetConditionals.h>
41 #include "netdb_async.h"
42 #include "si_module.h"
43
44 #define SOCK_UNSPEC 0
45 #define IPPROTO_UNSPEC 0
46
47 #define IPV6_ADDR_LEN 16
48 #define IPV4_ADDR_LEN 4
49
50 #define WANT_NOTHING 0
51 #define WANT_A4_ONLY 1
52 #define WANT_A6_ONLY 2
53 #define WANT_A6_PLUS_MAPPED_A4 3
54 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
55
56 #define V6TO4_PREFIX_16 0x2002
57
58 static int net_config_token = -1;
59 static uint32_t net_v4_count = 0;
60 static uint32_t net_v6_count = 0; // includes 6to4 addresses
61 static uint32_t net_v6to4_count = 0;
62 static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
63
64 typedef struct {
65 struct hostent host;
66 int alias_count;
67 int addr_count;
68 uint64_t ttl;
69 } build_hostent_t;
70
71 static int
72 _si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4)
73 {
74 int status, checkit;
75 struct ifaddrs *ifa, *ifap;
76 struct sockaddr_in6 *sa6;
77
78 pthread_mutex_lock(&net_config_mutex);
79
80 checkit = 1;
81
82 if (net_config_token < 0)
83 {
84 status = notify_register_check(kNotifySCNetworkChange, &net_config_token);
85 if (status != 0) net_config_token = -1;
86 }
87
88 if (net_config_token >= 0)
89 {
90 status = notify_check(net_config_token, &checkit);
91 if (status != 0) checkit = 1;
92 }
93
94 status = 0;
95
96 if (checkit != 0)
97 {
98 if (getifaddrs(&ifa) < 0)
99 {
100 status = -1;
101 }
102 else
103 {
104 net_v4_count = 0;
105 net_v6_count = 0;
106 net_v6to4_count = 0;
107 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
108 {
109 if (ifap->ifa_addr == NULL) continue;
110 if ((ifap->ifa_flags & IFF_UP) == 0) continue;
111
112 if (ifap->ifa_addr->sa_family == AF_INET)
113 {
114 net_v4_count++;
115 }
116 else if (ifap->ifa_addr->sa_family == AF_INET6)
117 {
118 net_v6_count++;
119 sa6 = (struct sockaddr_in6 *)ifap->ifa_addr;
120 if (sa6->sin6_addr.__u6_addr.__u6_addr16[0] == ntohs(V6TO4_PREFIX_16)) net_v6to4_count++;
121 }
122 }
123
124 freeifaddrs(ifa);
125 }
126 }
127
128 if (v4 != NULL) *v4 = net_v4_count;
129 if (v6 != NULL) *v6 = net_v6_count;
130 if (v6to4 != NULL) *v6to4 = net_v6to4_count;
131
132 pthread_mutex_unlock(&net_config_mutex);
133
134 return status;
135 }
136
137 void
138 freeaddrinfo(struct addrinfo *a)
139 {
140 struct addrinfo *next;
141
142 while (a != NULL)
143 {
144 next = a->ai_next;
145 if (a->ai_addr != NULL) free(a->ai_addr);
146 if (a->ai_canonname != NULL) free(a->ai_canonname);
147 free(a);
148 a = next;
149 }
150 }
151
152 const char *
153 gai_strerror(int32_t err)
154 {
155 switch (err)
156 {
157 case EAI_ADDRFAMILY: return "Address family for nodename not supported";
158 case EAI_AGAIN: return "Temporary failure in name resolution";
159 case EAI_BADFLAGS: return "Invalid value for ai_flags";
160 case EAI_FAIL: return "Non-recoverable failure in name resolution";
161 case EAI_FAMILY: return "ai_family not supported";
162 case EAI_MEMORY: return "Memory allocation failure";
163 case EAI_NODATA: return "No address associated with nodename";
164 case EAI_NONAME: return "nodename nor servname provided, or not known";
165 case EAI_SERVICE: return "servname not supported for ai_socktype";
166 case EAI_SOCKTYPE: return "ai_socktype not supported";
167 case EAI_SYSTEM: return "System error";
168 case EAI_BADHINTS: return "Bad hints";
169 case EAI_PROTOCOL: return "ai_protocol not supported";
170 case EAI_OVERFLOW: return "argument buffer overflow";
171 }
172
173 return "Unknown error";
174 }
175
176 /*
177 * getnameinfo
178 *
179 * We handle some "trival" cases locally. If the caller passes
180 * NI_NUMERICHOST (only), then this call turns into a getservbyport
181 * to get the service name + inet_pton() to create a host string.
182 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
183 * number, complete the getnameinfo, and use printf() to create a service
184 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
185 * we inet_ntop() and printf() and return the results.
186 */
187 __private_extern__ si_item_t *
188 si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
189 {
190 si_item_t *out = NULL;
191 const struct sockaddr *lookup_sa;
192 struct sockaddr_in s4;
193 struct in_addr a4;
194 struct in6_addr a6;
195 const uint64_t unused = 0;
196 void *addr = NULL;
197 char *host = NULL;
198 char *serv = NULL;
199 uint32_t ifnum = 0;
200 uint16_t port = 0;
201
202 int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
203 int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);
204
205 /* check input */
206 if ((si == NULL) || (sa == NULL))
207 {
208 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
209 return NULL;
210 }
211
212 if (err != NULL) *err = SI_STATUS_NO_ERROR;
213
214 lookup_sa = sa;
215
216 if (sa->sa_family == AF_INET)
217 {
218 struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
219 memcpy(&a4, &s4->sin_addr, sizeof(a4));
220 port = s4->sin_port;
221 addr = &a4;
222 }
223 else if (sa->sa_family == AF_INET6)
224 {
225 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
226 memcpy(&a6, &s6->sin6_addr, sizeof(a6));
227 port = s6->sin6_port;
228
229 /* Look for link-local IPv6 scope id */
230 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
231 {
232 ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
233 if (ifnum == 0)
234 {
235 ifnum = s6->sin6_scope_id;
236 a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
237 }
238
239 if (ifnum != s6->sin6_scope_id &&
240 s6->sin6_scope_id != 0)
241 {
242 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
243 return NULL;
244 }
245 }
246
247 /* v4 mapped and compat addresses are converted to plain v4 */
248 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
249 {
250 memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
251 addr = &a4;
252 memset(&s4, 0, sizeof(s4));
253 s4.sin_len = sizeof(s4);
254 s4.sin_family = AF_INET;
255 s4.sin_port = port;
256 memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
257 lookup_sa = (const struct sockaddr *)&s4;
258 }
259 else
260 {
261 addr = &a6;
262 }
263 }
264 else
265 {
266 if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
267 return NULL;
268 }
269
270 if (do_host_lookup == 1)
271 {
272 #if 0
273 if ((do_serv_lookup == 1) && (si->sim_nameinfo != NULL))
274 {
275 return si->sim_nameinfo(si, lookup_sa, flags, interface, err);
276 }
277 #endif
278 si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL);
279 if (item != NULL)
280 {
281 struct hostent *h;
282 h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
283 host = strdup(h->h_name);
284 si_item_release(item);
285 if (host == NULL)
286 {
287 if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
288 return NULL;
289 }
290 }
291 }
292
293 if ((do_serv_lookup == 1) && (port != 0))
294 {
295 si_item_t *item = si_service_byport(si, port, NULL);
296 if (item != NULL)
297 {
298 struct servent *s;
299 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
300 serv = strdup(s->s_name);
301 si_item_release(item);
302 if (serv == NULL)
303 {
304 free(host);
305 if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
306 return NULL;
307 }
308 }
309 }
310
311 /*
312 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
313 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
314 */
315 if (host == NULL && (flags & NI_NAMEREQD) == 0)
316 {
317 char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
318 tmp[0] = '\0';
319 if (sa->sa_family == AF_INET)
320 {
321 char buf[INET_ADDRSTRLEN];
322 if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
323 {
324 host = strdup(buf);
325 }
326 }
327 else if (sa->sa_family == AF_INET6)
328 {
329 char buf[INET6_ADDRSTRLEN];
330
331 /* zero the embedded scope ID */
332 if (ifnum != 0)
333 {
334 a6.__u6_addr.__u6_addr16[1] = 0;
335 }
336
337 if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
338 {
339 if (ifnum != 0)
340 {
341 char ifname[IF_NAMESIZE];
342 if (if_indextoname(ifnum, ifname) != NULL)
343 {
344 asprintf(&host, "%s%%%s", buf, ifname);
345 }
346 else
347 {
348 /* ENXIO */
349 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
350 return NULL;
351 }
352 }
353 else
354 {
355 host = strdup(buf);
356 }
357 }
358 }
359 }
360
361 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
362 if (serv == NULL)
363 {
364 asprintf(&serv, "%hu", ntohs(port));
365 }
366
367 if ((host == NULL) || (serv == NULL))
368 {
369 if (err != NULL)
370 {
371 if ((flags & NI_NAMEREQD) != 0)
372 {
373 *err = SI_STATUS_EAI_NONAME;
374 }
375 else
376 {
377 *err = SI_STATUS_EAI_MEMORY;
378 }
379 }
380 }
381 else
382 {
383 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
384 }
385
386 free(host);
387 free(serv);
388 return out;
389 }
390
391 static int
392 _gai_numericserv(const char *serv, uint16_t *port)
393 {
394 int numeric;
395 char *endptr;
396 long num;
397
398 numeric = 0;
399
400 if (serv == NULL)
401 {
402 if (port) *port = 0;
403 numeric = 1;
404 }
405 else
406 {
407 num = strtol(serv, &endptr, 10);
408 if ((serv[0] != '\0') && (*endptr == '\0') && (num >= 0) && (num <= UINT16_MAX))
409 {
410 numeric = 1;
411 if (port != NULL) *port = (uint16_t)num;
412 }
413 }
414
415 return numeric;
416 }
417
418 __private_extern__ int
419 _gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port)
420 {
421 si_item_t *item;
422 struct servent *s;
423 const char *protoname = NULL;
424
425 if (_gai_numericserv(serv, port)) return 0;
426
427 if (proto == IPPROTO_UDP) protoname = "udp";
428 if (proto == IPPROTO_TCP) protoname = "tcp";
429
430 item = si_service_byname(si_search(), serv, protoname);
431 if (item == NULL) return -1;
432
433 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
434 if (port) *port = ntohs(s->s_port);
435 si_item_release(item);
436
437 return 0;
438 }
439
440 __private_extern__ si_item_t *
441 si_addrinfo_v4(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr *addr, uint16_t iface, const char *cname)
442 {
443 socket_data_t sockdata;
444 struct sockaddr_in *sa;
445 int32_t len, v32;
446 uint64_t unused;
447
448 unused = 0;
449 len = sizeof(struct sockaddr_in);
450 memset(&sockdata, 0, sizeof(socket_data_t));
451 sa = (struct sockaddr_in *)&sockdata;
452
453 sa->sin_len = len;
454 sa->sin_family = AF_INET;
455 sa->sin_port = htons(port);
456 memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr));
457
458 /* Kludge: Jam the interface number into sin_zero (4 bytes). */
459 v32 = iface;
460 memmove(sa->sin_zero, &v32, sizeof(uint32_t));
461
462 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname);
463 }
464
465 __private_extern__ si_item_t *
466 si_addrinfo_v6(si_mod_t *si, int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr *addr, uint16_t iface, const char *cname)
467 {
468 socket_data_t sockdata;
469 struct sockaddr_in6 *sa;
470 int32_t len;
471 uint64_t unused;
472
473 unused = 0;
474 len = sizeof(struct sockaddr_in6);
475 memset(&sockdata, 0, sizeof(socket_data_t));
476 sa = (struct sockaddr_in6 *)&sockdata;
477
478 sa->sin6_len = len;
479 sa->sin6_family = AF_INET6;
480 sa->sin6_port = htons(port);
481 memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr));
482
483 /* sin6_scope_id is in host byte order */
484 sa->sin6_scope_id = iface;
485
486 if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
487 {
488 /* check for embedded scopeid */
489 uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]);
490 if (esid != 0)
491 {
492 sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
493 if (iface == 0) sa->sin6_scope_id = esid;
494 }
495 }
496
497 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
498 }
499
500 __private_extern__ si_list_t *
501 si_addrinfo_list(si_mod_t *si, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6)
502 {
503 si_item_t *item = NULL;
504 si_list_t *out4 = NULL, *out6 = NULL;
505 if (a4 != NULL)
506 {
507 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
508 {
509 item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
510 out4 = si_list_add(out4, item);
511 si_item_release(item);
512 }
513
514 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
515 {
516 item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
517 out4 = si_list_add(out4, item);
518 si_item_release(item);
519 }
520
521 if (proto == IPPROTO_ICMP)
522 {
523 item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
524 out4 = si_list_add(out4, item);
525 si_item_release(item);
526 }
527 }
528
529 if (a6 != NULL)
530 {
531 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
532 {
533 item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6);
534 out6 = si_list_add(out6, item);
535 si_item_release(item);
536 }
537
538 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
539 {
540 item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6);
541 out6 = si_list_add(out6, item);
542 si_item_release(item);
543 }
544
545 if (proto == IPPROTO_ICMPV6)
546 {
547 item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6);
548 out6 = si_list_add(out6, item);
549 si_item_release(item);
550 }
551 }
552
553 out6 = si_list_concat(out6, out4);
554 si_list_release(out4);
555
556 return out6;
557 }
558
559 /*
560 * _gai_numerichost
561 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
562 * based on the address family input value. If the input addres family is
563 * unspecified, a more specific value will be provided on output if possible.
564 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
565 */
566 static int
567 _gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_addr *a4, struct in6_addr *a6)
568 {
569 int numerichost, passive;
570
571 numerichost = 0;
572
573 if (nodename == NULL)
574 {
575 /* return loopback or passive addresses */
576 passive = (flags & AI_PASSIVE);
577
578 if ((*family == AF_UNSPEC) || (*family == AF_INET))
579 {
580 if (passive) a4->s_addr = 0;
581 else a4->s_addr = htonl(INADDR_LOOPBACK);
582 }
583
584 if ((*family == AF_UNSPEC) || (*family == AF_INET6))
585 {
586 memset(a6, 0, sizeof(*a6));
587 if (!passive) a6->__u6_addr.__u6_addr32[3] = htonl(1);
588 }
589
590 numerichost = 1;
591 }
592 else
593 {
594 /* numeric IPv4 host valid for AF_UNSPEC and AF_INET */
595 numerichost = inet_pton(AF_INET, nodename, a4);
596 if (numerichost == 1)
597 {
598 if (*family == AF_UNSPEC) *family = AF_INET;
599 else if (*family == AF_INET6) numerichost = -1;
600 return numerichost;
601 }
602
603 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
604 numerichost = inet_pton(AF_INET6, nodename, a6);
605 if (numerichost == 1)
606 {
607 if (*family == AF_UNSPEC) *family = AF_INET6;
608 else if (*family == AF_INET) numerichost = -1;
609 return numerichost;
610 }
611 }
612
613 return numerichost;
614 }
615
616 /* si_addrinfo_list_from_hostent
617 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
618 */
619 __private_extern__ si_list_t *
620 si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t socktype, uint32_t proto, uint16_t port, uint16_t scope, const struct hostent *h4, const struct hostent *h6)
621 {
622 int i;
623 si_list_t *out = NULL;
624 si_list_t *list;
625
626 if ((h6 != NULL) && (h6->h_addr_list != NULL))
627 {
628 for (i = 0; h6->h_addr_list[i] != NULL; i++)
629 {
630 struct in6_addr a6;
631 memcpy(&a6, h6->h_addr_list[i], h6->h_length);
632 list = si_addrinfo_list(si, socktype, proto, NULL, &a6, port, scope, NULL, h6->h_name);
633 out = si_list_concat(out, list);
634 si_list_release(list);
635 }
636 }
637
638 if ((h4 != NULL) && (h4->h_addr_list != NULL))
639 {
640 for (i = 0; h4->h_addr_list[i] != NULL; i++)
641 {
642 struct in_addr a4;
643 memcpy(&a4, h4->h_addr_list[i], h4->h_length);
644 list = si_addrinfo_list(si, socktype, proto, &a4, NULL, port, 0, h4->h_name, NULL);
645 out = si_list_concat(out, list);
646 si_list_release(list);
647 }
648 }
649
650 return out;
651 }
652
653 static si_list_t *
654 _gai_sort_list(si_list_t *in)
655 {
656 si_list_t *out;
657 int lead;
658 uint32_t i, v6to4;
659 si_addrinfo_t *a;
660
661 if (in == NULL) return NULL;
662
663 v6to4 = 0;
664 if (_si_netconfig(NULL, NULL, &v6to4) < 0) v6to4 = 0;
665
666 out = (si_list_t *)calloc(1, sizeof(si_list_t));
667 if (out == NULL) return in;
668
669 out->refcount = in->refcount;
670 out->count = in->count;
671 out->entry = (si_item_t **)calloc(in->count, sizeof(si_item_t *));
672 if (out->entry == NULL)
673 {
674 free(out);
675 return in;
676 }
677
678 lead = AF_INET6;
679 if (v6to4 > 0) lead = AF_INET;
680
681 out->curr = 0;
682
683 for (i = 0; i < in->count; i++)
684 {
685 a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
686 if (a->ai_family == lead) out->entry[out->curr++] = in->entry[i];
687 }
688
689 for (i = 0; i < in->count; i++)
690 {
691 a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t));
692 if (a->ai_family != lead) out->entry[out->curr++] = in->entry[i];
693 }
694
695 free(in->entry);
696 free(in);
697
698 out->curr = 0;
699
700 return out;
701 }
702
703 /* _gai_simple
704 * Simple lookup via gethostbyname2(3) mechanism.
705 */
706 __private_extern__ si_list_t *
707 _gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
708 {
709 si_item_t *h4_item = NULL, *h6_item = NULL;
710 struct hostent *h4 = NULL, *h6 = NULL;
711 si_list_t *out = NULL;
712 uint16_t port;
713
714 if ((flags & AI_NUMERICSERV) != 0)
715 {
716 port = *(uint16_t*)servptr;
717 }
718 else
719 {
720 if (_gai_serv_to_port(servptr, proto, &port) != 0)
721 {
722 if (err) *err = SI_STATUS_EAI_NONAME;
723 return NULL;
724 }
725 }
726
727 if ((flags & AI_NUMERICHOST) != 0)
728 {
729 if (family == AF_INET)
730 {
731 h4_item = si_host_byaddr(si, nodeptr, AF_INET, interface, NULL);
732 }
733 else if (family == AF_INET6)
734 {
735 h6_item = si_host_byaddr(si, nodeptr, AF_INET6, interface, NULL);
736 }
737 }
738 else
739 {
740 if ((family == AF_INET) || (family == AF_UNSPEC))
741 {
742 h4_item = si_host_byname(si, nodeptr, AF_INET, interface, NULL);
743 }
744
745 if ((family == AF_INET6) || (family == AF_UNSPEC))
746 {
747 h6_item = si_host_byname(si, nodeptr, AF_INET6, interface, NULL);
748 }
749 }
750
751 if (h4_item != NULL)
752 {
753 h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t));
754 }
755
756 if (h6_item != NULL)
757 {
758 h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t));
759 }
760
761 out = si_addrinfo_list_from_hostent(si, socktype, proto, port, 0, h4, h6);
762 si_item_release(h4_item);
763 si_item_release(h6_item);
764
765 return _gai_sort_list(out);
766 }
767
768 __private_extern__ si_list_t *
769 si_srv_byname(si_mod_t *si, const char *qname, const char *interface, uint32_t *err)
770 {
771 if (si == NULL) return 0;
772 if (si->sim_srv_byname == NULL) return 0;
773
774 return si->sim_srv_byname(si, qname, interface, err);
775 }
776
777 __private_extern__ int
778 si_wants_addrinfo(si_mod_t *si)
779 {
780 if (si == NULL) return 0;
781 if (si->sim_addrinfo == NULL) return 0;
782 if (si->sim_wants_addrinfo == NULL) return 0;
783
784 return si->sim_wants_addrinfo(si);
785 }
786
787 static si_list_t *
788 _gai_srv(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
789 {
790 int i;
791 char *qname;
792 si_srv_t *srv;
793 si_item_t *item;
794
795 si_list_t *list = NULL;
796 si_list_t *result = NULL;
797
798 /* Minimum SRV priority is zero. Start below that. */
799 int lastprio = -1;
800 int currprio;
801
802 if (node == NULL || serv == NULL) return NULL;
803
804 asprintf(&qname, "%s.%s", serv, node);
805 list = si_srv_byname(si, qname, interface, err);
806 free(qname);
807
808 /* Iterate the SRV records starting at lowest priority and attempt to
809 * lookup the target host name. Returns the first successful lookup.
810 * It's an O(n^2) algorithm but data sets are small (less than 100) and
811 * sorting overhead is dwarfed by network I/O for each element.
812 */
813 while (list != NULL && result == NULL)
814 {
815 /* Find the next lowest priority level. */
816 /* Maximum SRV priority is UINT16_MAX. Start above that. */
817 currprio = INT_MAX;
818
819 for (i = 0; i < list->count; ++i)
820 {
821 item = list->entry[i];
822 srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
823
824 if (srv->priority > lastprio && srv->priority < currprio)
825 {
826 currprio = srv->priority;
827 }
828 }
829
830 if (currprio == INT_MAX)
831 {
832 /* All priorities have been evaluated. Done. */
833 break;
834 }
835 else
836 {
837 lastprio = currprio;
838 }
839
840 /* Lookup hosts at the current priority level. Return first match. */
841 for (i = 0; i < list->count; ++i)
842 {
843 item = list->entry[i];
844 srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
845
846 if (srv->priority == currprio)
847 {
848 /* So that _gai_simple expects an integer service. */
849 flags |= AI_NUMERICSERV;
850
851 result = _gai_simple(si, srv->target, &srv->port, family, socktype, proto, flags, interface, err);
852 if (result)
853 {
854 break;
855 }
856 }
857 }
858 }
859
860 if (list != NULL)
861 {
862 si_list_release(list);
863 }
864
865 return result;
866 }
867
868 __private_extern__ si_list_t *
869 si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
870 {
871 int numerichost, numericserv = 0;
872 const void *nodeptr = NULL, *servptr = NULL;
873 uint16_t port;
874 struct in_addr a4, *p4;
875 struct in6_addr a6, *p6;
876 const char *cname;
877 si_list_t *out;
878
879 if (err != NULL) *err = SI_STATUS_NO_ERROR;
880
881 if (si == NULL)
882 {
883 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
884 return NULL;
885 }
886
887 /* treat empty strings as NULL */
888 if ((node != NULL) && (node[0] == '\0')) node = NULL;
889 if ((serv != NULL) && (serv[0] == '\0')) serv = NULL;
890
891 /* make sure we have a query */
892 if ((node == NULL) && (serv == NULL))
893 {
894 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
895 return NULL;
896 }
897
898 /* verify family is supported */
899 switch (family)
900 {
901 case AF_UNSPEC:
902 case AF_INET:
903 case AF_INET6:
904 break;
905 default:
906 if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
907 return NULL;
908 }
909
910 /* verify socket type is supported */
911 switch (socktype)
912 {
913 case SOCK_UNSPEC:
914 case SOCK_RAW:
915 case SOCK_DGRAM:
916 case SOCK_STREAM:
917 break;
918 default:
919 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
920 return NULL;
921 }
922
923 /* verify protocol is supported */
924 switch (proto)
925 {
926 case IPPROTO_UNSPEC:
927 case IPPROTO_UDP:
928 case IPPROTO_TCP:
929 case IPPROTO_ICMP:
930 case IPPROTO_ICMPV6:
931 break;
932 default:
933 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
934 return NULL;
935 }
936
937 /* verify socket type compatible with protocol */
938 if (((socktype == SOCK_DGRAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_UDP)) || ((socktype == SOCK_STREAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_TCP)))
939 {
940 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
941 return NULL;
942 }
943
944 memset(&a4, 0, sizeof(struct in_addr));
945 memset(&a6, 0, sizeof(struct in6_addr));
946
947 /* determine the protocol if possible */
948 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_DGRAM)) proto = IPPROTO_UDP;
949 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_STREAM)) proto = IPPROTO_TCP;
950
951 port = 0;
952
953 if ((flags & AI_SRV) != 0)
954 {
955 /* AI_SRV SPI */
956 out = _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err);
957 return _gai_sort_list(out);
958 }
959 else
960 {
961 /* Usual service lookup */
962 numericserv = _gai_numericserv(serv, &port);
963 }
964
965 if ((flags & AI_NUMERICSERV) && (numericserv == 0))
966 {
967 /* FreeBSD returns SI_STATUS_EAI_SERVICE */
968 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
969 return NULL;
970 }
971
972 if (serv != NULL)
973 {
974 if (numericserv == 1)
975 {
976 flags |= AI_NUMERICSERV;
977 servptr = &port;
978 }
979 else
980 {
981 servptr = serv;
982 }
983 }
984
985 numerichost = _gai_numerichost(node, &family, flags, &a4, &a6);
986 if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0)))
987 {
988 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
989 return NULL;
990 }
991
992 if (numerichost == 1)
993 {
994 flags |= AI_NUMERICHOST;
995 if (family == AF_INET)
996 {
997 nodeptr = &a4;
998 }
999 else if (family == AF_INET6)
1000 {
1001 nodeptr = &a6;
1002 }
1003 }
1004 else
1005 {
1006 nodeptr = node;
1007 }
1008
1009 if ((numerichost == 1) && (numericserv == 0))
1010 {
1011 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */
1012 if (_gai_serv_to_port(serv, proto, &port) != 0)
1013 {
1014 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
1015 return NULL;
1016 }
1017 else
1018 {
1019 flags |= AI_NUMERICSERV;
1020 servptr = &port;
1021 numericserv = 1;
1022 }
1023 }
1024
1025 if ((numerichost == 1) && (numericserv == 1))
1026 {
1027 p4 = &a4;
1028 p6 = &a6;
1029 cname = NULL;
1030
1031 if (family == AF_INET) p6 = NULL;
1032 if (family == AF_INET6) p4 = NULL;
1033 if (node == NULL) cname = "localhost";
1034
1035 /* handle trivial questions */
1036 out = si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname);
1037 return _gai_sort_list(out);
1038 }
1039 else if ((si->sim_wants_addrinfo != NULL) && si->sim_wants_addrinfo(si))
1040 {
1041 /* or let the current module handle the host lookups intelligently */
1042 out = si->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
1043 return _gai_sort_list(out);
1044 }
1045
1046 /* fall back to a default path */
1047 out = _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err);
1048 return _gai_sort_list(out);
1049 }
1050
1051 static struct addrinfo *
1052 si_item_to_addrinfo(si_item_t *item)
1053 {
1054 si_addrinfo_t *a;
1055 struct addrinfo *out;
1056
1057 if (item == NULL) return NULL;
1058
1059 a = (si_addrinfo_t *)((uintptr_t)item + sizeof(si_item_t));
1060
1061 out = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
1062 if (out == NULL) return NULL;
1063
1064 out->ai_flags = a->ai_flags;
1065 out->ai_family = a->ai_family;
1066 out->ai_socktype = a->ai_socktype;
1067 out->ai_protocol = a->ai_protocol;
1068 out->ai_addrlen = a->ai_addrlen;
1069
1070 out->ai_addr = (struct sockaddr *)calloc(1, out->ai_addrlen);
1071 if (out->ai_addr == NULL)
1072 {
1073 free(out);
1074 return NULL;
1075 }
1076
1077 memcpy(out->ai_addr, a->ai_addr.x, out->ai_addrlen);
1078
1079 if (a->ai_canonname != NULL)
1080 {
1081 out->ai_canonname = strdup(a->ai_canonname);
1082 if (out->ai_canonname == NULL)
1083 {
1084 free(out);
1085 return NULL;
1086 }
1087 }
1088
1089 return out;
1090 }
1091
1092 __private_extern__ struct addrinfo *
1093 si_list_to_addrinfo(si_list_t *list)
1094 {
1095 struct addrinfo *tail, *out;
1096 int i;
1097
1098 if (list == NULL) return NULL;
1099 if (list->count == 0) return NULL;
1100
1101 i = list->count - 1;
1102
1103 out = si_item_to_addrinfo(list->entry[i]);
1104 tail = out;
1105
1106 for (i--; i >= 0; i--)
1107 {
1108 out = si_item_to_addrinfo(list->entry[i]);
1109 if (out == NULL)
1110 {
1111 freeaddrinfo(tail);
1112 return NULL;
1113 }
1114
1115 out->ai_next = tail;
1116 tail = out;
1117 }
1118
1119 return out;
1120 }
1121
1122 /* getipnodebyname */
1123
1124 static si_item_t *
1125 make_hostent(si_mod_t *si, const char *name, struct in_addr addr)
1126 {
1127 char *addrs[2];
1128 char *aliases[1];
1129 uint64_t unused;
1130
1131 if (name == NULL) return NULL;
1132
1133 unused = 0;
1134
1135 addrs[0] = (char *)&(addr.s_addr);
1136 addrs[1] = NULL;
1137 aliases[0] = NULL;
1138
1139 return (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, unused, unused, name, aliases, AF_INET, IPV4_ADDR_LEN, addrs);
1140 }
1141
1142 static si_item_t *
1143 make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr)
1144 {
1145 char *addrs[2];
1146 char *aliases[1];
1147 uint64_t unused;
1148
1149 if (name == NULL) return NULL;
1150
1151 unused = 0;
1152
1153 addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]);
1154 addrs[1] = NULL;
1155 aliases[0] = NULL;
1156
1157 return (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, name, aliases, AF_INET6, IPV6_ADDR_LEN, addrs);
1158 }
1159
1160 static char *
1161 lower_case(const char *s)
1162 {
1163 int i;
1164 char *t;
1165
1166 if (s == NULL) return NULL;
1167
1168 t = malloc(strlen(s) + 1);
1169
1170 for (i = 0; s[i] != '\0'; i++)
1171 {
1172 if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32;
1173 else t[i] = s[i];
1174 }
1175
1176 t[i] = '\0';
1177
1178 return t;
1179 }
1180
1181 static int
1182 merge_alias(const char *name, build_hostent_t *h)
1183 {
1184 int i;
1185
1186 if (name == NULL) return 0;
1187 if (h == NULL) return 0;
1188
1189 if ((h->host.h_name != NULL) && (string_equal(name, h->host.h_name))) return 0;
1190
1191 for (i = 0; i < h->alias_count; i++)
1192 {
1193 if (string_equal(name, h->host.h_aliases[i])) return 0;
1194 }
1195
1196 if (h->alias_count == 0) h->host.h_aliases = (char **)calloc(2, sizeof(char *));
1197 else h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count + 2) * sizeof(char *));
1198
1199 if (h->host.h_aliases == NULL)
1200 {
1201 h->alias_count = 0;
1202 return -1;
1203 }
1204
1205 h->host.h_aliases[h->alias_count] = lower_case(name);
1206 h->alias_count++;
1207 h->host.h_aliases[h->alias_count] = NULL;
1208
1209 return 0;
1210 }
1211
1212 static int
1213 append_addr(const char *addr, uint32_t len, build_hostent_t *h)
1214 {
1215 if (addr == NULL) return 0;
1216 if (h == NULL) return 0;
1217
1218 if (h->addr_count == 0) h->host.h_addr_list = (char **)calloc(2, sizeof(char *));
1219 else h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count + 2) * sizeof(char *));
1220
1221 if (h->host.h_addr_list == NULL)
1222 {
1223 h->addr_count = 0;
1224 return -1;
1225 }
1226
1227 h->host.h_addr_list[h->addr_count] = malloc(len);
1228 if (h->host.h_addr_list[h->addr_count] == NULL) return -1;
1229
1230 memcpy(h->host.h_addr_list[h->addr_count], addr, len);
1231 h->addr_count++;
1232 h->host.h_addr_list[h->addr_count] = NULL;
1233
1234 return 0;
1235 }
1236
1237 static void
1238 free_build_hostent(build_hostent_t *h)
1239 {
1240 uint32_t i;
1241 char **aliases;
1242
1243 if (h == NULL) return;
1244
1245 if (h->host.h_name != NULL) free(h->host.h_name);
1246 h->host.h_name = NULL;
1247
1248 aliases = h->host.h_aliases;
1249 if (aliases != NULL)
1250 {
1251 while (*aliases != NULL) free(*aliases++);
1252 free(h->host.h_aliases);
1253 }
1254
1255 h->host.h_aliases = NULL;
1256
1257 if (h->host.h_addr_list != NULL)
1258 {
1259 for (i = 0; h->host.h_addr_list[i] != NULL; i++) free(h->host.h_addr_list[i]);
1260 free(h->host.h_addr_list);
1261 }
1262
1263 h->host.h_addr_list = NULL;
1264 free(h);
1265 }
1266
1267 __private_extern__ si_item_t *
1268 si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err)
1269 {
1270 int i, status, want;
1271 uint32_t if4, if6;
1272 struct in_addr addr4;
1273 struct in6_addr addr6;
1274 si_item_t *item4, *item6;
1275 build_hostent_t *out;
1276 struct hostent *h;
1277 uint64_t unused;
1278
1279 memset(&addr4, 0, sizeof(struct in_addr));
1280 memset(&addr6, 0, sizeof(struct in6_addr));
1281
1282 if (err != NULL) *err = 0;
1283
1284 if (family == AF_INET)
1285 {
1286 status = inet_aton(name, &addr4);
1287 if (status == 1)
1288 {
1289 /* create a host entry */
1290 item4 = make_hostent(si, name, addr4);
1291 if (item4 == NULL)
1292 {
1293 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1294 return NULL;
1295 }
1296
1297 return item4;
1298 }
1299 }
1300 else if (family == AF_INET6)
1301 {
1302 status = inet_pton(family, name, &addr6);
1303 if (status == 1)
1304 {
1305 /* create a host entry */
1306 item6 = make_hostent6(si, name, addr6);
1307 if (item6 == NULL)
1308 {
1309 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1310 return NULL;
1311 }
1312
1313 return item6;
1314 }
1315
1316 status = inet_aton(name, &addr4);
1317 if (status == 1)
1318 {
1319 if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)))
1320 {
1321 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1322 return NULL;
1323 }
1324
1325 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1326 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1327 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1328 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
1329
1330 /* create a host entry */
1331 item6 = make_hostent6(si, name, addr6);
1332 if (item6 == NULL)
1333 {
1334 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1335 return NULL;
1336 }
1337
1338 return item6;
1339 }
1340 }
1341 else
1342 {
1343 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1344 return NULL;
1345 }
1346
1347 /*
1348 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1349 */
1350
1351 if4 = 0;
1352 if6 = 0;
1353
1354 if (flags & AI_ADDRCONFIG)
1355 {
1356 if (_si_netconfig(&if4, &if6, NULL) < 0)
1357 {
1358 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1359 return NULL;
1360 }
1361
1362 /* Bail out if there are no interfaces */
1363 if ((if4 == 0) && (if6 == 0))
1364 {
1365 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1366 return NULL;
1367 }
1368 }
1369
1370 /*
1371 * Figure out what we want.
1372 * If user asked for AF_INET, we only want V4 addresses.
1373 */
1374 want = WANT_A4_ONLY;
1375
1376 if (family == AF_INET)
1377 {
1378 if ((flags & AI_ADDRCONFIG) && (if4 == 0))
1379 {
1380 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1381 return NULL;
1382 }
1383 }
1384 else if (family == AF_INET6)
1385 {
1386 /* family == AF_INET6 */
1387 want = WANT_A6_ONLY;
1388
1389 if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
1390 {
1391 if (flags & AI_ALL)
1392 {
1393 want = WANT_A6_PLUS_MAPPED_A4;
1394 }
1395 else
1396 {
1397 want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
1398 }
1399 }
1400 else
1401 {
1402 if ((flags & AI_ADDRCONFIG) && (if6 == 0))
1403 {
1404 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1405 return NULL;
1406 }
1407 }
1408 }
1409 else
1410 {
1411 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1412 return NULL;
1413 }
1414
1415 item6 = NULL;
1416 item4 = NULL;
1417
1418 /* fetch IPv6 data if required */
1419 if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4))
1420 {
1421 item6 = si_host_byname(si, name, AF_INET6, interface, (uint32_t *)err);
1422 }
1423
1424 /* fetch IPv4 data if required */
1425 if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL)))
1426 {
1427 item4 = si_host_byname(si, name, AF_INET, interface, (uint32_t *)err);
1428 }
1429
1430 if (want == WANT_A4_ONLY)
1431 {
1432 si_item_release(item6);
1433 if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1434 return item4;
1435 }
1436
1437 if (want == WANT_A6_ONLY)
1438 {
1439 si_item_release(item4);
1440 if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1441 return item6;
1442 }
1443
1444 if ((item6 == NULL) && (item4 == NULL))
1445 {
1446 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1447 return NULL;
1448 }
1449
1450 /* output item will have IPv6 + mapped IPv4 addresses */
1451
1452 out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t));
1453 if (out == NULL)
1454 {
1455 si_item_release(item4);
1456 si_item_release(item6);
1457 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1458 return NULL;
1459 }
1460
1461 if (item4 != NULL)
1462 {
1463 h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t));
1464
1465 out->host.h_name = lower_case(h->h_name);
1466
1467 if (h->h_aliases != NULL)
1468 {
1469 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1470 }
1471
1472 for (i = 0; h->h_addr_list[i] != 0; i++)
1473 {
1474 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1475 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1476 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1477 memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN);
1478 append_addr((const char *)&addr6, IPV6_ADDR_LEN, out);
1479 }
1480 }
1481
1482 if (item6 != NULL)
1483 {
1484 h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t));
1485
1486 if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name);
1487
1488 if (h->h_aliases != NULL)
1489 {
1490 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1491 }
1492
1493 for (i = 0; h->h_addr_list[i] != 0; i++) append_addr(h->h_addr_list[i], IPV6_ADDR_LEN, out);
1494 }
1495
1496 si_item_release(item4);
1497 si_item_release(item6);
1498
1499 unused = 0;
1500
1501 item6 = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, unused, unused, out->host.h_name, out->host.h_aliases, AF_INET6, IPV6_ADDR_LEN, out->host.h_addr_list);
1502
1503 free_build_hostent(out);
1504
1505 return item6;
1506 }