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