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