2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
36 #include <rpc/types.h>
38 #include <mach/mach.h>
39 #include <servers/bootstrap.h>
43 #include <arpa/inet.h>
47 #define IPPROTO_UNSPEC 0
49 #define WANT_A4_ONLY 1
50 #define WANT_A6_ONLY 2
51 #define WANT_A6_PLUS_MAPPED_A4 3
52 #define WANT_A6_OR_MAPPED4_IF_NO_A6 4
54 #define LONG_STRING_LENGTH 8192
55 #define _LU_MAXLUSTRLEN 256
57 extern int _lu_running(void);
58 extern mach_port_t
_lookupd_port();
59 extern int _lookup_link();
60 extern int _lookup_one();
61 extern int _lookup_all();
78 struct lu_dict
*lu_next
;
91 static int supported_family
[] =
97 static int supported_family_count
= 3;
99 static int supported_socket
[] =
106 static int supported_socket_count
= 4;
108 static int supported_protocol
[] =
115 static int supported_protocol_count
= 4;
117 static int supported_socket_protocol_pair
[] =
119 SOCK_RAW
, IPPROTO_UNSPEC
,
120 SOCK_RAW
, IPPROTO_UDP
,
121 SOCK_RAW
, IPPROTO_TCP
,
122 SOCK_RAW
, IPPROTO_ICMPV6
,
123 SOCK_UNSPEC
, IPPROTO_UNSPEC
,
124 SOCK_UNSPEC
, IPPROTO_UDP
,
125 SOCK_UNSPEC
, IPPROTO_TCP
,
126 SOCK_UNSPEC
, IPPROTO_ICMPV6
,
127 SOCK_DGRAM
, IPPROTO_UNSPEC
,
128 SOCK_DGRAM
, IPPROTO_UDP
,
129 SOCK_STREAM
, IPPROTO_UNSPEC
,
130 SOCK_STREAM
, IPPROTO_TCP
132 static int supported_socket_protocol_pair_count
= 12;
135 gai_family_type_check(int f
)
139 for (i
= 0; i
< supported_family_count
; i
++)
141 if (f
== supported_family
[i
]) return 0;
148 gai_socket_type_check(int s
)
152 for (i
= 0; i
< supported_socket_count
; i
++)
154 if (s
== supported_socket
[i
]) return 0;
161 gai_protocol_type_check(int p
)
165 for (i
= 0; i
< supported_protocol_count
; i
++)
167 if (p
== supported_protocol
[i
]) return 0;
174 gai_socket_protocol_type_check(int s
, int p
)
178 for (i
= 0, j
= 0; i
< supported_socket_protocol_pair_count
; i
++, j
+=2)
180 ss
= supported_socket_protocol_pair
[j
];
181 sp
= supported_socket_protocol_pair
[j
+1];
182 if ((s
== ss
) && (p
== sp
)) return 0;
189 gai_inet_pton(const char *s
, struct in6_addr
*a6
)
191 if (s
== NULL
) return 0;
192 if (a6
== NULL
) return 0;
193 return inet_pton(AF_INET6
, s
, (void *)&a6
->__u6_addr
.__u6_addr32
[0]);
197 gai_strerror(int err
)
201 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
202 case EAI_AGAIN
: return "Temporary failure in name resolution";
203 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
204 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
205 case EAI_FAMILY
: return "ai_family not supported";
206 case EAI_MEMORY
: return "Memory allocation failure";
207 case EAI_NODATA
: return "No address associated with nodename";
208 case EAI_NONAME
: return "nodename nor servname provided, or not known";
209 case EAI_SERVICE
: return "servname not supported for ai_socktype";
210 case EAI_SOCKTYPE
: return "ai_socktype not supported";
211 case EAI_SYSTEM
: return "System error";
212 case EAI_BADHINTS
: return "Bad hints";
213 case EAI_PROTOCOL
: return "ai_protocol not supported";
216 return "Unknown error";
220 is_ipv4_address(const char *s
)
224 if (s
== NULL
) return 0;
225 return inet_aton(s
, &a
);
229 is_ipv6_address(const char *s
)
233 if (s
== NULL
) return 0;
234 return gai_inet_pton(s
, &a
);
238 append_addrinfo(struct addrinfo
**l
, struct addrinfo
*a
)
242 if (l
== NULL
) return;
243 if (a
== NULL
) return;
253 if (a
->ai_family
== PF_INET6
)
255 if (x
->ai_family
== PF_INET
)
262 while ((x
->ai_next
!= NULL
) && (x
->ai_next
->ai_family
!= PF_INET
)) x
= x
->ai_next
;
263 a
->ai_next
= x
->ai_next
;
268 while (x
->ai_next
!= NULL
) x
= x
->ai_next
;
275 free_lu_dict(struct lu_dict
*d
)
277 struct lu_dict
*next
;
282 if (d
->type
!= NULL
) free(d
->type
);
283 if (d
->name
!= NULL
) free(d
->name
);
284 if (d
->cname
!= NULL
) free(d
->cname
);
285 if (d
->mx
!= NULL
) free(d
->mx
);
286 if (d
->ipv4
!= NULL
) free(d
->ipv4
);
287 if (d
->ipv6
!= NULL
) free(d
->ipv6
);
288 if (d
->service
!= NULL
) free(d
->service
);
289 if (d
->port
!= NULL
) free(d
->port
);
290 if (d
->protocol
!= NULL
) free(d
->protocol
);
291 if (d
->target
!= NULL
) free(d
->target
);
292 if (d
->priority
!= NULL
) free(d
->priority
);
293 if (d
->weight
!= NULL
) free(d
->weight
);
300 _lu_str_equal(char *a
, char *b
)
304 if (b
== NULL
) return 1;
308 if (b
== NULL
) return 0;
310 if (!strcmp(a
, b
)) return 1;
315 lu_dict_equal(struct lu_dict
*a
, struct lu_dict
*b
)
317 if (a
== NULL
) return 0;
318 if (b
== NULL
) return 0;
320 if (_lu_str_equal(a
->type
, b
->type
) == 0) return 0;
321 if (_lu_str_equal(a
->name
, b
->name
) == 0) return 0;
322 if (_lu_str_equal(a
->cname
, b
->cname
) == 0) return 0;
323 if (_lu_str_equal(a
->mx
, b
->mx
) == 0) return 0;
324 if (_lu_str_equal(a
->ipv4
, b
->ipv4
) == 0) return 0;
325 if (_lu_str_equal(a
->ipv6
, b
->ipv6
) == 0) return 0;
326 if (_lu_str_equal(a
->service
, b
->service
) == 0) return 0;
327 if (_lu_str_equal(a
->port
, b
->port
) == 0) return 0;
328 if (_lu_str_equal(a
->protocol
, b
->protocol
) == 0) return 0;
329 if (_lu_str_equal(a
->target
, b
->target
) == 0) return 0;
330 if (_lu_str_equal(a
->priority
, b
->priority
) == 0) return 0;
331 if (_lu_str_equal(a
->weight
, b
->weight
) == 0) return 0;
336 * Append a single dictionary to a list if it is unique.
337 * Free it if it is not appended.
340 merge_lu_dict(struct lu_dict
**l
, struct lu_dict
*d
)
342 struct lu_dict
*x
, *e
;
344 if (l
== NULL
) return;
345 if (d
== NULL
) return;
354 for (x
= *l
; x
!= NULL
; x
= x
->lu_next
)
357 if (lu_dict_equal(x
, d
))
368 append_lu_dict(struct lu_dict
**l
, struct lu_dict
*d
)
370 struct lu_dict
*x
, *next
;
372 if (l
== NULL
) return;
373 if (d
== NULL
) return;
393 * We collect values for the following keys:
407 lookupd_process_dictionary(XDR
*inxdr
, struct lu_dict
**l
)
409 int i
, nkeys
, j
, nvals
;
414 if (!xdr_int(inxdr
, &nkeys
)) return;
416 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
417 memset(d
, 0, sizeof(struct lu_dict
));
419 for (i
= 0; i
< nkeys
; i
++)
423 if (!xdr_string(inxdr
, &key
, LONG_STRING_LENGTH
))
430 if (!strcmp(key
, "name")) addme
= LU_NAME
;
431 else if (!strcmp(key
, "cname")) addme
= LU_CNAME
;
432 else if (!strcmp(key
, "mail_exchanger")) addme
= LU_MX
;
433 else if (!strcmp(key
, "ip_address")) addme
= LU_IPV4
;
434 else if (!strcmp(key
, "ipv6_address")) addme
= LU_IPV6
;
435 else if (!strcmp(key
, "port")) addme
= LU_PORT
;
436 else if (!strcmp(key
, "target")) addme
= LU_TARGET
;
437 else if (!strcmp(key
, "priority")) addme
= LU_PRIORITY
;
438 else if (!strcmp(key
, "preference")) addme
= LU_PRIORITY
;
439 else if (!strcmp(key
, "weight")) addme
= LU_WEIGHT
;
442 if (!xdr_int(inxdr
, &nvals
))
448 for (j
= 0; j
< nvals
; j
++)
451 if (!xdr_string(inxdr
, &val
, LONG_STRING_LENGTH
))
457 if (addme
== 0) free(val
);
458 else if (addme
== LU_NAME
) d
->name
= val
;
459 else if (addme
== LU_CNAME
) d
->cname
= val
;
460 else if (addme
== LU_MX
) d
->mx
= val
;
461 else if (addme
== LU_IPV4
) d
->ipv4
= val
;
462 else if (addme
== LU_IPV6
) d
->ipv6
= val
;
463 else if (addme
== LU_PORT
) d
->port
= val
;
464 else if (addme
== LU_TARGET
) d
->target
= val
;
465 else if (addme
== LU_PRIORITY
) d
->priority
= val
;
466 else if (addme
== LU_WEIGHT
) d
->weight
= val
;
468 if (addme
!= 0) d
->count
++;
477 encode_kv(XDR
*x
, char *k
, char *v
)
481 if (!xdr_string(x
, &k
, _LU_MAXLUSTRLEN
)) return 1;
482 if (!xdr_int(x
, &n
)) return 1;
483 if (!xdr_string(x
, &v
, _LU_MAXLUSTRLEN
)) return 1;
489 gai_files(struct lu_dict
*q
, struct lu_dict
**list
)
495 char str
[64], portstr
[64];
498 if (!strcmp(q
->type
, "service"))
503 s
= getservbyname(q
->name
, q
->protocol
);
505 else if (q
->port
!= NULL
)
507 port
= atoi(q
->port
);
508 s
= getservbyport(port
, q
->protocol
);
510 if (s
== NULL
) return 0;
512 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
513 memset(d
, 0, sizeof(struct lu_dict
));
515 if (s
->s_name
!= NULL
) d
->name
= strdup(s
->s_name
);
516 sprintf(str
, "%u", ntohl(s
->s_port
));
517 d
->port
= strdup(str
);
518 if (s
->s_proto
!= NULL
) d
->protocol
= strdup(s
->s_proto
);
520 merge_lu_dict(list
, d
);
524 if (!strcmp(q
->type
, "host"))
527 if (q
->service
!= NULL
)
529 s
= getservbyname(q
->service
, q
->protocol
);
531 else if (q
->port
!= NULL
)
533 port
= atoi(q
->port
);
534 s
= getservbyport(port
, q
->protocol
);
537 sprintf(portstr
, "0");
538 if (s
!= NULL
) sprintf(portstr
, "%u", ntohl(s
->s_port
));
543 h
= gethostbyname(q
->name
);
545 else if (q
->ipv4
!= NULL
)
547 if (inet_aton(q
->ipv4
, &a4
) == 0) return -1;
548 h
= gethostbyaddr((char *)&a4
, sizeof(struct in_addr
), PF_INET
);
552 /* gethostbyaddr for IPV6? */
556 if (h
== NULL
) return 0;
558 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
560 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
561 memset(d
, 0, sizeof(struct lu_dict
));
563 if (h
->h_name
!= NULL
)
565 d
->name
= strdup(h
->h_name
);
566 d
->target
= strdup(h
->h_name
);
568 memmove((void *)&a4
.s_addr
, h
->h_addr_list
[i
], h
->h_length
);
570 sprintf(str
, "%s", inet_ntoa(a4
));
571 d
->ipv4
= strdup(str
);
575 if (s
->s_name
!= NULL
) d
->service
= strdup(s
->s_name
);
576 d
->port
= strdup(portstr
);
579 merge_lu_dict(list
, d
);
588 gai_lookupd(struct lu_dict
*q
, struct lu_dict
**list
)
595 char databuf
[_LU_MAXLUSTRLEN
* BYTES_PER_XDR_UNIT
];
597 kern_return_t status
;
598 mach_port_t server_port
;
600 if (q
== NULL
) return 0;
601 if (q
->count
== 0) return 0;
602 if (q
->type
== NULL
) return 0;
604 if (list
== NULL
) return -1;
606 server_port
= MACH_PORT_NULL
;
607 if (_lu_running()) server_port
= _lookupd_port(0);
609 if (server_port
== MACH_PORT_NULL
) return gai_files(q
, list
);
611 status
= _lookup_link(server_port
, "query", &proc
);
612 if (status
!= KERN_SUCCESS
) return gai_files(q
, list
);
614 xdrmem_create(&outxdr
, databuf
, sizeof(databuf
), XDR_ENCODE
);
616 /* Encode attribute count */
618 if (!xdr_int(&outxdr
, &na
))
620 xdr_destroy(&outxdr
);
624 if (encode_kv(&outxdr
, "_lookup_category", q
->type
) != 0)
626 xdr_destroy(&outxdr
);
632 if (encode_kv(&outxdr
, "name", q
->name
) != 0)
634 xdr_destroy(&outxdr
);
641 if (encode_kv(&outxdr
, "ip_address", q
->ipv4
) != 0)
643 xdr_destroy(&outxdr
);
650 if (encode_kv(&outxdr
, "ipv6_address", q
->ipv6
) != 0)
652 xdr_destroy(&outxdr
);
657 if (q
->service
!= NULL
)
659 if (encode_kv(&outxdr
, "service", q
->service
) != 0)
661 xdr_destroy(&outxdr
);
668 if (encode_kv(&outxdr
, "port", q
->port
) != 0)
670 xdr_destroy(&outxdr
);
675 if (q
->protocol
!= NULL
)
677 if (encode_kv(&outxdr
, "protocol", q
->protocol
) != 0)
679 xdr_destroy(&outxdr
);
687 n
= xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
;
688 status
= _lookup_all(server_port
, proc
, databuf
, n
, &listbuf
, &datalen
);
689 if (status
!= KERN_SUCCESS
)
691 xdr_destroy(&outxdr
);
695 xdr_destroy(&outxdr
);
697 datalen
*= BYTES_PER_XDR_UNIT
;
699 xdrmem_create(&inxdr
, listbuf
, datalen
, XDR_DECODE
);
701 if (!xdr_int(&inxdr
, &n
))
707 for (i
= 0; i
< n
; i
++)
709 lookupd_process_dictionary(&inxdr
, list
);
714 vm_deallocate(mach_task_self(), (vm_address_t
)listbuf
, datalen
);
720 freeaddrinfo(struct addrinfo
*a
)
722 struct addrinfo
*next
;
727 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
728 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
734 static struct addrinfo
*
735 new_addrinfo_v4(int flags
, int sock
, int proto
, unsigned short port
, struct in_addr addr
, char *cname
)
738 struct sockaddr_in
*sa
;
741 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
742 memset(a
, 0, sizeof(struct addrinfo
));
746 a
->ai_family
= PF_INET
;
747 a
->ai_socktype
= sock
;
748 a
->ai_protocol
= proto
;
750 a
->ai_addrlen
= sizeof(struct sockaddr_in
);
751 sa
= (struct sockaddr_in
*)malloc(a
->ai_addrlen
);
752 memset(sa
, 0, a
->ai_addrlen
);
753 sa
->sin_len
= a
->ai_addrlen
;
754 sa
->sin_family
= PF_INET
;
757 a
->ai_addr
= (struct sockaddr
*)sa
;
761 len
= strlen(cname
) + 1;
762 a
->ai_canonname
= malloc(len
);
763 memmove(a
->ai_canonname
, cname
, len
);
769 static struct addrinfo
*
770 new_addrinfo_v6(int flags
, int sock
, int proto
, unsigned short port
, struct in6_addr addr
, char *cname
)
773 struct sockaddr_in6
*sa
;
776 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
777 memset(a
, 0, sizeof(struct addrinfo
));
781 a
->ai_family
= PF_INET6
;
782 a
->ai_socktype
= sock
;
783 a
->ai_protocol
= proto
;
785 a
->ai_addrlen
= sizeof(struct sockaddr_in6
);
786 sa
= (struct sockaddr_in6
*)malloc(a
->ai_addrlen
);
787 memset(sa
, 0, a
->ai_addrlen
);
788 sa
->sin6_len
= a
->ai_addrlen
;
789 sa
->sin6_family
= PF_INET6
;
790 sa
->sin6_port
= port
;
791 sa
->sin6_addr
= addr
;
792 a
->ai_addr
= (struct sockaddr
*)sa
;
796 len
= strlen(cname
) + 1;
797 a
->ai_canonname
= malloc(len
);
798 memmove(a
->ai_canonname
, cname
, len
);
805 grok_nodename(const char *nodename
, int family
, struct lu_dict
*q
)
807 if (nodename
== NULL
) return;
808 if (q
== NULL
) return;
810 if (((family
== PF_UNSPEC
) || (family
== PF_INET
)) && is_ipv4_address(nodename
))
812 q
->ipv4
= (char *)nodename
;
814 else if (((family
== PF_UNSPEC
) || (family
== PF_INET6
)) && is_ipv6_address(nodename
))
816 q
->ipv6
= (char *)nodename
;
820 q
->name
= (char *)nodename
;
825 grok_service(const char *servname
, struct lu_dict
*q
)
830 if (servname
== NULL
) return;
831 if (q
== NULL
) return;
834 for (p
= (char *)servname
; (port
== 0) && (*p
!= '\0'); p
++)
836 if (!isdigit(*p
)) port
= -1;
839 if (port
== 0) q
->port
= (char *)servname
;
840 else q
->service
= (char *)servname
;
844 gai_numerichost(struct lu_dict
*h
, struct lu_dict
**list
)
849 if (h
== NULL
) return 0;
850 if (list
== NULL
) return -1;
856 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
857 memset(a
, 0, sizeof(struct lu_dict
));
858 a
->ipv4
= strdup(h
->ipv4
);
859 merge_lu_dict(list
, a
);
865 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
866 memset(a
, 0, sizeof(struct lu_dict
));
867 a
->ipv6
= strdup(h
->ipv6
);
868 merge_lu_dict(list
, a
);
876 gai_numericserv(struct lu_dict
*s
, struct lu_dict
**list
)
880 if (s
== NULL
) return 0;
881 if (s
->port
== NULL
) return 0;
882 if (list
== NULL
) return -1;
884 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
885 memset(a
, 0, sizeof(struct lu_dict
));
886 a
->port
= strdup(s
->port
);
887 merge_lu_dict(list
, a
);
892 merge_addr4(struct in_addr a
, struct sockaddr_in
***l
, int *n
)
895 struct sockaddr_in
*sa4
;
897 for (i
= 0; i
< *n
; i
++)
899 if (((*l
)[i
]->sin_family
== PF_INET
) && (a
.s_addr
== (*l
)[i
]->sin_addr
.s_addr
)) return;
902 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
903 memset(sa4
, 0, sizeof(struct sockaddr_in
));
905 sa4
->sin_family
= PF_INET
;
908 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
909 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
916 merge_addr6(struct in6_addr a
, struct sockaddr_in6
***l
, int *n
)
919 struct sockaddr_in6
*sa6
;
921 for (i
= 0; i
< *n
; i
++)
923 if (((*l
)[i
]->sin6_family
== PF_INET6
)
924 && (a
.__u6_addr
.__u6_addr32
[0] == (*l
)[i
]->sin6_addr
.__u6_addr
.__u6_addr32
[0])) return;
927 sa6
= (struct sockaddr_in6
*)malloc(sizeof(struct sockaddr_in6
));
928 memset(sa6
, 0, sizeof(struct sockaddr_in6
));
930 sa6
->sin6_family
= PF_INET6
;
933 if (*n
== 0) *l
= (struct sockaddr_in6
**)malloc(sizeof(struct sockaddr_in6
*));
934 else *l
= (struct sockaddr_in6
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in6
*));
941 * N.B. We use sim_family to store protocol in the sockaddr.
942 * sockaddr is just used here as a data structure to keep
943 * (port, protocol) pairs.
946 merge_plist(unsigned short port
, unsigned short proto
, struct sockaddr_in
***l
, int *n
)
949 struct sockaddr_in
*sa4
;
951 for (i
= 0; i
< *n
; i
++)
953 if ((port
== (*l
)[i
]->sin_port
) && (proto
== (*l
)[i
]->sin_family
)) return;
956 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
957 memset(sa4
, 0, sizeof(struct sockaddr_in
));
959 sa4
->sin_port
= port
;
960 sa4
->sin_family
= proto
;
962 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
963 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
965 (*l
)[*n
] = (struct sockaddr_in
*)sa4
;
970 * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
971 * From "Random number generators: good ones are hard to find",
972 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
973 * October 1988, p. 1195.
978 static int did_init
= 0;
979 static unsigned int randseed
= 1;
985 gettimeofday(&tv
, NULL
);
986 randseed
= tv
.tv_usec
;
987 if(randseed
== 0) randseed
= 1;
993 t
= 16807 * lo
- 2836 * hi
;
994 if (t
<= 0) t
+= 0x7fffffff;
1000 * Sort by priority and weight.
1003 lu_prioity_sort(struct lu_dict
**l
)
1005 struct lu_dict
*d
, **nodes
;
1006 unsigned int x
, count
, i
, j
, bottom
, *pri
, *wgt
, swap
, t
;
1008 if (*l
== NULL
) return;
1011 for (d
= *l
; d
!= NULL
; d
= d
->lu_next
) count
++;
1012 nodes
= (struct lu_dict
**)malloc(count
* sizeof(struct lu_dict
*));
1013 pri
= (unsigned int *)malloc(count
* sizeof(unsigned int));
1014 wgt
= (unsigned int *)malloc(count
* sizeof(unsigned int));
1016 for (i
= 0, d
= *l
; d
!= NULL
; d
= d
->lu_next
, i
++)
1020 x
= (unsigned int)-1;
1021 if (d
->priority
!= NULL
) x
= atoi(d
->priority
);
1025 if (d
->weight
!= NULL
) x
= atoi(d
->weight
);
1026 wgt
[i
] = (gai_random() % 10000) * x
;
1029 /* bubble sort by priority */
1036 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++)
1038 if (pri
[i
] < pri
[j
]) continue;
1039 if ((pri
[i
] == pri
[j
]) && (wgt
[i
] < wgt
[j
])) continue;
1051 nodes
[i
] = nodes
[j
];
1060 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++) nodes
[i
]->lu_next
= nodes
[j
];
1061 nodes
[bottom
]->lu_next
= NULL
;
1069 * Get service records from lookupd
1072 gai_serv_lookupd(const char *servname
, int proto
, int numericserv
, struct lu_dict
**list
)
1074 struct lu_dict q
, *sub
;
1076 memset(&q
, 0, sizeof(struct lu_dict
));
1080 grok_service(servname
, &q
);
1081 if (q
.service
!= NULL
)
1087 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1091 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1092 else gai_lookupd(&q
, &sub
);
1093 append_lu_dict(list
, sub
);
1094 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1097 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1101 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1102 else gai_lookupd(&q
, &sub
);
1103 append_lu_dict(list
, sub
);
1104 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1112 gai_serv(const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1114 struct lu_dict
*list
, *d
;
1115 int proto
, family
, socktype
, setcname
, wantv4
, wantv6
;
1116 unsigned short port
;
1117 char *loopv4
, *loopv6
;
1122 loopv4
= "127.0.0.1";
1123 loopv6
= "0:0:0:0:0:0:0:1";
1126 proto
= IPPROTO_UNSPEC
;
1131 proto
= hints
->ai_protocol
;
1132 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1133 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1135 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1137 if ((hints
->ai_flags
& AI_PASSIVE
) == 1)
1140 loopv6
= "0:0:0:0:0:0:0:0";
1143 family
= hints
->ai_family
;
1148 if (family
== PF_INET6
) wantv4
= 0;
1149 if (family
== PF_INET
) wantv6
= 0;
1152 gai_serv_lookupd(servname
, proto
, 0, &list
);
1153 if (list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &list
);
1155 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1157 /* We only want records with port and protocol specified */
1158 if ((d
->port
== NULL
) || (d
->protocol
== NULL
)) continue;
1160 port
= htons(atoi(d
->port
));
1161 proto
= IPPROTO_UDP
;
1162 socktype
= SOCK_DGRAM
;
1163 if (!strcasecmp(d
->protocol
, "tcp"))
1165 proto
= IPPROTO_TCP
;
1166 socktype
= SOCK_STREAM
;
1171 inet_aton(loopv4
, &a4
);
1172 a
= new_addrinfo_v4(0, socktype
, proto
, port
, a4
, NULL
);
1173 append_addrinfo(res
, a
);
1178 gai_inet_pton(loopv6
, &a6
);
1179 a
= new_addrinfo_v6(0, socktype
, proto
, port
, a6
, NULL
);
1180 append_addrinfo(res
, a
);
1186 /* Set cname in first result */
1187 if ((setcname
== 1) && (*res
!= NULL
))
1189 if (res
[0]->ai_canonname
== NULL
) res
[0]->ai_canonname
= strdup("localhost");
1199 gai_node_lookupd(const char *nodename
, int family
, int numerichost
, struct lu_dict
**list
)
1203 memset(&q
, 0, sizeof(struct lu_dict
));
1207 grok_nodename(nodename
, family
, &q
);
1208 if (numerichost
) gai_numerichost(&q
, list
);
1209 else gai_lookupd(&q
, list
);
1216 gai_node(const char *nodename
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1218 int i
, family
, numerichost
, setcname
, a_list_count
, wantv4
, wantv6
;
1219 struct lu_dict
*list
, *d
, *t
;
1224 struct sockaddr
**a_list
;
1225 struct sockaddr_in
*sa4
;
1226 struct sockaddr_in6
*sa6
;
1238 family
= hints
->ai_family
;
1239 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1240 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1245 if (family
== PF_INET6
) wantv4
= 0;
1246 if (family
== PF_INET
) wantv6
= 0;
1249 gai_node_lookupd(nodename
, family
, numerichost
, &t
);
1250 if ((t
== NULL
) && (numerichost
== 0))
1252 gai_node_lookupd(nodename
, family
, 1, &t
);
1255 /* If the nodename is an alias, look up the real name */
1257 for (d
= t
; d
!= NULL
; d
= d
->lu_next
)
1259 if (d
->cname
!= NULL
)
1261 if (cname
== NULL
) cname
= strdup(d
->cname
);
1262 gai_node_lookupd(d
->cname
, family
, 0, &t
);
1266 append_lu_dict(&list
, t
);
1268 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1270 /* Check for cname */
1271 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1273 cname
= strdup(d
->name
);
1276 /* Check for ipv4 address */
1277 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1279 inet_aton(d
->ipv4
, &a4
);
1280 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1283 /* Check for ipv6 address */
1284 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1286 gai_inet_pton(d
->ipv6
, &a6
);
1287 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1291 /* Last chance for a name */
1292 for (d
= list
; (cname
== NULL
) && (d
!= NULL
); d
= d
->lu_next
)
1294 if (d
->name
!= NULL
) cname
= strdup(d
->name
);
1299 for (i
= 0; i
< a_list_count
; i
++)
1301 if (a_list
[i
]->sa_family
== PF_INET
)
1303 sa4
= (struct sockaddr_in
*)a_list
[i
];
1304 a
= new_addrinfo_v4(0, 0, 0, 0, sa4
->sin_addr
, NULL
);
1305 append_addrinfo(res
, a
);
1307 else if (a_list
[i
]->sa_family
== PF_INET6
)
1309 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1310 a
= new_addrinfo_v6(0, 0, 0, 0, sa6
->sin6_addr
, NULL
);
1311 append_addrinfo(res
, a
);
1317 if (a_list_count
> 0) free(a_list
);
1319 /* Set cname in first result */
1320 if ((setcname
== 1) && (*res
!= NULL
))
1322 if (res
[0]->ai_canonname
== NULL
)
1324 res
[0]->ai_canonname
= cname
;
1329 if (cname
!= NULL
) free(cname
);
1335 * Find a service+node.
1338 gai_nodeserv_lookupd(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct lu_dict
**list
)
1340 struct lu_dict q
, *sub
;
1344 proto
= IPPROTO_UNSPEC
;
1348 if (hints
->ai_flags
& AI_NUMERICHOST
) return;
1349 family
= hints
->ai_family
;
1351 proto
= hints
->ai_protocol
;
1352 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1353 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1356 memset(&q
, 0, sizeof(struct lu_dict
));
1360 grok_nodename(nodename
, family
, &q
);
1361 grok_service(servname
, &q
);
1363 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1367 gai_lookupd(&q
, &sub
);
1368 append_lu_dict(list
, sub
);
1369 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1372 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1376 gai_lookupd(&q
, &sub
);
1377 append_lu_dict(list
, sub
);
1378 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1383 gai_node_pp(const char *nodename
, unsigned short port
, int proto
, int family
, int setcname
, struct addrinfo
**res
)
1385 struct lu_dict
*list
, *d
;
1386 int i
, wantv4
, wantv6
, a_list_count
, socktype
;
1388 struct sockaddr
**a_list
;
1391 struct sockaddr_in
*sa4
;
1392 struct sockaddr_in6
*sa6
;
1395 socktype
= SOCK_UNSPEC
;
1396 if (proto
== IPPROTO_UDP
) socktype
= SOCK_DGRAM
;
1397 if (proto
== IPPROTO_TCP
) socktype
= SOCK_STREAM
;
1403 if (family
== PF_INET6
) wantv4
= 0;
1404 if (family
== PF_INET
) wantv6
= 0;
1406 /* Resolve node name */
1408 gai_node_lookupd(nodename
, family
, 0, &list
);
1411 gai_node_lookupd(nodename
, family
, 1, &list
);
1414 /* Resolve aliases */
1415 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1417 if (d
->cname
!= NULL
)
1419 if (cname
== NULL
) cname
= strdup(d
->cname
);
1420 gai_node_lookupd(d
->cname
, family
, 0, &list
);
1426 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1428 /* Check for cname */
1429 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1431 cname
= strdup(d
->name
);
1434 /* Check for ipv4 address */
1435 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1437 inet_aton(d
->ipv4
, &a4
);
1438 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1441 /* Check for ipv6 address */
1442 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1444 gai_inet_pton(d
->ipv6
, &a6
);
1445 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1451 for (i
= 0; i
< a_list_count
; i
++)
1453 if (a_list
[i
]->sa_family
== PF_INET
)
1455 sa4
= (struct sockaddr_in
*)a_list
[i
];
1456 a
= new_addrinfo_v4(0, socktype
, proto
, port
, sa4
->sin_addr
, NULL
);
1457 append_addrinfo(res
, a
);
1459 else if (a_list
[i
]->sa_family
== PF_INET6
)
1461 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1462 a
= new_addrinfo_v6(0, socktype
, proto
, port
, sa6
->sin6_addr
, NULL
);
1463 append_addrinfo(res
, a
);
1469 if (a_list_count
> 0) free(a_list
);
1471 /* Set cname in first result */
1472 if ((setcname
== 1) && (*res
!= NULL
))
1474 if (res
[0]->ai_canonname
== NULL
)
1476 res
[0]->ai_canonname
= cname
;
1481 if (cname
!= NULL
) free(cname
);
1485 gai_nodeserv(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1487 struct lu_dict
*srv_list
, *node_list
, *s
, *n
;
1488 int numerichost
, family
, proto
, setcname
;
1489 int wantv4
, wantv6
, i
, j
, gotmx
, p_list_count
;
1490 unsigned short port
;
1492 struct sockaddr
**p_list
;
1493 struct sockaddr_in
*sa4
;
1497 proto
= IPPROTO_UNSPEC
;
1505 family
= hints
->ai_family
;
1506 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1507 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1509 proto
= hints
->ai_protocol
;
1510 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1511 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1514 if (family
== PF_INET6
) wantv4
= 0;
1515 if (family
== PF_INET
) wantv6
= 0;
1517 /* First check for this particular host / service (e.g. DNS_SRV) */
1520 gai_nodeserv_lookupd(nodename
, servname
, hints
, &srv_list
);
1521 lu_prioity_sort(&srv_list
);
1523 if (srv_list
!= NULL
)
1525 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1527 if (s
->port
== NULL
) continue;
1528 if (s
->protocol
== NULL
) continue;
1530 i
= htons(atoi(s
->port
));
1532 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1533 gai_node_pp(s
->target
, i
, j
, family
, setcname
, res
);
1536 free_lu_dict(srv_list
);
1541 * Special case for smtp: collect mail_exchangers.
1546 if (!strcmp(servname
, "smtp"))
1548 gai_node_lookupd(nodename
, family
, numerichost
, &node_list
);
1549 if ((node_list
== NULL
) && (numerichost
== 0))
1551 gai_node_lookupd(nodename
, family
, 1, &node_list
);
1554 lu_prioity_sort(&node_list
);
1556 for (n
= node_list
; (n
!= NULL
) && (gotmx
== 0); n
= n
->lu_next
)
1558 if (n
->mx
!= NULL
) gotmx
= 1;
1561 if ((gotmx
== 0) && (node_list
!= NULL
))
1563 free_lu_dict(node_list
);
1569 * Look up service, look up node, and combine port/proto with node addresses.
1572 gai_serv_lookupd(servname
, proto
, 0, &srv_list
);
1573 if (srv_list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &srv_list
);
1574 if (srv_list
== NULL
) return 0;
1577 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1579 if (s
->port
== NULL
) continue;
1580 if (s
->protocol
== NULL
) continue;
1582 i
= htons(atoi(s
->port
));
1584 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1586 merge_plist(i
, j
, (struct sockaddr_in
***)&p_list
, &p_list_count
);
1589 free_lu_dict(srv_list
);
1591 for (i
= 0; i
< p_list_count
; i
++)
1593 sa4
= (struct sockaddr_in
*)p_list
[i
];
1594 port
= sa4
->sin_port
;
1595 /* N.B. sin_family is overloaded */
1596 proto
= sa4
->sin_family
;
1600 for (n
= node_list
; n
!= NULL
; n
= n
->lu_next
)
1602 if (n
->mx
!= NULL
) gai_node_pp(n
->mx
, port
, proto
, family
, setcname
, res
);
1607 gai_node_pp(nodename
, port
, proto
, family
, setcname
, res
);
1613 if (node_list
!= NULL
) free_lu_dict(node_list
);
1615 if (p_list_count
> 0) free(p_list
);
1620 getaddrinfo(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1623 struct lu_dict
*list
;
1625 if (res
== NULL
) return 0;
1630 if ((nodename
== NULL
) && (servname
== NULL
)) return EAI_NONAME
;
1635 if (hints
->ai_addrlen
!= 0) return EAI_BADHINTS
;
1636 if (hints
->ai_canonname
!= NULL
) return EAI_BADHINTS
;
1637 if (hints
->ai_addr
!= NULL
) return EAI_BADHINTS
;
1638 if (hints
->ai_next
!= NULL
) return EAI_BADHINTS
;
1640 /* Check for supported protocol family */
1641 if (gai_family_type_check(hints
->ai_family
) != 0) return EAI_FAMILY
;
1643 /* Check for supported socket */
1644 if (gai_socket_type_check(hints
->ai_socktype
) != 0) return EAI_BADHINTS
;
1646 /* Check for supported protocol */
1647 if (gai_protocol_type_check(hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1649 /* Check that socket type is compatible with protocol */
1650 if (gai_socket_protocol_type_check(hints
->ai_socktype
, hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1655 if (nodename
== NULL
)
1657 /* If node is NULL, find service */
1658 status
= gai_serv(servname
, hints
, res
);
1659 if ((status
== 0) && (*res
== NULL
)) status
= EAI_NODATA
;
1663 if (servname
== NULL
)
1665 /* If service is NULL, find node */
1666 status
= gai_node(nodename
, hints
, res
);
1667 if ((status
== 0) && (*res
== NULL
)) status
= EAI_NODATA
;
1671 /* Find node + service */
1672 status
= gai_nodeserv(nodename
, servname
, hints
, res
);
1673 if ((status
== 0) && (*res
== NULL
)) status
= EAI_NODATA
;