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