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