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