Libinfo-222.4.12.tar.gz
[apple/libinfo.git] / lookup.subproj / getaddrinfo.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <netdb.h>
26 #include <sys/types.h>
27 #include <stdint.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30 #include <net/if.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <rpc/types.h>
39 #include <rpc/xdr.h>
40 #include <mach/mach.h>
41 #include <servers/bootstrap.h>
42 #include <ifaddrs.h>
43 #include "lu_utils.h"
44 #include "netdb_async.h"
45
46 #define SOCK_UNSPEC 0
47 #define IPPROTO_UNSPEC 0
48
49 #define LONG_STRING_LENGTH 8192
50 #define _LU_MAXLUSTRLEN 256
51 #define LU_QBUF_SIZE 8192
52
53 #define MAX_LOOKUP_ATTEMPTS 10
54
55 #define INET_NTOP_AF_INET_OFFSET 4
56 #define INET_NTOP_AF_INET6_OFFSET 8
57
58 extern mach_port_t _lookupd_port();
59
60 static int gai_proc = -1;
61 static int gni_proc = -1;
62
63 static const int32_t supported_family[] =
64 {
65 PF_UNSPEC,
66 PF_INET,
67 PF_INET6
68 };
69 static const int32_t supported_family_count = (sizeof(supported_family) / sizeof(supported_family[0]));
70
71 static const int32_t supported_socket[] =
72 {
73 SOCK_RAW,
74 SOCK_UNSPEC,
75 SOCK_DGRAM,
76 SOCK_STREAM
77 };
78 static const int32_t supported_socket_count = (sizeof(supported_socket) / sizeof(supported_socket[0]));
79
80 static const int32_t supported_protocol[] =
81 {
82 IPPROTO_UNSPEC,
83 IPPROTO_ICMP,
84 IPPROTO_ICMPV6,
85 IPPROTO_UDP,
86 IPPROTO_TCP
87 };
88 static const int32_t supported_protocol_count = (sizeof(supported_protocol) / sizeof(supported_protocol[0]));
89
90 static const int32_t supported_socket_protocol_pair[] =
91 {
92 SOCK_RAW, IPPROTO_UNSPEC,
93 SOCK_RAW, IPPROTO_UDP,
94 SOCK_RAW, IPPROTO_TCP,
95 SOCK_RAW, IPPROTO_ICMP,
96 SOCK_RAW, IPPROTO_ICMPV6,
97 SOCK_UNSPEC, IPPROTO_UNSPEC,
98 SOCK_UNSPEC, IPPROTO_UDP,
99 SOCK_UNSPEC, IPPROTO_TCP,
100 SOCK_UNSPEC, IPPROTO_ICMP,
101 SOCK_UNSPEC, IPPROTO_ICMPV6,
102 SOCK_DGRAM, IPPROTO_UNSPEC,
103 SOCK_DGRAM, IPPROTO_UDP,
104 SOCK_STREAM, IPPROTO_UNSPEC,
105 SOCK_STREAM, IPPROTO_TCP
106 };
107 static const int32_t supported_socket_protocol_pair_count = (sizeof(supported_socket_protocol_pair) / (sizeof(supported_socket_protocol_pair[0]) * 2));
108
109 static int
110 gai_family_type_check(int32_t f)
111 {
112 int32_t i;
113
114 for (i = 0; i < supported_family_count; i++)
115 {
116 if (f == supported_family[i]) return 0;
117 }
118
119 return 1;
120 }
121
122 static int
123 gai_socket_type_check(int32_t s)
124 {
125 int32_t i;
126
127 for (i = 0; i < supported_socket_count; i++)
128 {
129 if (s == supported_socket[i]) return 0;
130 }
131
132 return 1;
133 }
134
135 static int
136 gai_protocol_type_check(int32_t p)
137 {
138 int32_t i;
139
140 for (i = 0; i < supported_protocol_count; i++)
141 {
142 if (p == supported_protocol[i]) return 0;
143 }
144
145 return 1;
146 }
147
148 static int
149 gai_socket_protocol_type_check(int32_t s, int32_t p)
150 {
151 int32_t i, j, ss, sp;
152
153 for (i = 0, j = 0; i < supported_socket_protocol_pair_count; i++, j+=2)
154 {
155 ss = supported_socket_protocol_pair[j];
156 sp = supported_socket_protocol_pair[j+1];
157 if ((s == ss) && (p == sp)) return 0;
158 }
159
160 return 1;
161 }
162
163 const char *
164 gai_strerror(int32_t err)
165 {
166 switch (err)
167 {
168 case EAI_ADDRFAMILY: return "Address family for nodename not supported";
169 case EAI_AGAIN: return "Temporary failure in name resolution";
170 case EAI_BADFLAGS: return "Invalid value for ai_flags";
171 case EAI_FAIL: return "Non-recoverable failure in name resolution";
172 case EAI_FAMILY: return "ai_family not supported";
173 case EAI_MEMORY: return "Memory allocation failure";
174 case EAI_NODATA: return "No address associated with nodename";
175 case EAI_NONAME: return "nodename nor servname provided, or not known";
176 case EAI_SERVICE: return "servname not supported for ai_socktype";
177 case EAI_SOCKTYPE: return "ai_socktype not supported";
178 case EAI_SYSTEM: return "System error";
179 case EAI_BADHINTS: return "Bad hints";
180 case EAI_PROTOCOL: return "ai_protocol not supported";
181 }
182
183 return "Unknown error";
184 }
185
186 static void
187 append_addrinfo(struct addrinfo **l, struct addrinfo *a)
188 {
189 struct addrinfo *x;
190
191 if (l == NULL) return;
192 if (a == NULL) return;
193
194 if (*l == NULL)
195 {
196 *l = a;
197 return;
198 }
199
200 x = *l;
201
202 if (a->ai_family == PF_INET6)
203 {
204 if (x->ai_family == PF_INET)
205 {
206 *l = a;
207 a->ai_next = x;
208 return;
209 }
210
211 while ((x->ai_next != NULL) && (x->ai_next->ai_family != PF_INET)) x = x->ai_next;
212 a->ai_next = x->ai_next;
213 x->ai_next = a;
214 }
215 else
216 {
217 while (x->ai_next != NULL) x = x->ai_next;
218 a->ai_next = NULL;
219 x->ai_next = a;
220 }
221 }
222
223 static int
224 encode_kv(XDR *x, const char *k, const char *v)
225 {
226 int32_t n = 1;
227
228 if (!xdr_string(x, (char **)&k, _LU_MAXLUSTRLEN)) return 1;
229 if (!xdr_int(x, &n)) return 1;
230 if (!xdr_string(x, (char **)&v, _LU_MAXLUSTRLEN)) return 1;
231
232 return 0;
233 }
234
235 void
236 freeaddrinfo(struct addrinfo *a)
237 {
238 struct addrinfo *next;
239
240 while (a != NULL)
241 {
242 next = a->ai_next;
243 if (a->ai_addr != NULL) free(a->ai_addr);
244 if (a->ai_canonname != NULL) free(a->ai_canonname);
245 free(a);
246 a = next;
247 }
248 }
249
250 static struct addrinfo *
251 new_addrinfo_v4(int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr addr, uint32_t iface, char *cname)
252 {
253 struct addrinfo *a;
254 struct sockaddr_in *sa;
255 int32_t len;
256
257 a = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
258 if (a == NULL) return NULL;
259
260 a->ai_next = NULL;
261
262 a->ai_flags = flags;
263 a->ai_family = PF_INET;
264 a->ai_socktype = sock;
265 a->ai_protocol = proto;
266
267 a->ai_addrlen = sizeof(struct sockaddr_in);
268
269 sa = (struct sockaddr_in *)calloc(1, a->ai_addrlen);
270 if (sa == NULL)
271 {
272 free(a);
273 return NULL;
274 }
275
276 sa->sin_len = a->ai_addrlen;
277 sa->sin_family = PF_INET;
278 sa->sin_port = htons(port);
279 sa->sin_addr = addr;
280
281 /* Kludge: Jam the interface number into sin_zero. */
282 memmove(sa->sin_zero, &iface, sizeof(uint32_t));
283
284 a->ai_addr = (struct sockaddr *)sa;
285
286 if (cname != NULL)
287 {
288 len = strlen(cname) + 1;
289 a->ai_canonname = malloc(len);
290 memmove(a->ai_canonname, cname, len);
291 }
292
293 return a;
294 }
295
296 static struct addrinfo *
297 new_addrinfo_v6(int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr addr, uint32_t scopeid, char *cname)
298 {
299 struct addrinfo *a;
300 struct sockaddr_in6 *sa;
301 int32_t len;
302
303 a = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
304 if (a == NULL) return NULL;
305
306 a->ai_next = NULL;
307
308 a->ai_flags = flags;
309 a->ai_family = PF_INET6;
310 a->ai_socktype = sock;
311 a->ai_protocol = proto;
312
313 a->ai_addrlen = sizeof(struct sockaddr_in6);
314
315 sa = (struct sockaddr_in6 *)calloc(1, a->ai_addrlen);
316 if (sa == NULL)
317 {
318 free(a);
319 return NULL;
320 }
321
322 sa->sin6_len = a->ai_addrlen;
323 sa->sin6_family = PF_INET6;
324 sa->sin6_port = htons(port);
325 sa->sin6_addr = addr;
326 sa->sin6_scope_id = scopeid;
327 a->ai_addr = (struct sockaddr *)sa;
328
329 if (cname != NULL)
330 {
331 len = strlen(cname) + 1;
332 a->ai_canonname = malloc(len);
333 memmove(a->ai_canonname, cname, len);
334 }
335
336 return a;
337 }
338
339 /*
340 * getaddrinfo support in lookupd
341 * Input dict may contain the following
342 *
343 * name: nodename
344 * service: servname
345 * protocol: [IPPROTO_UNSPEC] | IPPROTO_UDP | IPPROTO_TCP
346 * socktype: [SOCK_UNSPEC] | SOCK_DGRAM | SOCK_STREAM
347 * family: [PF_UNSPEC] | PF_INET | PF_INET6
348 * canonname: [0] | 1
349 * passive: [0] | 1
350 * numerichost: [0] | 1
351 *
352 * Output dictionary may contain the following
353 * All values are encoded as strings.
354 *
355 * flags: unsigned long
356 * family: unsigned long
357 * socktype: unsigned long
358 * protocol: unsigned long
359 * port: unsigned long
360 * address: char *
361 * scopeid: unsigned long
362 * canonname: char *
363 *
364 */
365
366 static struct addrinfo *
367 gai_lookupd_process_dictionary(XDR *inxdr)
368 {
369 int32_t i, nkeys, nvals;
370 char *key, *val;
371 uint32_t flags, family, socktype, protocol, longport, scopeid;
372 uint16_t port;
373 char *addr, *canonname;
374 struct addrinfo *a;
375 struct in_addr a4;
376 struct in6_addr a6;
377
378 flags = 0;
379 family = PF_UNSPEC;
380 socktype = SOCK_UNSPEC;
381 protocol = IPPROTO_UNSPEC;
382 port = 0;
383 scopeid = 0;
384 addr = NULL;
385 canonname = NULL;
386
387 if (!xdr_int(inxdr, &nkeys)) return NULL;
388
389 for (i = 0; i < nkeys; i++)
390 {
391 key = NULL;
392 val = NULL;
393
394 if (!xdr_string(inxdr, &key, LONG_STRING_LENGTH)) return NULL;
395 if (!xdr_int(inxdr, &nvals))
396 {
397 free(key);
398 return NULL;
399 }
400
401 if (nvals != 1)
402 {
403 free(key);
404 return NULL;
405 }
406
407 if (!xdr_string(inxdr, &val, LONG_STRING_LENGTH))
408 {
409 free(key);
410 return NULL;
411 }
412
413 if (!strcmp(key, "flags"))
414 {
415 flags = atoi(val);
416 }
417 else if (!strcmp(key, "family"))
418 {
419 family = atoi(val);
420 }
421 else if (!strcmp(key, "socktype"))
422 {
423 socktype = atoi(val);
424 }
425 else if (!strcmp(key, "protocol"))
426 {
427 protocol = atoi(val);
428 }
429 else if (!strcmp(key, "port"))
430 {
431 longport = atoi(val);
432 port = longport;
433 }
434 else if (!strcmp(key, "scopeid"))
435 {
436 scopeid = atoi(val);
437 }
438 else if (!strcmp(key, "address")) addr = strdup(val);
439 else if (!strcmp(key, "canonname")) canonname = strdup(val);
440 free(key);
441 free(val);
442 }
443
444 if (family == PF_UNSPEC)
445 {
446 if (addr != NULL) free(addr);
447 if (canonname != NULL) free(canonname);
448 return NULL;
449 }
450
451 a = NULL;
452 if (family == PF_INET)
453 {
454 inet_aton(addr, &a4);
455 a = new_addrinfo_v4(flags, socktype, protocol, port, a4, scopeid, canonname);
456 }
457 else if (family == PF_INET6)
458 {
459 inet_pton(AF_INET6, addr, &a6);
460 a = new_addrinfo_v6(flags, socktype, protocol, port, a6, scopeid, canonname);
461 }
462
463 if (addr != NULL) free(addr);
464 if (canonname != NULL) free(canonname);
465
466 return a;
467 }
468
469 static int
470 gai_make_query(const char *nodename, const char *servname, const struct addrinfo *hints, char *buf, uint32_t *len)
471 {
472 int32_t numerichost, family, proto, socktype, canonname, passive, parallel;
473 uint32_t na;
474 XDR outxdr;
475 char str[64], *cname;
476
477 numerichost = 0;
478 family = PF_UNSPEC;
479 proto = IPPROTO_UNSPEC;
480 socktype = SOCK_UNSPEC;
481 canonname = 0;
482 passive = 0;
483 parallel = 0;
484 cname = NULL;
485
486 if (hints != NULL)
487 {
488 family = hints->ai_family;
489 if (hints->ai_flags & AI_NUMERICHOST) numerichost = 1;
490 if (hints->ai_flags & AI_CANONNAME) canonname = 1;
491 if (hints->ai_flags & AI_PASSIVE) passive = 1;
492 if (hints->ai_flags & AI_PARALLEL) parallel = 1;
493
494 proto = hints->ai_protocol;
495 if (hints->ai_socktype == SOCK_DGRAM)
496 {
497 socktype = SOCK_DGRAM;
498 proto = IPPROTO_UDP;
499 }
500 if (hints->ai_socktype == SOCK_STREAM)
501 {
502 socktype = SOCK_STREAM;
503 proto = IPPROTO_TCP;
504 }
505 }
506
507 xdrmem_create(&outxdr, buf, *len, XDR_ENCODE);
508
509 /* Attribute count */
510 na = 0;
511 if (nodename != NULL) na++;
512 if (servname != NULL) na++;
513 if (proto != IPPROTO_UNSPEC) na++;
514 if (socktype != SOCK_UNSPEC) na++;
515 if (family != PF_UNSPEC) na++;
516 if (canonname != 0) na++;
517 if (passive != 0) na++;
518 if (parallel != 0) na++;
519 if (numerichost != 0) na++;
520
521 if (!xdr_int(&outxdr, (int32_t *)&na))
522 {
523 xdr_destroy(&outxdr);
524 errno = EIO;
525 return EAI_SYSTEM;
526 }
527
528 if (nodename != NULL)
529 {
530 if (encode_kv(&outxdr, "name", nodename) != 0)
531 {
532 xdr_destroy(&outxdr);
533 errno = EIO;
534 return EAI_SYSTEM;
535 }
536 }
537
538 if (servname != NULL)
539 {
540 if (encode_kv(&outxdr, "service", servname) != 0)
541 {
542 xdr_destroy(&outxdr);
543 errno = EIO;
544 return EAI_SYSTEM;
545 }
546 }
547
548 if (proto != IPPROTO_UNSPEC)
549 {
550 snprintf(str, 64, "%u", proto);
551 if (encode_kv(&outxdr, "protocol", str) != 0)
552 {
553 xdr_destroy(&outxdr);
554 errno = EIO;
555 return EAI_SYSTEM;
556 }
557 }
558
559 if (socktype != SOCK_UNSPEC)
560 {
561 snprintf(str, 64, "%u", socktype);
562 if (encode_kv(&outxdr, "socktype", str) != 0)
563 {
564 xdr_destroy(&outxdr);
565 errno = EIO;
566 return EAI_SYSTEM;
567 }
568 }
569
570 if (family != PF_UNSPEC)
571 {
572 snprintf(str, 64, "%u", family);
573 if (encode_kv(&outxdr, "family", str) != 0)
574 {
575 xdr_destroy(&outxdr);
576 errno = EIO;
577 return EAI_SYSTEM;
578 }
579 }
580
581 if (canonname != 0)
582 {
583 if (encode_kv(&outxdr, "canonname", "1") != 0)
584 {
585 xdr_destroy(&outxdr);
586 errno = EIO;
587 return EAI_SYSTEM;
588 }
589 }
590
591 if (passive != 0)
592 {
593 if (encode_kv(&outxdr, "passive", "1") != 0)
594 {
595 xdr_destroy(&outxdr);
596 errno = EIO;
597 return EAI_SYSTEM;
598 }
599 }
600
601 if (parallel != 0)
602 {
603 if (encode_kv(&outxdr, "parallel", "1") != 0)
604 {
605 xdr_destroy(&outxdr);
606 errno = EIO;
607 return EAI_SYSTEM;
608 }
609 }
610
611 if (numerichost != 0)
612 {
613 if (encode_kv(&outxdr, "numerichost", "1") != 0)
614 {
615 xdr_destroy(&outxdr);
616 errno = EIO;
617 return EAI_SYSTEM;
618 }
619 }
620
621 *len = xdr_getpos(&outxdr);
622
623 xdr_destroy(&outxdr);
624
625 return 0;
626 }
627
628 static int32_t
629 is_a_number(const char *s)
630 {
631 int32_t i, len;
632
633 if (s == NULL) return 0;
634
635 len = strlen(s);
636 for (i = 0; i < len; i++)
637 {
638 if (isdigit(s[i]) == 0) return 0;
639 }
640
641 return 1;
642 }
643
644 static int
645 gai_trivial(struct in_addr *in4, struct in6_addr *in6, int16_t port, const struct addrinfo *hints, struct addrinfo **res)
646 {
647 int32_t family, wantv4, wantv6, proto;
648 char *loopv4, *loopv6;
649 struct in_addr a4;
650 struct in6_addr a6;
651 struct addrinfo *a;
652
653 family = PF_UNSPEC;
654 if (hints != NULL) family = hints->ai_family;
655
656 wantv4 = 1;
657 wantv6 = 1;
658
659 if (family == PF_INET6) wantv4 = 0;
660 if (family == PF_INET) wantv6 = 0;
661
662 memset(&a4, 0, sizeof(struct in_addr));
663 memset(&a6, 0, sizeof(struct in6_addr));
664
665 if ((in4 == NULL) && (in6 == NULL))
666 {
667 loopv4 = "127.0.0.1";
668 loopv6 = "0:0:0:0:0:0:0:1";
669
670 if ((hints != NULL) && ((hints->ai_flags & AI_PASSIVE) == 1))
671 {
672 loopv4 = "0.0.0.0";
673 loopv6 = "0:0:0:0:0:0:0:0";
674 }
675
676 if ((family == PF_UNSPEC) || (family == PF_INET))
677 {
678 inet_pton(AF_INET, loopv4, &a4);
679 }
680
681 if ((family == PF_UNSPEC) || (family == PF_INET6))
682 {
683 inet_pton(AF_INET6, loopv6, &a6);
684 }
685 }
686 else if (in4 == NULL)
687 {
688 if (family == PF_INET) return EAI_BADHINTS;
689
690 wantv4 = 0;
691 memcpy(&a6, in6, sizeof(struct in6_addr));
692 }
693 else if (in6 == NULL)
694 {
695 if (family == PF_INET6) return EAI_BADHINTS;
696
697 wantv6 = 0;
698 memcpy(&a4, in4, sizeof(struct in_addr));
699 }
700 else
701 {
702 return EAI_NODATA;
703 }
704
705 proto = IPPROTO_UNSPEC;
706
707 if (hints != NULL)
708 {
709 proto = hints->ai_protocol;
710 if (proto == IPPROTO_UNSPEC)
711 {
712 if (hints->ai_socktype == SOCK_DGRAM) proto = IPPROTO_UDP;
713 else if (hints->ai_socktype == SOCK_STREAM) proto = IPPROTO_TCP;
714 }
715 }
716
717 if (wantv4 == 1)
718 {
719 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
720 {
721 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
722 append_addrinfo(res, a);
723 }
724
725 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
726 {
727 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
728 append_addrinfo(res, a);
729 }
730
731 if (proto == IPPROTO_ICMP)
732 {
733 a = new_addrinfo_v4(0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, NULL);
734 append_addrinfo(res, a);
735 }
736 }
737
738 if (wantv6 == 1)
739 {
740 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
741 {
742 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, 0, NULL);
743 append_addrinfo(res, a);
744 }
745
746 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
747 {
748 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, 0, NULL);
749 append_addrinfo(res, a);
750 }
751
752 if (proto == IPPROTO_ICMPV6)
753 {
754 a = new_addrinfo_v6(0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, 0, NULL);
755 append_addrinfo(res, a);
756 }
757 }
758
759 return 0;
760 }
761
762 int
763 gai_files(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
764 {
765 int32_t i, status, numericserv, numerichost, family, proto, wantv4, wantv6;
766 int16_t port;
767 struct servent *s;
768 struct hostent *h;
769 char *protoname, *loopv4, *loopv6;
770 struct in_addr a4;
771 struct in6_addr a6;
772 struct addrinfo *a;
773
774 numericserv = 0;
775 if (servname != NULL) numericserv = is_a_number(servname);
776
777 family = PF_UNSPEC;
778 if (hints != NULL) family = hints->ai_family;
779
780 numerichost = 0;
781
782 if (nodename == NULL)
783 {
784 numerichost = 1;
785
786 loopv4 = "127.0.0.1";
787 loopv6 = "0:0:0:0:0:0:0:1";
788
789 if ((hints != NULL) && ((hints->ai_flags & AI_PASSIVE) == 1))
790 {
791 loopv4 = "0.0.0.0";
792 loopv6 = "0:0:0:0:0:0:0:0";
793 }
794
795 if ((family == PF_UNSPEC) || (family == PF_INET))
796 {
797 inet_pton(AF_INET, loopv4, &a4);
798 }
799
800 if ((family == PF_UNSPEC) || (family == PF_INET6))
801 {
802 inet_pton(AF_INET6, loopv6, &a6);
803 }
804 }
805 else
806 {
807 if ((family == PF_UNSPEC) || (family == PF_INET))
808 {
809 status = inet_pton(AF_INET, nodename, &a4);
810 if (status == 1)
811 {
812 numerichost = 1;
813 if (family == PF_UNSPEC) family = PF_INET;
814 }
815 }
816
817 if ((family == PF_UNSPEC) || (family == PF_INET6))
818 {
819 status = inet_pton(AF_INET6, nodename, &a6);
820 if (status == 1)
821 {
822 numerichost = 1;
823 if (family == PF_UNSPEC) family = PF_INET6;
824 }
825 }
826 }
827
828 wantv4 = 1;
829 wantv6 = 1;
830 if (family == PF_INET6) wantv4 = 0;
831 if (family == PF_INET) wantv6 = 0;
832
833 proto = IPPROTO_UNSPEC;
834 protoname = NULL;
835
836 if (hints != NULL)
837 {
838 proto = hints->ai_protocol;
839 if (proto == IPPROTO_UNSPEC)
840 {
841 if (hints->ai_socktype == SOCK_DGRAM) proto = IPPROTO_UDP;
842 else if (hints->ai_socktype == SOCK_STREAM) proto = IPPROTO_TCP;
843 }
844 }
845
846 if (proto == IPPROTO_UDP) protoname = "udp";
847 else if (proto == IPPROTO_TCP) protoname = "tcp";
848
849 s = NULL;
850 port = 0;
851
852 if (numericserv != 0)
853 {
854 port = htons(atoi(servname));
855 }
856 else if (servname != NULL)
857 {
858 s = getservbyname(servname, protoname);
859 if (s != NULL) port = s->s_port;
860 }
861
862 /* new_addrinfo_v4 and new_addrinfo_v6 expect port in host byte order */
863 port = ntohs(port);
864
865 if (numerichost != 0)
866 {
867 if (wantv4 == 1)
868 {
869 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
870 {
871 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
872 append_addrinfo(res, a);
873 }
874
875 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
876 {
877 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
878 append_addrinfo(res, a);
879 }
880
881 if (proto == IPPROTO_ICMP)
882 {
883 a = new_addrinfo_v4(0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, NULL);
884 append_addrinfo(res, a);
885 }
886 }
887
888 if (wantv6 == 1)
889 {
890 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
891 {
892 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, 0, NULL);
893 append_addrinfo(res, a);
894 }
895
896 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
897 {
898 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, 0, NULL);
899 append_addrinfo(res, a);
900 }
901
902 if (proto == IPPROTO_ICMPV6)
903 {
904 a = new_addrinfo_v6(0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, 0, NULL);
905 append_addrinfo(res, a);
906 }
907 }
908
909 return 0;
910 }
911
912 if (wantv4 == 1)
913 {
914 h = gethostbyname(nodename);
915 if (h == NULL) return 0;
916
917 for (i = 0; h->h_addr_list[i] != 0; i++)
918 {
919 memmove((void *)&a4.s_addr, h->h_addr_list[i], h->h_length);
920
921 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
922 {
923 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
924 append_addrinfo(res, a);
925 }
926
927 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
928 {
929 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
930 append_addrinfo(res, a);
931 }
932 }
933 }
934
935 return 0;
936 }
937
938 static int
939 gai_lookupd(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
940 {
941 uint32_t n, i, qlen, rlen;
942 XDR inxdr;
943 char qbuf[LU_QBUF_SIZE];
944 char *rbuf;
945 char *cname;
946 mach_port_t server_port;
947 kern_return_t status;
948 struct addrinfo *a;
949
950 server_port = MACH_PORT_NULL;
951 if (_lu_running()) server_port = _lookupd_port(0);
952 if (server_port == MACH_PORT_NULL)
953 {
954 /* lookupd isn't available - fall back to the flat files */
955 return gai_files(nodename, servname, hints, res);
956 }
957
958 if (gai_proc < 0)
959 {
960 status = _lookup_link(server_port, "getaddrinfo", &gai_proc);
961 if (status != KERN_SUCCESS)
962 {
963 errno = ECONNREFUSED;
964 return EAI_SYSTEM;
965 }
966 }
967
968 qlen = LU_QBUF_SIZE;
969
970 /* gai_make_query sets errno if it fails */
971 i = gai_make_query(nodename, servname, hints, qbuf, &qlen);
972 if (i != 0) return EAI_SYSTEM;
973
974 qlen /= BYTES_PER_XDR_UNIT;
975
976 rbuf = NULL;
977
978 status = _lookup_all(server_port, gai_proc, (unit *)qbuf, qlen, &rbuf, &rlen);
979 if (status != KERN_SUCCESS) return EAI_NODATA;
980
981 rlen *= BYTES_PER_XDR_UNIT;
982
983 xdrmem_create(&inxdr, rbuf, rlen, XDR_DECODE);
984
985 if (!xdr_int(&inxdr, (int32_t *)&n))
986 {
987 xdr_destroy(&inxdr);
988 errno = EIO;
989 return EAI_SYSTEM;
990 }
991
992 cname = NULL;
993 for (i = 0; i < n; i++)
994 {
995 a = gai_lookupd_process_dictionary(&inxdr);
996 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
997 append_addrinfo(res, a);
998 }
999
1000 xdr_destroy(&inxdr);
1001 if (rbuf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)rbuf, rlen);
1002
1003 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
1004 {
1005 res[0]->ai_canonname = strdup(cname);
1006 }
1007
1008 return 0;
1009 }
1010
1011 static int
1012 gai_checkhints(const struct addrinfo *hints)
1013 {
1014 if (hints == NULL) return 0;
1015 if (hints->ai_addrlen != 0) return EAI_BADHINTS;
1016 if (hints->ai_canonname != NULL) return EAI_BADHINTS;
1017 if (hints->ai_addr != NULL) return EAI_BADHINTS;
1018 if (hints->ai_next != NULL) return EAI_BADHINTS;
1019
1020 /* Check for supported protocol family */
1021 if (gai_family_type_check(hints->ai_family) != 0) return EAI_FAMILY;
1022
1023 /* Check for supported socket */
1024 if (gai_socket_type_check(hints->ai_socktype) != 0) return EAI_BADHINTS;
1025
1026 /* Check for supported protocol */
1027 if (gai_protocol_type_check(hints->ai_protocol) != 0) return EAI_BADHINTS;
1028
1029 /* Check that socket type is compatible with protocol */
1030 if (gai_socket_protocol_type_check(hints->ai_socktype, hints->ai_protocol) != 0) return EAI_BADHINTS;
1031
1032 return 0;
1033 }
1034
1035 int
1036 getaddrinfo(const char * __restrict nodename, const char * __restrict servname, const struct addrinfo * __restrict hints, struct addrinfo ** __restrict res)
1037 {
1038 int32_t status, nodenull, servnull;
1039 int32_t numericserv, numerichost, family;
1040 int16_t port;
1041 struct in_addr a4, *p4;
1042 struct in6_addr a6, *p6;
1043
1044 if (res == NULL) return 0;
1045 *res = NULL;
1046
1047 /* Check input */
1048 nodenull = 0;
1049 if ((nodename == NULL) || (nodename[0] == '\0')) nodenull = 1;
1050
1051 servnull = 0;
1052 if ((servname == NULL) || (servname[0] == '\0')) servnull = 1;
1053
1054 if ((nodenull == 1) && (servnull == 1)) return EAI_NONAME;
1055
1056 status = gai_checkhints(hints);
1057 if (status != 0) return status;
1058
1059 /*
1060 * Trap the "trivial" cases that can be answered without a query.
1061 * (nodename == numeric) && (servname == NULL)
1062 * (nodename == numeric) && (servname == numeric)
1063 * (nodename == NULL) && (servname == numeric)
1064 */
1065 p4 = NULL;
1066 p6 = NULL;
1067
1068 memset(&a4, 0, sizeof(struct in_addr));
1069 memset(&a6, 0, sizeof(struct in6_addr));
1070
1071 numericserv = 0;
1072 port = 0;
1073 if (servnull == 0) numericserv = is_a_number(servname);
1074 if (numericserv == 1) port = atoi(servname);
1075
1076 family = PF_UNSPEC;
1077 if (hints != NULL) family = hints->ai_family;
1078
1079 numerichost = 0;
1080 if (nodenull == 0)
1081 {
1082 if ((family == PF_UNSPEC) || (family == PF_INET))
1083 {
1084 status = inet_pton(AF_INET, nodename, &a4);
1085 if (status == 1)
1086 {
1087 p4 = &a4;
1088 numerichost = 1;
1089 }
1090 }
1091
1092 if ((family == PF_UNSPEC) || (family == PF_INET6))
1093 {
1094 status = inet_pton(AF_INET6, nodename, &a6);
1095 if (status == 1)
1096 {
1097 p6 = &a6;
1098 numerichost = 1;
1099 }
1100 }
1101 }
1102
1103 if ((nodenull == 1) && (numericserv == 1)) return gai_trivial(NULL, NULL, port, hints, res);
1104 if ((numerichost == 1) && (numericserv == 1)) return gai_trivial(p4, p6, port, hints, res);
1105 if ((numerichost == 1) && (servnull == 1)) return gai_trivial(p4, p6, 0, hints, res);
1106
1107 if (nodenull == 1) status = gai_lookupd(NULL, servname, hints, res);
1108 else if (servnull == 1) status = gai_lookupd(nodename, NULL, hints, res);
1109 else status = gai_lookupd(nodename, servname, hints, res);
1110
1111 if ((status == 0) && (*res == NULL)) status = EAI_NODATA;
1112
1113 return status;
1114 }
1115
1116 int32_t
1117 getaddrinfo_async_start(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints, getaddrinfo_async_callback callback, void *context)
1118 {
1119 int32_t status;
1120 uint32_t i, qlen;
1121 char qbuf[LU_QBUF_SIZE];
1122 mach_port_t server_port;
1123
1124 *p = MACH_PORT_NULL;
1125
1126 if ((nodename == NULL) && (servname == NULL)) return EAI_NONAME;
1127
1128 status = gai_checkhints(hints);
1129 if (status != 0) return EAI_BADHINTS;
1130
1131 server_port = MACH_PORT_NULL;
1132 if (_lu_running()) server_port = _lookupd_port(0);
1133 if (server_port == MACH_PORT_NULL)
1134 {
1135 errno = ECONNREFUSED;
1136 return EAI_SYSTEM;
1137 }
1138
1139 if (gai_proc < 0)
1140 {
1141 status = _lookup_link(server_port, "getaddrinfo", &gai_proc);
1142 if (status != KERN_SUCCESS)
1143 {
1144 errno = ECONNREFUSED;
1145 return EAI_SYSTEM;
1146 }
1147 }
1148
1149 qlen = LU_QBUF_SIZE;
1150
1151 /* gai_make_query sets errno if it fails */
1152 i = gai_make_query(nodename, servname, hints, qbuf, &qlen);
1153 if (i != 0) return EAI_SYSTEM;
1154
1155 qlen /= BYTES_PER_XDR_UNIT;
1156
1157 status = lu_async_start(p, gai_proc, qbuf, qlen, (void *)callback, context);
1158 if (status != 0)
1159 {
1160 errno = ECONNREFUSED;
1161 return EAI_SYSTEM;
1162 }
1163
1164 return 0;
1165 }
1166
1167 int32_t
1168 getaddrinfo_async_send(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints)
1169 {
1170 return getaddrinfo_async_start(p, nodename, servname, hints, NULL, NULL);
1171 }
1172
1173 static int
1174 gai_extract_data(char *buf, uint32_t len, struct addrinfo **res)
1175 {
1176 XDR xdr;
1177 uint32_t i, n;
1178 char *cname;
1179 struct addrinfo *a;
1180
1181 *res = NULL;
1182
1183 if (buf == NULL) return EAI_NODATA;
1184 if (len == 0) return EAI_NODATA;
1185
1186 xdrmem_create(&xdr, buf, len, XDR_DECODE);
1187
1188 if (!xdr_int(&xdr, (int32_t *)&n))
1189 {
1190 xdr_destroy(&xdr);
1191 errno = EIO;
1192 return EAI_SYSTEM;
1193 }
1194
1195 cname = NULL;
1196 for (i = 0; i < n; i++)
1197 {
1198 a = gai_lookupd_process_dictionary(&xdr);
1199 if (a == NULL) break;
1200
1201 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
1202 append_addrinfo(res, a);
1203 }
1204
1205 xdr_destroy(&xdr);
1206
1207 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
1208 {
1209 res[0]->ai_canonname = strdup(cname);
1210 }
1211
1212 if (*res == NULL) return EAI_NODATA;
1213 return 0;
1214 }
1215
1216 int32_t
1217 getaddrinfo_async_receive(mach_port_t p, struct addrinfo **res)
1218 {
1219 kern_return_t status;
1220 char *buf;
1221 uint32_t len;
1222
1223 if (res == NULL) return 0;
1224 *res = NULL;
1225
1226 buf = NULL;
1227 len = 0;
1228
1229 status = lu_async_receive(p, &buf, &len);
1230 if (status < 0) return EAI_FAIL;
1231
1232 status = gai_extract_data(buf, len, res);
1233 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1234 if (status != 0) return status;
1235
1236 if (*res == NULL) return EAI_NODATA;
1237
1238 return 0;
1239 }
1240
1241 int32_t
1242 getaddrinfo_async_handle_reply(void *msg)
1243 {
1244 getaddrinfo_async_callback callback;
1245 void *context;
1246 char *buf;
1247 uint32_t len;
1248 int status;
1249 struct addrinfo *res;
1250
1251 callback = (getaddrinfo_async_callback)NULL;
1252 context = NULL;
1253 buf = NULL;
1254 len = 0;
1255 res = NULL;
1256
1257 status = lu_async_handle_reply(msg, &buf, &len, (void **)&callback, &context);
1258 if (status != KERN_SUCCESS)
1259 {
1260 if (status == MIG_REPLY_MISMATCH) return 0;
1261 if (callback != NULL) callback(EAI_NODATA, NULL, context);
1262 return EAI_NODATA;
1263 }
1264
1265 status = gai_extract_data(buf, len, &res);
1266 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1267 if (status != 0)
1268 {
1269 if (callback != NULL) callback(status, NULL, context);
1270 return status;
1271 }
1272
1273 if (res == NULL)
1274 {
1275 callback(EAI_NODATA, NULL, context);
1276 return EAI_NODATA;
1277 }
1278
1279 callback(0, res, context);
1280 return 0;
1281 }
1282
1283 /*
1284 * getnameinfo
1285 */
1286
1287 /*
1288 * getnameinfo support in lookupd
1289 * Input dict may contain the following
1290 *
1291 * ip_address: node address
1292 * ipv6_address: node address
1293 * port: service number
1294 * protocol: [tcp] | udp
1295 * fqdn: [1] | 0
1296 * numerichost: [0] | 1
1297 * name_required: [0] | 1
1298 * numericserv: [0] | 1
1299 *
1300 * Output dictionary may contain the following
1301 * All values are encoded as strings.
1302 *
1303 * name: char *
1304 * service: char *
1305 */
1306
1307 static int
1308 gni_lookupd_process_dictionary(XDR *inxdr, char **host, char **serv)
1309 {
1310 int32_t i, j, nkeys, nvals, status;
1311 char *key, **vals;
1312
1313 if ((host == NULL) || (serv == NULL))
1314 {
1315 errno = EINVAL;
1316 return EAI_SYSTEM;
1317 }
1318
1319 if (!xdr_int(inxdr, &nkeys))
1320 {
1321 errno = EIO;
1322 return EAI_SYSTEM;
1323 }
1324
1325 *host = NULL;
1326 *serv = NULL;
1327
1328 for (i = 0; i < nkeys; i++)
1329 {
1330 key = NULL;
1331 vals = NULL;
1332 nvals = 0;
1333
1334 status = _lu_xdr_attribute(inxdr, &key, &vals, (uint32_t *)&nvals);
1335 if (status < 0)
1336 {
1337 errno = EIO;
1338 return EAI_SYSTEM;
1339 }
1340
1341 if (nvals == 0)
1342 {
1343 free(key);
1344 continue;
1345 }
1346
1347 if ((*host == NULL) && (!strcmp("name", key)))
1348 {
1349 *host = vals[0];
1350 for (j = 1; j < nvals; j++) free(vals[j]);
1351 }
1352
1353 else if ((*serv == NULL) && (!strcmp(key, "service")))
1354 {
1355 *serv = vals[0];
1356 for (j = 1; j < nvals; j++) free(vals[j]);
1357 }
1358
1359 if (key != NULL) free(key);
1360 free(vals);
1361 }
1362
1363 return 0;
1364 }
1365
1366 static int
1367 gni_make_query(const struct sockaddr *sa, size_t salen, int wanthost, int wantserv, int flags, char *buf, uint32_t *len)
1368 {
1369 XDR outxdr;
1370 uint16_t port;
1371 char str[_LU_MAXLUSTRLEN], *key, ifname[IF_NAMESIZE];
1372 uint32_t a4, ifnum, offset, na, proto, fqdn, numerichost, numericserv, name_req, isll, issl;
1373 struct sockaddr_in6 *s6;
1374
1375 if (sa == NULL) return EAI_FAIL;
1376 if (sa->sa_len != salen) return EAI_FAMILY;
1377
1378 proto = IPPROTO_TCP;
1379 fqdn = 1;
1380 numerichost = 0;
1381 numericserv = 0;
1382 name_req = 0;
1383 isll = 0;
1384 issl = 0;
1385
1386 offset = INET_NTOP_AF_INET_OFFSET;
1387 key = "ip_address";
1388 port = 0;
1389
1390 if (sa->sa_family == PF_INET)
1391 {
1392 a4 = ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
1393 if (IN_MULTICAST(a4) || IN_EXPERIMENTAL(a4)) flags |= NI_NUMERICHOST;
1394 a4 >>= IN_CLASSA_NSHIFT;
1395 if (a4 == 0) flags |= NI_NUMERICHOST;
1396
1397 port = ((struct sockaddr_in *)sa)->sin_port;
1398 }
1399 else if (sa->sa_family == PF_INET6)
1400 {
1401 s6 = (struct sockaddr_in6 *)sa;
1402 switch (s6->sin6_addr.s6_addr[0])
1403 {
1404 case 0x00:
1405 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
1406 {
1407 }
1408 else if (IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr))
1409 {
1410 }
1411 else
1412 {
1413 flags |= NI_NUMERICHOST;
1414 }
1415 break;
1416 default:
1417 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
1418 {
1419 isll = 1;
1420 }
1421 else if (IN6_IS_ADDR_SITELOCAL(&s6->sin6_addr))
1422 {
1423 issl = 1;
1424 }
1425 else if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
1426 {
1427 flags |= NI_NUMERICHOST;
1428 }
1429 break;
1430 }
1431
1432 if ((isll != 0) || (issl != 0))
1433 {
1434 ifnum = s6->sin6_addr.__u6_addr.__u6_addr16[1];
1435 if (ifnum == 0) ifnum = s6->sin6_scope_id;
1436 else if ((s6->sin6_scope_id != 0) && (ifnum != s6->sin6_scope_id)) return EAI_FAIL;
1437
1438 s6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1439 s6->sin6_scope_id = ifnum;
1440 if ((ifnum != 0) && (flags & NI_NUMERICHOST)) flags |= NI_WITHSCOPEID;
1441 }
1442
1443 offset = INET_NTOP_AF_INET6_OFFSET;
1444 key = "ipv6_address";
1445 port = s6->sin6_port;
1446 }
1447 else
1448 {
1449 return EAI_FAMILY;
1450 }
1451
1452 na = 0;
1453
1454 if (wanthost != 0) na++;
1455 if (wantserv != 0) na++;
1456
1457 if (flags & NI_NOFQDN)
1458 {
1459 fqdn = 0;
1460 na++;
1461 }
1462
1463 if (flags & NI_NUMERICHOST)
1464 {
1465 numerichost = 1;
1466 na++;
1467 }
1468
1469 if (flags & NI_NUMERICSERV)
1470 {
1471 numericserv = 1;
1472 na++;
1473 }
1474
1475 if (flags & NI_NAMEREQD)
1476 {
1477 name_req = 1;
1478 na++;
1479 }
1480
1481 if (flags & NI_DGRAM)
1482 {
1483 proto = IPPROTO_UDP;
1484 na++;
1485 }
1486
1487 xdrmem_create(&outxdr, buf, *len, XDR_ENCODE);
1488
1489 if (!xdr_int(&outxdr, (int32_t *)&na))
1490 {
1491 xdr_destroy(&outxdr);
1492 errno = EIO;
1493 return EAI_SYSTEM;
1494 }
1495
1496 if (wanthost != 0)
1497 {
1498 inet_ntop(sa->sa_family, (char *)(sa) + offset, str, _LU_MAXLUSTRLEN);
1499
1500 if ((flags & NI_WITHSCOPEID) && (sa->sa_family == AF_INET6))
1501 {
1502 ifnum = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
1503 if (if_indextoname(ifnum, ifname) != NULL)
1504 {
1505 strcat(str, "%");
1506 strcat(str, ifname);
1507 }
1508 }
1509
1510 if (encode_kv(&outxdr, key, str) != 0)
1511 {
1512 xdr_destroy(&outxdr);
1513 errno = EIO;
1514 return EAI_SYSTEM;
1515 }
1516 }
1517
1518 if (wantserv != 0)
1519 {
1520 snprintf(str, _LU_MAXLUSTRLEN, "%hu", port);
1521 if (encode_kv(&outxdr, "port", str) != 0)
1522 {
1523 xdr_destroy(&outxdr);
1524 errno = EIO;
1525 return EAI_SYSTEM;
1526 }
1527 }
1528
1529 if (proto == IPPROTO_UDP)
1530 {
1531 if (encode_kv(&outxdr, "protocol", "udp") != 0)
1532 {
1533 xdr_destroy(&outxdr);
1534 errno = EIO;
1535 return EAI_SYSTEM;
1536 }
1537 }
1538
1539 if (fqdn == 0)
1540 {
1541 if (encode_kv(&outxdr, "fqdn", "0") != 0)
1542 {
1543 xdr_destroy(&outxdr);
1544 errno = EIO;
1545 return EAI_SYSTEM;
1546 }
1547 }
1548
1549 if (numerichost == 1)
1550 {
1551 if (encode_kv(&outxdr, "numerichost", "1") != 0)
1552 {
1553 xdr_destroy(&outxdr);
1554 errno = EIO;
1555 return EAI_SYSTEM;
1556 }
1557 }
1558
1559 if (numericserv == 1)
1560 {
1561 if (encode_kv(&outxdr, "numericserv", "1") != 0)
1562 {
1563 xdr_destroy(&outxdr);
1564 errno = EIO;
1565 return EAI_SYSTEM;
1566 }
1567 }
1568
1569 if (name_req == 1)
1570 {
1571 if (encode_kv(&outxdr, "name_required", "1") != 0)
1572 {
1573 xdr_destroy(&outxdr);
1574 errno = EIO;
1575 return EAI_SYSTEM;
1576 }
1577 }
1578
1579 *len = xdr_getpos(&outxdr);
1580
1581 xdr_destroy(&outxdr);
1582
1583 return 0;
1584 }
1585
1586 int
1587 getnameinfo(const struct sockaddr * __restrict sa, socklen_t salen, char * __restrict host, socklen_t hostlen, char * __restrict serv, socklen_t servlen, int flags)
1588 {
1589 uint32_t n, i, qlen, rlen;
1590 uint32_t ifnum;
1591 int wanth, wants, isll, issl;
1592 XDR inxdr;
1593 char qbuf[LU_QBUF_SIZE], ifname[IF_NAMESIZE];
1594 char *rbuf, *hval, *sval;
1595 mach_port_t server_port;
1596 kern_return_t status;
1597 struct sockaddr_in *s4;
1598 struct sockaddr_in6 *s6;
1599
1600 /* Check input */
1601 if (sa == NULL) return EAI_FAIL;
1602
1603 isll = 0;
1604 issl = 0;
1605 ifnum = 0;
1606
1607 if (sa->sa_family == AF_INET6)
1608 {
1609 s6 = (struct sockaddr_in6 *)sa;
1610
1611 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) isll = 1;
1612 if (IN6_IS_ADDR_SITELOCAL(&s6->sin6_addr)) issl = 1;
1613
1614 /*
1615 * Link-local and site-local IPv6 addresses may have a scope id
1616 * in s6->sin6_addr.__u6_addr.__u6_addr16[1] as well as in s6->sin6_scope_id.
1617 * If they are both non-zero, they must be equal.
1618 * We zero s6->sin6_addr.__u6_addr.__u6_addr16[1] and set s6->sin6_scope_id.
1619 */
1620 if ((isll != 0) || (issl != 0))
1621 {
1622 ifnum = ntohs(s6->sin6_addr.__u6_addr.__u6_addr16[1]);
1623 if (ifnum == 0) ifnum = s6->sin6_scope_id;
1624 else if ((s6->sin6_scope_id != 0) && (ifnum != s6->sin6_scope_id)) return EAI_FAIL;
1625
1626 s6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1627 s6->sin6_scope_id = ifnum;
1628 }
1629
1630 /* V4 mapped and compat addresses are converted to plain V4 */
1631 if ((IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) || (IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr)))
1632 {
1633 s4 = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in));
1634 s4->sin_len = sizeof(struct sockaddr_in);
1635 s4->sin_family = AF_INET;
1636 s4->sin_port = s6->sin6_port;
1637 memcpy(&(s4->sin_addr.s_addr), &(s6->sin6_addr.s6_addr[12]), 4);
1638
1639 i = getnameinfo((const struct sockaddr *)s4, s4->sin_len, host, hostlen, serv, servlen, flags);
1640 free(s4);
1641 return i;
1642 }
1643 }
1644
1645 wanth = 0;
1646 if ((host != NULL) && (hostlen != 0)) wanth = 1;
1647
1648 wants = 0;
1649 if ((serv != NULL) && (servlen != 0)) wants = 1;
1650
1651 if ((wanth == 0) && (wants == 0)) return 0;
1652
1653 /*
1654 * Special cases handled by the library
1655 */
1656 if ((wanth == 1) && (flags & NI_NUMERICHOST))
1657 {
1658 i = INET_NTOP_AF_INET_OFFSET;
1659 if (sa->sa_family == PF_INET6) i = INET_NTOP_AF_INET6_OFFSET;
1660 if (inet_ntop(sa->sa_family, (char *)(sa) + i, host, hostlen) == NULL) return EAI_FAIL;
1661
1662 if (((isll != 0) || (issl != 0)) && (ifnum != 0))
1663 {
1664 /* append interface name */
1665 if (if_indextoname(ifnum, ifname) != NULL)
1666 {
1667 strcat(host, "%");
1668 strcat(host, ifname);
1669 }
1670 }
1671
1672 if (wants == 0) return 0;
1673 }
1674
1675 if ((wants == 1) && (flags & NI_NUMERICSERV))
1676 {
1677 if (sa->sa_family == PF_INET)
1678 {
1679 s4 = (struct sockaddr_in *)sa;
1680 n = snprintf(serv, servlen, "%hu", ntohs(s4->sin_port));
1681 if (n >= servlen) return EAI_FAIL;
1682 }
1683 else if (sa->sa_family == PF_INET6)
1684 {
1685 s6 = (struct sockaddr_in6 *)sa;
1686 n = snprintf(serv, servlen, "%hu", ntohs(s6->sin6_port));
1687 if (n >= servlen) return EAI_FAIL;
1688 }
1689 else return EAI_FAMILY;
1690
1691 if (wanth == 0) return 0;
1692 }
1693
1694 if ((wanth == 1) && (flags & NI_NUMERICHOST) && (wants == 1) && (flags & NI_NUMERICSERV)) return 0;
1695
1696 /*
1697 * Ask lookupd
1698 */
1699 server_port = MACH_PORT_NULL;
1700 if (_lu_running()) server_port = _lookupd_port(0);
1701 if (server_port == MACH_PORT_NULL)
1702 {
1703 errno = ECONNREFUSED;
1704 return EAI_SYSTEM;
1705 }
1706
1707 if (gni_proc < 0)
1708 {
1709 status = _lookup_link(server_port, "getnameinfo", &gni_proc);
1710 if (status != KERN_SUCCESS)
1711 {
1712 errno = ECONNREFUSED;
1713 return EAI_SYSTEM;
1714 }
1715 }
1716
1717 qlen = LU_QBUF_SIZE;
1718 i = gni_make_query(sa, salen, wanth, wants, flags, qbuf, &qlen);
1719 if (i != 0) return i;
1720
1721 qlen /= BYTES_PER_XDR_UNIT;
1722
1723 rbuf = NULL;
1724
1725 status = _lookup_all(server_port, gni_proc, (unit *)qbuf, qlen, &rbuf, &rlen);
1726 if (status != KERN_SUCCESS) return EAI_NONAME;
1727
1728 rlen *= BYTES_PER_XDR_UNIT;
1729
1730 xdrmem_create(&inxdr, rbuf, rlen, XDR_DECODE);
1731
1732 if (!xdr_int(&inxdr, (int32_t *)&n))
1733 {
1734 xdr_destroy(&inxdr);
1735 errno = EIO;
1736 return EAI_SYSTEM;
1737 }
1738
1739 if (n != 1)
1740 {
1741 xdr_destroy(&inxdr);
1742 return EAI_NONAME;
1743 }
1744
1745 hval = NULL;
1746 sval = NULL;
1747
1748 i = gni_lookupd_process_dictionary(&inxdr, &hval, &sval);
1749
1750 xdr_destroy(&inxdr);
1751 if (rbuf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)rbuf, rlen);
1752
1753 if (i != 0) return i;
1754
1755 i = 0;
1756 if (hval != NULL) i = strlen(hval) + 1;
1757 if ((host != NULL) && (hostlen != 0) && (i != 0))
1758 {
1759 if (i > hostlen) return EAI_FAIL;
1760 memcpy(host, hval, i);
1761 free(hval);
1762 }
1763
1764 i = 0;
1765 if (sval != NULL) i = strlen(sval) + 1;
1766 if ((serv != NULL) && (servlen != 0) && (i != 0))
1767 {
1768 if (i > servlen) return EAI_FAIL;
1769 memcpy(serv, sval, i);
1770 free(sval);
1771 }
1772
1773 return 0;
1774 }
1775
1776 int32_t
1777 getnameinfo_async_start(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags, getnameinfo_async_callback callback, void *context)
1778 {
1779 uint32_t i, qlen;
1780 char qbuf[LU_QBUF_SIZE];
1781 mach_port_t server_port;
1782 kern_return_t status;
1783
1784 /* Check input */
1785 if (sa == NULL) return EAI_FAIL;
1786
1787 server_port = MACH_PORT_NULL;
1788 if (_lu_running()) server_port = _lookupd_port(0);
1789 if (server_port == MACH_PORT_NULL)
1790 {
1791 errno = ECONNREFUSED;
1792 return EAI_SYSTEM;
1793 }
1794
1795 if (gni_proc < 0)
1796 {
1797 status = _lookup_link(server_port, "getnameinfo", &gni_proc);
1798 if (status != KERN_SUCCESS)
1799 {
1800 errno = ECONNREFUSED;
1801 return EAI_SYSTEM;
1802 }
1803 }
1804
1805 qlen = LU_QBUF_SIZE;
1806 i = gni_make_query(sa, salen, 1, 1, flags, qbuf, &qlen);
1807 if (i != 0) return i;
1808
1809 qlen /= BYTES_PER_XDR_UNIT;
1810
1811 status = lu_async_start(p, gni_proc, qbuf, qlen, (void *)callback, context);
1812 if (status != 0)
1813 {
1814 errno = ECONNREFUSED;
1815 return EAI_SYSTEM;
1816 }
1817
1818 return 0;
1819 }
1820
1821 int32_t
1822 getnameinfo_async_send(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags)
1823 {
1824 return getnameinfo_async_start(p, sa, salen, flags, NULL, NULL);
1825 }
1826
1827 static int
1828 gni_extract_data(char *buf, uint32_t len, char **host, char **serv)
1829 {
1830 XDR xdr;
1831 uint32_t n;
1832 int i;
1833
1834 *host = NULL;
1835 *serv = NULL;
1836
1837 if (buf == NULL) return EAI_NODATA;
1838 if (len == 0) return EAI_NODATA;
1839
1840 xdrmem_create(&xdr, buf, len, XDR_DECODE);
1841
1842 if (!xdr_int(&xdr, (int32_t *)&n))
1843 {
1844 xdr_destroy(&xdr);
1845 errno = EIO;
1846 return EAI_SYSTEM;
1847 }
1848
1849 if (n != 1)
1850 {
1851 xdr_destroy(&xdr);
1852 return EAI_NONAME;
1853 }
1854
1855 i = gni_lookupd_process_dictionary(&xdr, host, serv);
1856 xdr_destroy(&xdr);
1857 return i;
1858 }
1859
1860 int32_t
1861 getnameinfo_async_receive(mach_port_t p, char **host, char **serv)
1862 {
1863 kern_return_t status;
1864 char *buf;
1865 uint32_t len;
1866
1867 buf = NULL;
1868 len = 0;
1869
1870 status = lu_async_receive(p, &buf, &len);
1871 if (status < 0) return EAI_FAIL;
1872
1873 status = gni_extract_data(buf, len, host, serv);
1874 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1875 if (status != 0) return status;
1876
1877 return 0;
1878 }
1879
1880 int32_t
1881 getnameinfo_async_handle_reply(void *msg)
1882 {
1883 getnameinfo_async_callback callback;
1884 void *context;
1885 char *buf, *hval, *sval;
1886 uint32_t len;
1887 int status;
1888
1889 callback = (getnameinfo_async_callback)NULL;
1890 context = NULL;
1891 buf = NULL;
1892 len = 0;
1893
1894 status = lu_async_handle_reply(msg, &buf, &len, (void **)&callback, &context);
1895 if (status != KERN_SUCCESS)
1896 {
1897 if (status == MIG_REPLY_MISMATCH) return 0;
1898 if (callback != NULL) callback(EAI_NONAME, NULL, NULL, context);
1899 return EAI_NONAME;
1900 }
1901
1902 hval = NULL;
1903 sval = NULL;
1904
1905 status = gni_extract_data(buf, len, &hval, &sval);
1906 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1907 if (status != 0)
1908 {
1909 if (callback != NULL) callback(status, NULL, NULL, context);
1910 return status;
1911 }
1912
1913 callback(0, hval, sval, context);
1914 return 0;
1915 }