Libinfo-324.tar.gz
[apple/libinfo.git] / lookup.subproj / si_getaddrinfo.c
1 /*
2 * Copyright (c) 2008-2009 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 <arpa/inet.h>
33 #include <ifaddrs.h>
34 #include <net/if.h>
35 #include <string.h>
36 #include <sys/param.h>
37 #include <TargetConditionals.h>
38 #include "netdb_async.h"
39 #include "si_module.h"
40
41 #define SOCK_UNSPEC 0
42 #define IPPROTO_UNSPEC 0
43
44 #define IPV6_ADDR_LEN 16
45 #define IPV4_ADDR_LEN 4
46
47 #define WANT_NOTHING 0
48 #define WANT_A4_ONLY 1
49 #define WANT_A6_ONLY 2
50 #define WANT_A6_PLUS_MAPPED_A4 3
51 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
52
53 typedef struct {
54 struct hostent host;
55 int alias_count;
56 int addr_count;
57 uint64_t ttl;
58 } build_hostent_t;
59
60 void
61 freeaddrinfo(struct addrinfo *a)
62 {
63 struct addrinfo *next;
64
65 while (a != NULL)
66 {
67 next = a->ai_next;
68 if (a->ai_addr != NULL) free(a->ai_addr);
69 if (a->ai_canonname != NULL) free(a->ai_canonname);
70 free(a);
71 a = next;
72 }
73 }
74
75 const char *
76 gai_strerror(int32_t err)
77 {
78 switch (err)
79 {
80 case EAI_ADDRFAMILY: return "Address family for nodename not supported";
81 case EAI_AGAIN: return "Temporary failure in name resolution";
82 case EAI_BADFLAGS: return "Invalid value for ai_flags";
83 case EAI_FAIL: return "Non-recoverable failure in name resolution";
84 case EAI_FAMILY: return "ai_family not supported";
85 case EAI_MEMORY: return "Memory allocation failure";
86 case EAI_NODATA: return "No address associated with nodename";
87 case EAI_NONAME: return "nodename nor servname provided, or not known";
88 case EAI_SERVICE: return "servname not supported for ai_socktype";
89 case EAI_SOCKTYPE: return "ai_socktype not supported";
90 case EAI_SYSTEM: return "System error";
91 case EAI_BADHINTS: return "Bad hints";
92 case EAI_PROTOCOL: return "ai_protocol not supported";
93 case EAI_OVERFLOW: return "argument buffer overflow";
94 }
95
96 return "Unknown error";
97 }
98
99 /*
100 * getnameinfo
101 *
102 * We handle some "trival" cases locally. If the caller passes
103 * NI_NUMERICHOST (only), then this call turns into a getservbyport
104 * to get the service name + inet_pton() to create a host string.
105 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
106 * number, complete the getnameinfo, and use printf() to create a service
107 * string. If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
108 * we inet_ntop() and printf() and return the results.
109 */
110 __private_extern__ si_item_t *
111 si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, uint32_t *err)
112 {
113 si_item_t *out = NULL;
114 const struct sockaddr *lookup_sa;
115 struct sockaddr_in s4;
116 struct in_addr a4;
117 struct in6_addr a6;
118 const uint64_t unused = 0;
119 void *addr = NULL;
120 char *host = NULL;
121 char *serv = NULL;
122 uint32_t ifnum = 0;
123 uint16_t port = 0;
124
125 int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
126 int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);
127
128 /* check input */
129 if ((si == NULL) || (sa == NULL))
130 {
131 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
132 return NULL;
133 }
134
135 if (err != NULL) *err = SI_STATUS_NO_ERROR;
136
137 lookup_sa = sa;
138
139 if (sa->sa_family == AF_INET)
140 {
141 struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
142 memcpy(&a4, &s4->sin_addr, sizeof(a4));
143 port = s4->sin_port;
144 addr = &a4;
145 }
146 else if (sa->sa_family == AF_INET6)
147 {
148 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
149 memcpy(&a6, &s6->sin6_addr, sizeof(a6));
150 port = s6->sin6_port;
151
152 /* Look for link-local IPv6 scope id */
153 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
154 {
155 ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
156 if (ifnum == 0)
157 {
158 ifnum = s6->sin6_scope_id;
159 a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
160 }
161
162 if (ifnum != s6->sin6_scope_id)
163 {
164 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
165 return NULL;
166 }
167 }
168
169 /* v4 mapped and compat addresses are converted to plain v4 */
170 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
171 {
172 memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
173 addr = &a4;
174 memset(&s4, 0, sizeof(s4));
175 s4.sin_len = sizeof(s4);
176 s4.sin_family = AF_INET;
177 s4.sin_port = port;
178 memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
179 lookup_sa = (const struct sockaddr *)&s4;
180 }
181 else
182 {
183 addr = &a6;
184 }
185 }
186 else
187 {
188 if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
189 return NULL;
190 }
191
192 if (do_host_lookup == 1)
193 {
194 #if 0
195 if ((do_serv_lookup == 1) && (si->sim_nameinfo != NULL))
196 {
197 return si->sim_nameinfo(si, lookup_sa, flags, err);
198 }
199 #endif
200 si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, NULL);
201 if (item != NULL)
202 {
203 struct hostent *h;
204 h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
205 host = strdup(h->h_name);
206 si_item_release(item);
207 if (host == NULL)
208 {
209 if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
210 return NULL;
211 }
212 }
213 }
214
215 if ((do_serv_lookup == 1) && (port != 0))
216 {
217 si_item_t *item = si_service_byport(si, port, NULL);
218 if (item != NULL)
219 {
220 struct servent *s;
221 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
222 serv = strdup(s->s_name);
223 si_item_release(item);
224 if (serv == NULL)
225 {
226 free(host);
227 if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
228 return NULL;
229 }
230 }
231 }
232
233 /*
234 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
235 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
236 */
237 if (host == NULL && (flags & NI_NAMEREQD) == 0)
238 {
239 char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
240 tmp[0] = '\0';
241 if (sa->sa_family == AF_INET)
242 {
243 char buf[INET_ADDRSTRLEN];
244 if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
245 {
246 host = strdup(buf);
247 }
248 }
249 else if (sa->sa_family == AF_INET6)
250 {
251 char buf[INET6_ADDRSTRLEN];
252
253 /* zero the embedded scope ID */
254 if (ifnum != 0)
255 {
256 a6.__u6_addr.__u6_addr16[1] = 0;
257 }
258
259 if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
260 {
261 if (ifnum != 0)
262 {
263 char ifname[IF_NAMESIZE];
264 if (if_indextoname(ifnum, ifname) != NULL)
265 {
266 asprintf(&host, "%s%%%s", buf, ifname);
267 }
268 else
269 {
270 /* ENXIO */
271 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
272 return NULL;
273 }
274 }
275 else
276 {
277 host = strdup(buf);
278 }
279 }
280 }
281 }
282
283 /* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
284 if (serv == NULL)
285 {
286 asprintf(&serv, "%hu", ntohs(port));
287 }
288
289 if ((host == NULL) || (serv == NULL))
290 {
291 if (err != NULL)
292 {
293 if ((flags & NI_NAMEREQD) != 0)
294 {
295 *err = SI_STATUS_EAI_NONAME;
296 }
297 else
298 {
299 *err = SI_STATUS_EAI_MEMORY;
300 }
301 }
302 }
303 else
304 {
305 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
306 }
307
308 free(host);
309 free(serv);
310 return out;
311 }
312
313 static int
314 _gai_numericserv(const char *serv, uint16_t *port)
315 {
316 int numeric;
317 char *endptr;
318 long num;
319
320 numeric = 0;
321
322 if (serv == NULL)
323 {
324 if (port) *port = 0;
325 numeric = 1;
326 }
327 else
328 {
329 num = strtol(serv, &endptr, 10);
330 if ((serv[0] != '\0') && (*endptr == '\0') && (num >= 0) && (num <= UINT16_MAX))
331 {
332 numeric = 1;
333 if (port != NULL) *port = (uint16_t)num;
334 }
335 }
336
337 return numeric;
338 }
339
340 __private_extern__ int
341 _gai_serv_to_port(const char *serv, uint32_t proto, uint16_t *port)
342 {
343 si_item_t *item;
344 struct servent *s;
345 const char *protoname = NULL;
346
347 if (_gai_numericserv(serv, port)) return 0;
348
349 if (proto == IPPROTO_UDP) protoname = "udp";
350 if (proto == IPPROTO_TCP) protoname = "tcp";
351
352 item = si_service_byname(si_search(), serv, protoname);
353 if (item == NULL) return -1;
354
355 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
356 if (port) *port = ntohs(s->s_port);
357 si_item_release(item);
358
359 return 0;
360 }
361
362 __private_extern__ si_item_t *
363 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)
364 {
365 socket_data_t sockdata;
366 struct sockaddr_in *sa;
367 int32_t len, v32;
368 uint64_t unused;
369
370 unused = 0;
371 len = sizeof(struct sockaddr_in);
372 memset(&sockdata, 0, sizeof(socket_data_t));
373 sa = (struct sockaddr_in *)&sockdata;
374
375 sa->sin_len = len;
376 sa->sin_family = AF_INET;
377 sa->sin_port = htons(port);
378 memcpy(&sa->sin_addr, addr, sizeof(sa->sin_addr));
379
380 /* Kludge: Jam the interface number into sin_zero (4 bytes). */
381 v32 = iface;
382 memmove(sa->sin_zero, &v32, sizeof(uint32_t));
383
384 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET, sock, proto, len, sockdata, cname);
385 }
386
387 __private_extern__ si_item_t *
388 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)
389 {
390 socket_data_t sockdata;
391 struct sockaddr_in6 *sa;
392 int32_t len;
393 uint64_t unused;
394
395 unused = 0;
396 len = sizeof(struct sockaddr_in6);
397 memset(&sockdata, 0, sizeof(socket_data_t));
398 sa = (struct sockaddr_in6 *)&sockdata;
399
400 sa->sin6_len = len;
401 sa->sin6_family = AF_INET6;
402 sa->sin6_port = htons(port);
403 memcpy(&sa->sin6_addr, addr, sizeof(sa->sin6_addr));
404
405 /* sin6_scope_id is in host byte order */
406 sa->sin6_scope_id = iface;
407
408 if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
409 {
410 /* check for embedded scopeid */
411 uint16_t esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]);
412 if (esid != 0)
413 {
414 sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
415 if (iface == 0) sa->sin6_scope_id = esid;
416 }
417 }
418
419 return (si_item_t *)LI_ils_create("L448844444Ss", (unsigned long)si, CATEGORY_ADDRINFO, 1, unused, unused, flags, AF_INET6, sock, proto, len, sockdata, cname);
420 }
421
422 __private_extern__ si_list_t *
423 si_addrinfo_list(si_mod_t *si, int socktype, int proto, struct in_addr *a4, struct in6_addr *a6, int port, int scopeid, const char *cname4, const char *cname6)
424 {
425 si_item_t *item = NULL;
426 si_list_t *out4 = NULL, *out6 = NULL;
427 if (a4 != NULL)
428 {
429 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
430 {
431 item = si_addrinfo_v4(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, cname4);
432 out4 = si_list_add(out4, item);
433 si_item_release(item);
434 }
435
436 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
437 {
438 item = si_addrinfo_v4(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, cname4);
439 out4 = si_list_add(out4, item);
440 si_item_release(item);
441 }
442
443 if (proto == IPPROTO_ICMP)
444 {
445 item = si_addrinfo_v4(si, 0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, cname4);
446 out4 = si_list_add(out4, item);
447 si_item_release(item);
448 }
449 }
450
451 if (a6 != NULL)
452 {
453 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
454 {
455 item = si_addrinfo_v6(si, 0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, cname6);
456 out6 = si_list_add(out6, item);
457 si_item_release(item);
458 }
459
460 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
461 {
462 item = si_addrinfo_v6(si, 0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, cname6);
463 out6 = si_list_add(out6, item);
464 si_item_release(item);
465 }
466
467 if (proto == IPPROTO_ICMPV6)
468 {
469 item = si_addrinfo_v6(si, 0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, cname6);
470 out6 = si_list_add(out6, item);
471 si_item_release(item);
472 }
473 }
474
475 out6 = si_list_concat(out6, out4);
476 si_list_release(out4);
477
478 return out6;
479 }
480
481 /*
482 * _gai_numerichost
483 * Determines whether the given host name is a numeric IPv4 or IPv6 address,
484 * based on the address family input value. If the input addres family is
485 * unspecified, a more specific value will be provided on output if possible.
486 * Returns 1 if host name is numeric or 0 if not, or -1 on error.
487 */
488 static int
489 _gai_numerichost(const char* nodename, uint32_t *family, int flags, struct in_addr *a4, struct in6_addr *a6)
490 {
491 int numerichost, passive;
492
493 numerichost = 0;
494
495 if (nodename == NULL)
496 {
497 /* return loopback or passive addresses */
498 passive = (flags & AI_PASSIVE);
499
500 if ((*family == AF_UNSPEC) || (*family == AF_INET))
501 {
502 if (passive) a4->s_addr = 0;
503 else a4->s_addr = htonl(INADDR_LOOPBACK);
504 }
505
506 if ((*family == AF_UNSPEC) || (*family == AF_INET6))
507 {
508 memset(a6, 0, sizeof(*a6));
509 if (!passive) a6->__u6_addr.__u6_addr32[3] = htonl(1);
510 }
511
512 numerichost = 1;
513 }
514 else
515 {
516 /* numeric IPv4 host valid for AF_UNSPEC and AF_INET */
517 numerichost = inet_pton(AF_INET, nodename, a4);
518 if (numerichost == 1)
519 {
520 if (*family == AF_UNSPEC) *family = AF_INET;
521 else if (*family == AF_INET6) numerichost = -1;
522 return numerichost;
523 }
524
525 /* numeric IPv6 host valid for AF_UNSPEC and AF_INET6 */
526 numerichost = inet_pton(AF_INET6, nodename, a6);
527 if (numerichost == 1)
528 {
529 if (*family == AF_UNSPEC) *family = AF_INET6;
530 else if (*family == AF_INET) numerichost = -1;
531 return numerichost;
532 }
533 }
534
535 return numerichost;
536 }
537
538 /* si_addrinfo_list_from_hostent
539 * Returns an addrinfo list from IPv4 and IPv6 hostent entries
540 */
541 __private_extern__ si_list_t *
542 si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t socktype, uint32_t proto, uint16_t port, uint16_t scope, const struct hostent *h4, const struct hostent *h6)
543 {
544 int i;
545 si_list_t *out = NULL;
546 si_list_t *list;
547
548 if ((h6 != NULL) && (h6->h_addr_list != NULL))
549 {
550 for (i = 0; h6->h_addr_list[i] != NULL; i++)
551 {
552 struct in6_addr a6;
553 memcpy(&a6, h6->h_addr_list[i], h6->h_length);
554 list = si_addrinfo_list(si, socktype, proto, NULL, &a6, port, scope, NULL, h6->h_name);
555 out = si_list_concat(out, list);
556 si_list_release(list);
557 }
558 }
559
560 if ((h4 != NULL) && (h4->h_addr_list != NULL))
561 {
562 for (i = 0; h4->h_addr_list[i] != NULL; i++)
563 {
564 struct in_addr a4;
565 memcpy(&a4, h4->h_addr_list[i], h4->h_length);
566 list = si_addrinfo_list(si, socktype, proto, &a4, NULL, port, 0, h4->h_name, NULL);
567 out = si_list_concat(out, list);
568 si_list_release(list);
569 }
570 }
571
572 return out;
573 }
574
575 /* _gai_simple
576 * Simple lookup via gethostbyname2(3) mechanism.
577 */
578 static si_list_t *
579 _gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, uint32_t *err)
580 {
581 si_item_t *h4_item = NULL, *h6_item = NULL;
582 struct hostent *h4 = NULL, *h6 = NULL;
583 si_list_t *out = NULL;
584 uint16_t port;
585
586 if ((flags & AI_NUMERICSERV) != 0)
587 {
588 port = *(uint16_t*)servptr;
589 }
590 else
591 {
592 if (_gai_serv_to_port(servptr, proto, &port) != 0)
593 {
594 if (err) *err = SI_STATUS_EAI_NONAME;
595 return NULL;
596 }
597 }
598
599 if ((flags & AI_NUMERICHOST) != 0)
600 {
601 if (family == AF_INET)
602 {
603 h4_item = si_host_byaddr(si, nodeptr, AF_INET, NULL);
604 }
605 else if (family == AF_INET6)
606 {
607 h6_item = si_host_byaddr(si, nodeptr, AF_INET6, NULL);
608 }
609 }
610 else
611 {
612 if ((family == AF_INET) || (family == AF_UNSPEC))
613 {
614 h4_item = si_host_byname(si, nodeptr, AF_INET, NULL);
615 }
616 #if !TARGET_OS_EMBEDDED
617 if ((family == AF_INET6) || (family == AF_UNSPEC))
618 {
619 h6_item = si_host_byname(si, nodeptr, AF_INET6, NULL);
620 }
621 #endif /* !TARGET_OS_EMBEDDED */
622 }
623
624 if (h4_item != NULL)
625 {
626 h4 = (struct hostent *)((uintptr_t)h4_item + sizeof(si_item_t));
627 }
628
629 if (h6_item != NULL)
630 {
631 h6 = (struct hostent *)((uintptr_t)h6_item + sizeof(si_item_t));
632 }
633
634 out = si_addrinfo_list_from_hostent(si, socktype, proto, port, 0, h4, h6);
635 si_item_release(h4_item);
636 si_item_release(h6_item);
637
638 return out;
639 }
640
641 __private_extern__ si_list_t *
642 si_srv_byname(si_mod_t *si, const char *qname, uint32_t *err)
643 {
644 if (si == NULL) return 0;
645 if (si->sim_srv_byname == NULL) return 0;
646
647 return si->sim_srv_byname(si, qname, err);
648 }
649
650 __private_extern__ int
651 si_wants_addrinfo(si_mod_t *si)
652 {
653 if (si == NULL) return 0;
654 if (si->sim_addrinfo == NULL) return 0;
655 if (si->sim_wants_addrinfo == NULL) return 0;
656
657 return si->sim_wants_addrinfo(si);
658 }
659
660 __private_extern__ si_list_t *
661 si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, uint32_t *err)
662 {
663 int i, lastprio, numerichost, numericserv = 0;
664 const void *nodeptr = NULL, *servptr = NULL;
665 uint16_t port;
666 struct in_addr a4, *p4;
667 struct in6_addr a6, *p6;
668 char srvnode[MAXHOSTNAMELEN];
669 const char *cname;
670 si_srv_t *srv;
671 si_item_t *item;
672 si_list_t *list;
673 char *qname;
674
675 if (err != NULL) *err = SI_STATUS_NO_ERROR;
676
677 if (si == NULL)
678 {
679 if (err != NULL) *err = SI_STATUS_EAI_FAIL;
680 return NULL;
681 }
682
683 /* treat empty strings as NULL */
684 if ((node != NULL) && (node[0] == '\0')) node = NULL;
685 if ((serv != NULL) && (serv[0] == '\0')) serv = NULL;
686
687 /* make sure we have a query */
688 if ((node == NULL) && (serv == NULL))
689 {
690 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
691 return NULL;
692 }
693
694 /* verify family is supported */
695 switch (family)
696 {
697 case AF_UNSPEC:
698 #if TARGET_OS_EMBEDDED
699 family = AF_INET;
700 #endif
701 case AF_INET:
702 case AF_INET6:
703 break;
704 default:
705 if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
706 return NULL;
707 }
708
709 /* verify socket type is supported */
710 switch (socktype)
711 {
712 case SOCK_UNSPEC:
713 case SOCK_RAW:
714 case SOCK_DGRAM:
715 case SOCK_STREAM:
716 break;
717 default:
718 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
719 return NULL;
720 }
721
722 /* verify protocol is supported */
723 switch (proto)
724 {
725 case IPPROTO_UNSPEC:
726 case IPPROTO_UDP:
727 case IPPROTO_TCP:
728 case IPPROTO_ICMP:
729 case IPPROTO_ICMPV6:
730 break;
731 default:
732 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
733 return NULL;
734 }
735
736 /* verify socket type compatible with protocol */
737 if (((socktype == SOCK_DGRAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_UDP)) || ((socktype == SOCK_STREAM) && (proto != IPPROTO_UNSPEC) && (proto != IPPROTO_TCP)))
738 {
739 if (err != NULL) *err = SI_STATUS_EAI_BADHINTS;
740 return NULL;
741 }
742
743 memset(&a4, 0, sizeof(struct in_addr));
744 memset(&a6, 0, sizeof(struct in6_addr));
745
746 /* determine the protocol if possible */
747 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_DGRAM)) proto = IPPROTO_UDP;
748 if ((proto == IPPROTO_UNSPEC) && (socktype == SOCK_STREAM)) proto = IPPROTO_TCP;
749
750 port = 0;
751
752 if ((flags & AI_SRV) != 0)
753 {
754 /* AI_SRV SPI */
755 lastprio = INT_MAX;
756
757 /* set so that getaddrinfo(3) fails if the SRV fails */
758 flags |= AI_NUMERICSERV;
759
760 /* XXX what if serv is NULL */
761 asprintf(&qname, "%s.%s", serv, node);
762 list = si_srv_byname(si, qname, err);
763 free(qname);
764
765 if (list != NULL)
766 {
767 for (i = 0; i < list->count; ++i)
768 {
769 item = list->entry[i];
770 srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
771
772 if (srv->priority < lastprio)
773 {
774 port = srv->port;
775 numericserv = 1;
776 strlcpy(srvnode, srv->target, sizeof(srvnode));
777 node = srvnode;
778 }
779 }
780
781 si_list_release(list);
782 }
783 }
784 else
785 {
786 /* Usual service lookup */
787 numericserv = _gai_numericserv(serv, &port);
788 }
789
790 if ((flags & AI_NUMERICSERV) && (numericserv == 0))
791 {
792 /* FreeBSD returns SI_STATUS_EAI_SERVICE */
793 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
794 return NULL;
795 }
796
797 if (serv != NULL)
798 {
799 if (numericserv == 1)
800 {
801 flags |= AI_NUMERICSERV;
802 servptr = &port;
803 }
804 else
805 {
806 servptr = serv;
807 }
808 }
809
810 numerichost = _gai_numerichost(node, &family, flags, &a4, &a6);
811 if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0)))
812 {
813 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
814 return NULL;
815 }
816
817 if (numerichost == 1)
818 {
819 flags |= AI_NUMERICHOST;
820 if (family == AF_INET)
821 {
822 nodeptr = &a4;
823 }
824 else if (family == AF_INET6)
825 {
826 nodeptr = &a6;
827 }
828 }
829 else
830 {
831 nodeptr = node;
832 }
833
834 if ((numerichost == 1) && (numericserv == 0))
835 {
836 /* only service lookup needed. convert to port and perform a trivial getaddrinfo */
837 if (_gai_serv_to_port(serv, proto, &port) != 0)
838 {
839 if (err != NULL) *err = SI_STATUS_EAI_NONAME;
840 return NULL;
841 }
842 else
843 {
844 flags |= AI_NUMERICSERV;
845 servptr = &port;
846 numericserv = 1;
847 }
848 }
849
850 if ((numerichost == 1) && (numericserv == 1))
851 {
852 p4 = &a4;
853 p6 = &a6;
854 cname = NULL;
855
856 if (family == AF_INET) p6 = NULL;
857 if (family == AF_INET6) p4 = NULL;
858 if (node == NULL) cname = "localhost";
859
860 /* handle trivial questions */
861 return si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname);
862 }
863 else if ((si->sim_wants_addrinfo != NULL) && si->sim_wants_addrinfo(si))
864 {
865 /* or let the current module handle the host lookups intelligently */
866 return si->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, err);
867 }
868
869 /* fall back to a default path */
870 return _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, err);
871 }
872
873 static struct addrinfo *
874 si_item_to_addrinfo(si_item_t *item)
875 {
876 si_addrinfo_t *a;
877 struct addrinfo *out;
878
879 if (item == NULL) return NULL;
880
881 a = (si_addrinfo_t *)((uintptr_t)item + sizeof(si_item_t));
882
883 out = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
884 if (out == NULL) return NULL;
885
886 out->ai_flags = a->ai_flags;
887 out->ai_family = a->ai_family;
888 out->ai_socktype = a->ai_socktype;
889 out->ai_protocol = a->ai_protocol;
890 out->ai_addrlen = a->ai_addrlen;
891
892 out->ai_addr = (struct sockaddr *)calloc(1, out->ai_addrlen);
893 if (out->ai_addr == NULL)
894 {
895 free(out);
896 return NULL;
897 }
898
899 memcpy(out->ai_addr, a->ai_addr.x, out->ai_addrlen);
900
901 if (a->ai_canonname != NULL)
902 {
903 out->ai_canonname = strdup(a->ai_canonname);
904 if (out->ai_canonname == NULL)
905 {
906 free(out);
907 return NULL;
908 }
909 }
910
911 return out;
912 }
913
914 __private_extern__ struct addrinfo *
915 si_list_to_addrinfo(si_list_t *list)
916 {
917 struct addrinfo *tail, *out;
918 int i;
919
920 if (list == NULL) return NULL;
921 if (list->count == 0) return NULL;
922
923 i = list->count - 1;
924
925 out = si_item_to_addrinfo(list->entry[i]);
926 tail = out;
927
928 for (i--; i >= 0; i--)
929 {
930 out = si_item_to_addrinfo(list->entry[i]);
931 if (out == NULL)
932 {
933 freeaddrinfo(tail);
934 return NULL;
935 }
936
937 out->ai_next = tail;
938 tail = out;
939 }
940
941 return out;
942 }
943
944 /* getipnodebyname */
945
946 static si_item_t *
947 make_hostent(si_mod_t *si, const char *name, struct in_addr addr)
948 {
949 char *addrs[2];
950 char *aliases[1];
951 uint64_t unused;
952
953 if (name == NULL) return NULL;
954
955 unused = 0;
956
957 addrs[0] = (char *)&(addr.s_addr);
958 addrs[1] = NULL;
959 aliases[0] = NULL;
960
961 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);
962 }
963
964 static si_item_t *
965 make_hostent6(si_mod_t *si, const char *name, struct in6_addr addr)
966 {
967 char *addrs[2];
968 char *aliases[1];
969 uint64_t unused;
970
971 if (name == NULL) return NULL;
972
973 unused = 0;
974
975 addrs[0] = (char *)&(addr.__u6_addr.__u6_addr32[0]);
976 addrs[1] = NULL;
977 aliases[0] = NULL;
978
979 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);
980 }
981
982 static char *
983 lower_case(const char *s)
984 {
985 int i;
986 char *t;
987
988 if (s == NULL) return NULL;
989
990 t = malloc(strlen(s) + 1);
991
992 for (i = 0; s[i] != '\0'; i++)
993 {
994 if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32;
995 else t[i] = s[i];
996 }
997
998 t[i] = '\0';
999
1000 return t;
1001 }
1002
1003 static int
1004 merge_alias(const char *name, build_hostent_t *h)
1005 {
1006 int i;
1007
1008 if (name == NULL) return 0;
1009 if (h == NULL) return 0;
1010
1011 if ((h->host.h_name != NULL) && (string_equal(name, h->host.h_name))) return 0;
1012
1013 for (i = 0; i < h->alias_count; i++)
1014 {
1015 if (string_equal(name, h->host.h_aliases[i])) return 0;
1016 }
1017
1018 if (h->alias_count == 0) h->host.h_aliases = (char **)calloc(2, sizeof(char *));
1019 else h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count + 2) * sizeof(char *));
1020
1021 if (h->host.h_aliases == NULL)
1022 {
1023 h->alias_count = 0;
1024 return -1;
1025 }
1026
1027 h->host.h_aliases[h->alias_count] = lower_case(name);
1028 h->alias_count++;
1029 h->host.h_aliases[h->alias_count] = NULL;
1030
1031 return 0;
1032 }
1033
1034 static int
1035 append_addr(const char *addr, uint32_t len, build_hostent_t *h)
1036 {
1037 if (addr == NULL) return 0;
1038 if (h == NULL) return 0;
1039
1040 if (h->addr_count == 0) h->host.h_addr_list = (char **)calloc(2, sizeof(char *));
1041 else h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count + 2) * sizeof(char *));
1042
1043 if (h->host.h_addr_list == NULL)
1044 {
1045 h->addr_count = 0;
1046 return -1;
1047 }
1048
1049 h->host.h_addr_list[h->addr_count] = malloc(len);
1050 if (h->host.h_addr_list[h->addr_count] == NULL) return -1;
1051
1052 memcpy(h->host.h_addr_list[h->addr_count], addr, len);
1053 h->addr_count++;
1054 h->host.h_addr_list[h->addr_count] = NULL;
1055
1056 return 0;
1057 }
1058
1059 static void
1060 free_build_hostent(build_hostent_t *h)
1061 {
1062 uint32_t i;
1063 char **aliases;
1064
1065 if (h == NULL) return;
1066
1067 if (h->host.h_name != NULL) free(h->host.h_name);
1068 h->host.h_name = NULL;
1069
1070 aliases = h->host.h_aliases;
1071 if (aliases != NULL)
1072 {
1073 while (*aliases != NULL) free(*aliases++);
1074 free(h->host.h_aliases);
1075 }
1076
1077 h->host.h_aliases = NULL;
1078
1079 if (h->host.h_addr_list != NULL)
1080 {
1081 for (i = 0; h->host.h_addr_list[i] != NULL; i++) free(h->host.h_addr_list[i]);
1082 free(h->host.h_addr_list);
1083 }
1084
1085 h->host.h_addr_list = NULL;
1086 free(h);
1087 }
1088
1089 __private_extern__ si_item_t *
1090 si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, uint32_t *err)
1091 {
1092 int i, status, want, if4, if6;
1093 struct ifaddrs *ifa, *ifap;
1094 struct in_addr addr4;
1095 struct in6_addr addr6;
1096 si_item_t *item4, *item6;
1097 build_hostent_t *out;
1098 struct hostent *h;
1099 uint64_t unused;
1100
1101 memset(&addr4, 0, sizeof(struct in_addr));
1102 memset(&addr6, 0, sizeof(struct in6_addr));
1103
1104 if (err != NULL) *err = 0;
1105
1106 if (family == AF_INET)
1107 {
1108 status = inet_aton(name, &addr4);
1109 if (status == 1)
1110 {
1111 /* create a host entry */
1112 item4 = make_hostent(si, name, addr4);
1113 if (item4 == NULL)
1114 {
1115 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1116 return NULL;
1117 }
1118
1119 return item4;
1120 }
1121 }
1122 else if (family == AF_INET6)
1123 {
1124 status = inet_pton(family, name, &addr6);
1125 if (status == 1)
1126 {
1127 /* create a host entry */
1128 item6 = make_hostent6(si, name, addr6);
1129 if (item6 == NULL)
1130 {
1131 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1132 return NULL;
1133 }
1134
1135 return item6;
1136 }
1137
1138 status = inet_aton(name, &addr4);
1139 if (status == 1)
1140 {
1141 if (!(flags & (AI_V4MAPPED | AI_V4MAPPED_CFG)))
1142 {
1143 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1144 return NULL;
1145 }
1146
1147 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1148 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1149 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1150 memmove(&(addr6.__u6_addr.__u6_addr32[3]), &(addr4.s_addr), IPV4_ADDR_LEN);
1151
1152 /* create a host entry */
1153 item6 = make_hostent6(si, name, addr6);
1154 if (item6 == NULL)
1155 {
1156 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1157 return NULL;
1158 }
1159
1160 return item6;
1161 }
1162 }
1163 else
1164 {
1165 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1166 return NULL;
1167 }
1168
1169 /*
1170 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
1171 */
1172
1173 if4 = 0;
1174 if6 = 0;
1175
1176 if (flags & AI_ADDRCONFIG)
1177 {
1178 if (getifaddrs(&ifa) < 0)
1179 {
1180 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1181 return NULL;
1182 }
1183
1184 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
1185 {
1186 if (ifap->ifa_addr == NULL) continue;
1187 if ((ifap->ifa_flags & IFF_UP) == 0) continue;
1188 if (ifap->ifa_addr->sa_family == AF_INET) if4++;
1189 else if (ifap->ifa_addr->sa_family == AF_INET6) if6++;
1190 }
1191
1192 freeifaddrs(ifa);
1193
1194 /* Bail out if there are no interfaces */
1195 if ((if4 == 0) && (if6 == 0))
1196 {
1197 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1198 return NULL;
1199 }
1200 }
1201
1202 /*
1203 * Figure out what we want.
1204 * If user asked for AF_INET, we only want V4 addresses.
1205 */
1206 want = WANT_A4_ONLY;
1207
1208 if (family == AF_INET)
1209 {
1210 if ((flags & AI_ADDRCONFIG) && (if4 == 0))
1211 {
1212 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1213 return NULL;
1214 }
1215 }
1216 else if (family == AF_INET6)
1217 {
1218 /* family == AF_INET6 */
1219 want = WANT_A6_ONLY;
1220
1221 if (flags & (AI_V4MAPPED | AI_V4MAPPED_CFG))
1222 {
1223 if (flags & AI_ALL)
1224 {
1225 want = WANT_A6_PLUS_MAPPED_A4;
1226 }
1227 else
1228 {
1229 want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
1230 }
1231 }
1232 else
1233 {
1234 if ((flags & AI_ADDRCONFIG) && (if6 == 0))
1235 {
1236 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1237 return NULL;
1238 }
1239 }
1240 }
1241 else
1242 {
1243 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1244 return NULL;
1245 }
1246
1247 item6 = NULL;
1248 item4 = NULL;
1249
1250 /* fetch IPv6 data if required */
1251 if ((want == WANT_A6_ONLY) || (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) || (want == WANT_A6_PLUS_MAPPED_A4))
1252 {
1253 item6 = si_host_byname(si, name, AF_INET6, (uint32_t *)err);
1254 }
1255
1256 /* fetch IPv4 data if required */
1257 if ((want == WANT_A4_ONLY) || (want == WANT_A6_PLUS_MAPPED_A4) || ((want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) && (item6 == NULL)))
1258 {
1259 item4 = si_host_byname(si, name, AF_INET, (uint32_t *)err);
1260 }
1261
1262 if (want == WANT_A4_ONLY)
1263 {
1264 si_item_release(item6);
1265 if ((item4 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1266 return item4;
1267 }
1268
1269 if (want == WANT_A6_ONLY)
1270 {
1271 si_item_release(item4);
1272 if ((item6 == NULL) && (err != NULL)) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1273 return item6;
1274 }
1275
1276 if ((item6 == NULL) && (item4 == NULL))
1277 {
1278 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1279 return NULL;
1280 }
1281
1282 /* output item will have IPv6 + mapped IPv4 addresses */
1283
1284 out = (build_hostent_t *)calloc(1, sizeof(build_hostent_t));
1285 if (out == NULL)
1286 {
1287 si_item_release(item4);
1288 si_item_release(item6);
1289 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1290 return NULL;
1291 }
1292
1293 if (item4 != NULL)
1294 {
1295 h = (struct hostent *)((uintptr_t)item4 + sizeof(si_item_t));
1296
1297 out->host.h_name = lower_case(h->h_name);
1298
1299 if (h->h_aliases != NULL)
1300 {
1301 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1302 }
1303
1304 for (i = 0; h->h_addr_list[i] != 0; i++)
1305 {
1306 addr6.__u6_addr.__u6_addr32[0] = 0x00000000;
1307 addr6.__u6_addr.__u6_addr32[1] = 0x00000000;
1308 addr6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
1309 memmove(&(addr6.__u6_addr.__u6_addr32[3]), h->h_addr_list[i], IPV4_ADDR_LEN);
1310 append_addr((const char *)&addr6, IPV6_ADDR_LEN, out);
1311 }
1312 }
1313
1314 if (item6 != NULL)
1315 {
1316 h = (struct hostent *)((uintptr_t)item6 + sizeof(si_item_t));
1317
1318 if (out->host.h_name == NULL) out->host.h_name = lower_case(h->h_name);
1319
1320 if (h->h_aliases != NULL)
1321 {
1322 for (i = 0; h->h_aliases[i] != NULL; i++) merge_alias(h->h_aliases[i], out);
1323 }
1324
1325 for (i = 0; h->h_addr_list[i] != 0; i++) append_addr((const char *)&(h->h_addr_list[i]), IPV6_ADDR_LEN, out);
1326 }
1327
1328 si_item_release(item4);
1329 si_item_release(item6);
1330
1331 unused = 0;
1332
1333 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);
1334
1335 free_build_hostent(out);
1336
1337 return item6;
1338 }