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