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>
44 #define IPPROTO_UNSPEC 0
46 #define LONG_STRING_LENGTH 8192
47 #define _LU_MAXLUSTRLEN 256
49 static char *LOOKUPD_NAME
= "lookup daemon";
51 extern int _lookup_link();
52 extern int _lookup_one();
53 extern int _lookup_all();
70 struct lu_dict
*lu_next
;
83 static int supported_family
[] =
89 static int supported_family_count
= 3;
91 static int supported_socket
[] =
97 static int supported_socket_count
= 3;
99 static int supported_protocol
[] =
105 static int supported_protocol_count
= 3;
107 static int supported_socket_protocol_pair
[] =
109 SOCK_UNSPEC
, IPPROTO_UNSPEC
,
110 SOCK_UNSPEC
, IPPROTO_UDP
,
111 SOCK_UNSPEC
, IPPROTO_TCP
,
112 SOCK_DGRAM
, IPPROTO_UNSPEC
,
113 SOCK_DGRAM
, IPPROTO_UDP
,
114 SOCK_STREAM
, IPPROTO_UNSPEC
,
115 SOCK_STREAM
, IPPROTO_TCP
117 static int supported_socket_protocol_pair_count
= 7;
120 gai_family_type_check(int f
)
124 for (i
= 0; i
< supported_family_count
; i
++)
126 if (f
== supported_family
[i
]) return 0;
133 gai_socket_type_check(int s
)
137 for (i
= 0; i
< supported_socket_count
; i
++)
139 if (s
== supported_socket
[i
]) return 0;
146 gai_protocol_type_check(int p
)
150 for (i
= 0; i
< supported_protocol_count
; i
++)
152 if (p
== supported_protocol
[i
]) return 0;
159 gai_socket_protocol_type_check(int s
, int p
)
163 for (i
= 0, j
= 0; i
< supported_socket_protocol_pair_count
; i
++, j
+=2)
165 ss
= supported_socket_protocol_pair
[j
];
166 sp
= supported_socket_protocol_pair
[j
+1];
167 if ((s
== ss
) && (p
== sp
)) return 0;
174 gai_inet_pton(const char *s
, struct in6_addr
*a6
)
180 if (s
== NULL
) return 0;
181 if (a6
== NULL
) return 0;
183 for (ncolon
= 0; ncolon
< 8; ncolon
++) x
[ncolon
] = 0;
188 for (p
= (char *)s
; *p
!= '\0'; p
++)
192 if (run
> 0) sscanf(buf
, "%hx", &(x
[ncolon
]));
194 if (ncolon
> 7) return 0;
198 else if (((*p
>= '0') && (*p
<= '9')) || ((*p
>= 'a') && (*p
<= 'f')) || ((*p
>= 'A') && (*p
<= 'F')))
202 if (run
> 4) return 0;
206 if (ncolon
!= 7) return 0;
208 if (run
> 0) sscanf(buf
, "%hx", &(x
[7]));
210 a6
->__u6_addr
.__u6_addr32
[0] = (x
[0] << 16) + x
[1];
211 a6
->__u6_addr
.__u6_addr32
[1] = (x
[2] << 16) + x
[3];
212 a6
->__u6_addr
.__u6_addr32
[2] = (x
[4] << 16) + x
[5];
213 a6
->__u6_addr
.__u6_addr32
[3] = (x
[6] << 16) + x
[7];
219 gai_inet_ntop(struct in6_addr a
)
221 static char buf
[128];
229 p
= (char *)&a
.__u6_addr
.__u6_addr32
;
230 for (i
= 0; i
< 8; i
++, x
+= 1)
234 sprintf(t
, "%hx", x
);
236 if (i
< 7) strcat(buf
, ":");
243 gai_strerror(int err
)
247 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
248 case EAI_AGAIN
: return "Temporary failure in name resolution";
249 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
250 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
251 case EAI_FAMILY
: return "ai_family not supported";
252 case EAI_MEMORY
: return "Memory allocation failure";
253 case EAI_NODATA
: return "No address associated with nodename";
254 case EAI_NONAME
: return "nodename nor servname provided, or not known";
255 case EAI_SERVICE
: return "servname not supported for ai_socktype";
256 case EAI_SOCKTYPE
: return "ai_socktype not supported";
257 case EAI_SYSTEM
: return "System error";
258 case EAI_BADHINTS
: return "Bad hints";
259 case EAI_PROTOCOL
: return "ai_protocol not supported";
262 return "Unknown error";
266 is_ipv4_address(const char *s
)
270 if (s
== NULL
) return 0;
271 return inet_aton(s
, &a
);
275 is_ipv6_address(const char *s
)
279 if (s
== NULL
) return 0;
280 return gai_inet_pton(s
, &a
);
284 append_addrinfo(struct addrinfo
**l
, struct addrinfo
*a
)
288 if (l
== NULL
) return;
289 if (a
== NULL
) return;
298 while (x
->ai_next
!= NULL
) x
= x
->ai_next
;
303 free_lu_dict(struct lu_dict
*d
)
305 struct lu_dict
*next
;
310 if (d
->type
!= NULL
) free(d
->type
);
311 if (d
->name
!= NULL
) free(d
->name
);
312 if (d
->cname
!= NULL
) free(d
->cname
);
313 if (d
->mx
!= NULL
) free(d
->mx
);
314 if (d
->ipv4
!= NULL
) free(d
->ipv4
);
315 if (d
->ipv6
!= NULL
) free(d
->ipv6
);
316 if (d
->service
!= NULL
) free(d
->service
);
317 if (d
->port
!= NULL
) free(d
->port
);
318 if (d
->protocol
!= NULL
) free(d
->protocol
);
319 if (d
->target
!= NULL
) free(d
->target
);
320 if (d
->priority
!= NULL
) free(d
->priority
);
321 if (d
->weight
!= NULL
) free(d
->weight
);
328 append_lu_dict(struct lu_dict
**l
, struct lu_dict
*d
)
332 if (l
== NULL
) return;
333 if (d
== NULL
) return;
342 while (x
->lu_next
!= NULL
) x
= x
->lu_next
;
347 * We collect values for the following keys:
361 lookupd_process_dictionary(XDR
*inxdr
, struct lu_dict
**l
)
363 int i
, nkeys
, j
, nvals
;
368 if (!xdr_int(inxdr
, &nkeys
)) return;
370 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
371 memset(d
, 0, sizeof(struct lu_dict
));
373 for (i
= 0; i
< nkeys
; i
++)
377 if (!xdr_string(inxdr
, &key
, LONG_STRING_LENGTH
))
384 if (!strcmp(key
, "name")) addme
= LU_NAME
;
385 else if (!strcmp(key
, "cname")) addme
= LU_CNAME
;
386 else if (!strcmp(key
, "mail_exchanger")) addme
= LU_MX
;
387 else if (!strcmp(key
, "ip_address")) addme
= LU_IPV4
;
388 else if (!strcmp(key
, "ipv6_address")) addme
= LU_IPV6
;
389 else if (!strcmp(key
, "port")) addme
= LU_PORT
;
390 else if (!strcmp(key
, "target")) addme
= LU_TARGET
;
391 else if (!strcmp(key
, "priority")) addme
= LU_PRIORITY
;
392 else if (!strcmp(key
, "preference")) addme
= LU_PRIORITY
;
393 else if (!strcmp(key
, "weight")) addme
= LU_WEIGHT
;
396 if (!xdr_int(inxdr
, &nvals
))
402 for (j
= 0; j
< nvals
; j
++)
405 if (!xdr_string(inxdr
, &val
, LONG_STRING_LENGTH
))
411 if (addme
== 0) free(val
);
412 else if (addme
== LU_NAME
) d
->name
= val
;
413 else if (addme
== LU_CNAME
) d
->cname
= val
;
414 else if (addme
== LU_MX
) d
->mx
= val
;
415 else if (addme
== LU_IPV4
) d
->ipv4
= val
;
416 else if (addme
== LU_IPV6
) d
->ipv6
= val
;
417 else if (addme
== LU_PORT
) d
->port
= val
;
418 else if (addme
== LU_TARGET
) d
->target
= val
;
419 else if (addme
== LU_PRIORITY
) d
->priority
= val
;
420 else if (addme
== LU_WEIGHT
) d
->weight
= val
;
422 if (addme
!= 0) d
->count
++;
427 append_lu_dict(l
, d
);
431 lookupd_port(char *name
)
434 kern_return_t status
;
436 status
= bootstrap_look_up(bootstrap_port
, name
, &p
);
437 if (status
== KERN_SUCCESS
) return p
;
438 return MACH_PORT_NULL
;
442 encode_kv(XDR
*x
, char *k
, char *v
)
446 if (!xdr_string(x
, &k
, _LU_MAXLUSTRLEN
)) return 1;
447 if (!xdr_int(x
, &n
)) return 1;
448 if (!xdr_string(x
, &v
, _LU_MAXLUSTRLEN
)) return 1;
454 gai_files(struct lu_dict
*q
, struct lu_dict
**list
)
463 if (!strcmp(q
->type
, "service"))
468 s
= getservbyname(q
->name
, q
->protocol
);
470 else if (q
->port
!= NULL
)
472 port
= atoi(q
->port
);
473 s
= getservbyport(port
, q
->protocol
);
475 if (s
== NULL
) return 0;
477 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
478 memset(d
, 0, sizeof(struct lu_dict
));
480 if (s
->s_name
!= NULL
) d
->name
= strdup(s
->s_name
);
481 sprintf(str
, "%u", ntohl(s
->s_port
));
482 d
->port
= strdup(str
);
483 if (s
->s_proto
!= NULL
) d
->protocol
= strdup(s
->s_proto
);
485 append_lu_dict(list
, d
);
489 else if (!strcmp(q
->type
, "host"))
494 h
= gethostbyname(q
->name
);
496 else if (q
->ipv4
!= NULL
)
498 if (inet_aton(q
->ipv4
, &a4
) == 0) return -1;
499 h
= gethostbyaddr((char *)&a4
, sizeof(struct in_addr
), PF_INET
);
503 /* gethostbyaddr for IPV6? */
507 if (h
== NULL
) return 0;
509 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
511 d
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
512 memset(d
, 0, sizeof(struct lu_dict
));
514 if (h
->h_name
!= NULL
) d
->name
= strdup(h
->h_name
);
515 memmove((void *)&a4
.s_addr
, h
->h_addr_list
[i
], h
->h_length
);
517 sprintf(str
, "%s", inet_ntoa(a4
));
518 d
->ipv4
= strdup(str
);
520 append_lu_dict(list
, d
);
529 gai_lookupd(struct lu_dict
*q
, struct lu_dict
**list
)
536 char databuf
[_LU_MAXLUSTRLEN
* BYTES_PER_XDR_UNIT
];
538 kern_return_t status
;
539 mach_port_t server_port
;
541 if (q
== NULL
) return 0;
542 if (q
->count
== 0) return 0;
543 if (q
->type
== NULL
) return 0;
545 if (list
== NULL
) return -1;
547 server_port
= lookupd_port(LOOKUPD_NAME
);
548 if (server_port
== NULL
) return gai_files(q
, list
);
550 status
= _lookup_link(server_port
, "query", &proc
);
551 if (status
!= KERN_SUCCESS
) return gai_files(q
, list
);
553 xdrmem_create(&outxdr
, databuf
, sizeof(databuf
), XDR_ENCODE
);
555 /* Encode attribute count */
557 if (!xdr_int(&outxdr
, &na
))
559 xdr_destroy(&outxdr
);
563 if (encode_kv(&outxdr
, "_lookup_category", q
->type
) != 0)
565 xdr_destroy(&outxdr
);
571 if (encode_kv(&outxdr
, "name", q
->name
) != 0)
573 xdr_destroy(&outxdr
);
580 if (encode_kv(&outxdr
, "ip_address", q
->ipv4
) != 0)
582 xdr_destroy(&outxdr
);
589 if (encode_kv(&outxdr
, "ipv6_address", q
->ipv6
) != 0)
591 xdr_destroy(&outxdr
);
596 if (q
->service
!= NULL
)
598 if (encode_kv(&outxdr
, "service", q
->service
) != 0)
600 xdr_destroy(&outxdr
);
607 if (encode_kv(&outxdr
, "port", q
->port
) != 0)
609 xdr_destroy(&outxdr
);
614 if (q
->protocol
!= NULL
)
616 if (encode_kv(&outxdr
, "protocol", q
->protocol
) != 0)
618 xdr_destroy(&outxdr
);
626 n
= xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
;
627 status
= _lookup_all(server_port
, proc
, databuf
, n
, &listbuf
, &datalen
);
628 if (status
!= KERN_SUCCESS
)
630 xdr_destroy(&outxdr
);
634 xdr_destroy(&outxdr
);
637 /* NOTDEF because OOL buffers are counted in bytes with untyped IPC */
638 datalen
*= BYTES_PER_XDR_UNIT
;
640 xdrmem_create(&inxdr
, listbuf
, datalen
, XDR_DECODE
);
642 if (!xdr_int(&inxdr
, &n
))
648 for (i
= 0; i
< n
; i
++)
650 lookupd_process_dictionary(&inxdr
, list
);
655 vm_deallocate(mach_task_self(), (vm_address_t
)listbuf
, datalen
);
661 freeaddrinfo(struct addrinfo
*a
)
663 struct addrinfo
*next
;
668 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
669 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
675 static struct addrinfo
*
676 new_addrinfo_v4(int flags
, int sock
, int proto
, unsigned short port
, struct in_addr addr
, char *cname
)
679 struct sockaddr_in
*sa
;
682 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
683 memset(a
, 0, sizeof(struct addrinfo
));
687 a
->ai_family
= PF_INET
;
688 a
->ai_socktype
= sock
;
689 a
->ai_protocol
= proto
;
691 a
->ai_addrlen
= sizeof(struct sockaddr_in
);
692 sa
= (struct sockaddr_in
*)malloc(a
->ai_addrlen
);
693 memset(sa
, 0, a
->ai_addrlen
);
694 sa
->sin_len
= a
->ai_addrlen
;
695 sa
->sin_family
= PF_INET
;
698 a
->ai_addr
= (struct sockaddr
*)sa
;
702 len
= strlen(cname
) + 1;
703 a
->ai_canonname
= malloc(len
);
704 memmove(a
->ai_canonname
, cname
, len
);
710 static struct addrinfo
*
711 new_addrinfo_v6(int flags
, int sock
, int proto
, unsigned short port
, struct in6_addr addr
, char *cname
)
714 struct sockaddr_in6
*sa
;
717 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
718 memset(a
, 0, sizeof(struct addrinfo
));
722 a
->ai_family
= PF_INET6
;
723 a
->ai_socktype
= sock
;
724 a
->ai_protocol
= proto
;
726 a
->ai_addrlen
= sizeof(struct sockaddr_in6
);
727 sa
= (struct sockaddr_in6
*)malloc(a
->ai_addrlen
);
728 memset(sa
, 0, a
->ai_addrlen
);
729 sa
->sin6_len
= a
->ai_addrlen
;
730 sa
->sin6_family
= PF_INET6
;
731 sa
->sin6_port
= port
;
732 sa
->sin6_addr
= addr
;
733 a
->ai_addr
= (struct sockaddr
*)sa
;
737 len
= strlen(cname
) + 1;
738 a
->ai_canonname
= malloc(len
);
739 memmove(a
->ai_canonname
, cname
, len
);
746 grok_nodename(const char *nodename
, int family
, struct lu_dict
*q
)
748 if (nodename
== NULL
) return;
749 if (q
== NULL
) return;
751 if (((family
== PF_UNSPEC
) || (family
== PF_INET
)) && is_ipv4_address(nodename
))
753 q
->ipv4
= (char *)nodename
;
755 else if (((family
== PF_UNSPEC
) || (family
== PF_INET6
)) && is_ipv6_address(nodename
))
757 q
->ipv6
= (char *)nodename
;
761 q
->name
= (char *)nodename
;
766 grok_service(const char *servname
, struct lu_dict
*q
)
771 if (servname
== NULL
) return;
772 if (q
== NULL
) return;
775 for (p
= (char *)servname
; (port
== 0) && (*p
!= '\0'); p
++)
777 if (!isdigit(*p
)) port
= -1;
780 if (port
== 0) port
= atoi(servname
);
781 if ((port
> 0) && (port
< 0xffff)) q
->port
= (char *)servname
;
782 else q
->service
= (char *)servname
;
786 gai_numerichost(struct lu_dict
*h
, struct lu_dict
**list
)
791 if (h
== NULL
) return 0;
792 if (list
== NULL
) return -1;
798 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
799 memset(a
, 0, sizeof(struct lu_dict
));
800 a
->ipv4
= strdup(h
->ipv4
);
801 append_lu_dict(list
, a
);
807 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
808 memset(a
, 0, sizeof(struct lu_dict
));
809 a
->ipv6
= strdup(h
->ipv6
);
810 append_lu_dict(list
, a
);
818 gai_numericserv(struct lu_dict
*s
, struct lu_dict
**list
)
822 if (s
== NULL
) return 0;
823 if (s
->port
== NULL
) return 0;
824 if (list
== NULL
) return -1;
826 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
827 memset(a
, 0, sizeof(struct lu_dict
));
828 a
->port
= strdup(s
->port
);
829 append_lu_dict(list
, a
);
834 merge_addr4(struct in_addr a
, struct sockaddr_in
***l
, int *n
)
837 struct sockaddr_in
*sa4
;
839 for (i
= 0; i
< *n
; i
++)
841 if (((*l
)[i
]->sin_family
== PF_INET
) && (a
.s_addr
== (*l
)[i
]->sin_addr
.s_addr
)) return;
844 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
845 memset(sa4
, 0, sizeof(struct sockaddr_in
));
847 sa4
->sin_family
= PF_INET
;
850 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
851 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
858 merge_addr6(struct in6_addr a
, struct sockaddr_in6
***l
, int *n
)
861 struct sockaddr_in6
*sa6
;
863 for (i
= 0; i
< *n
; i
++)
865 if (((*l
)[i
]->sin6_family
== PF_INET6
)
866 && (a
.__u6_addr
.__u6_addr32
[0] == (*l
)[i
]->sin6_addr
.__u6_addr
.__u6_addr32
[0])) return;
869 sa6
= (struct sockaddr_in6
*)malloc(sizeof(struct sockaddr_in6
));
870 memset(sa6
, 0, sizeof(struct sockaddr_in6
));
872 sa6
->sin6_family
= PF_INET6
;
875 if (*n
== 0) *l
= (struct sockaddr_in6
**)malloc(sizeof(struct sockaddr_in6
*));
876 else *l
= (struct sockaddr_in6
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in6
*));
883 * N.B. We use sim_family to store protocol in the sockaddr.
884 * sockaddr is just used here as a data structure to keep
885 * (port, protocol) pairs.
888 merge_plist(unsigned short port
, unsigned short proto
, struct sockaddr_in
***l
, int *n
)
891 struct sockaddr_in
*sa4
;
893 for (i
= 0; i
< *n
; i
++)
895 if ((port
== (*l
)[i
]->sin_port
) && (proto
== (*l
)[i
]->sin_family
)) return;
898 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
899 memset(sa4
, 0, sizeof(struct sockaddr_in
));
901 sa4
->sin_port
= port
;
902 sa4
->sin_family
= proto
;
904 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
905 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
907 (*l
)[*n
] = (struct sockaddr_in
*)sa4
;
912 * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
913 * From "Random number generators: good ones are hard to find",
914 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
915 * October 1988, p. 1195.
920 static int did_init
= 0;
921 static unsigned int randseed
= 1;
927 gettimeofday(&tv
, NULL
);
928 randseed
= tv
.tv_usec
;
929 if(randseed
== 0) randseed
= 1;
935 t
= 16807 * lo
- 2836 * hi
;
936 if (t
<= 0) t
+= 0x7fffffff;
942 * Sort by priority and weight.
945 lu_prioity_sort(struct lu_dict
**l
)
947 struct lu_dict
*d
, **nodes
;
948 unsigned int x
, count
, i
, j
, bottom
, *pri
, *wgt
, swap
, t
;
950 if (*l
== NULL
) return;
953 for (d
= *l
; d
!= NULL
; d
= d
->lu_next
) count
++;
954 nodes
= (struct lu_dict
**)malloc(count
* sizeof(struct lu_dict
*));
955 pri
= (unsigned int *)malloc(count
* sizeof(unsigned int));
956 wgt
= (unsigned int *)malloc(count
* sizeof(unsigned int));
958 for (i
= 0, d
= *l
; d
!= NULL
; d
= d
->lu_next
, i
++)
962 x
= (unsigned int)-1;
963 if (d
->priority
!= NULL
) x
= atoi(d
->priority
);
967 if (d
->weight
!= NULL
) x
= atoi(d
->weight
);
968 wgt
[i
] = (gai_random() % 10000) * x
;
971 /* bubble sort by priority */
978 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++)
980 if (pri
[i
] < pri
[j
]) continue;
981 if ((pri
[i
] == pri
[j
]) && (wgt
[i
] < wgt
[j
])) continue;
1002 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++) nodes
[i
]->lu_next
= nodes
[j
];
1003 nodes
[bottom
]->lu_next
= NULL
;
1011 * Get service records from lookupd
1014 gai_serv_lookupd(const char *servname
, int proto
, int numericserv
, struct lu_dict
**list
)
1016 struct lu_dict q
, *sub
;
1018 memset(&q
, 0, sizeof(struct lu_dict
));
1022 grok_service(servname
, &q
);
1023 if (q
.service
!= NULL
)
1029 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1033 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1034 else gai_lookupd(&q
, &sub
);
1035 append_lu_dict(list
, sub
);
1036 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1039 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1043 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1044 else gai_lookupd(&q
, &sub
);
1045 append_lu_dict(list
, sub
);
1046 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1054 gai_serv(const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1056 struct lu_dict
*list
, *d
;
1057 int proto
, family
, socktype
, setcname
, wantv4
, wantv6
;
1058 unsigned short port
;
1059 char *loopv4
, *loopv6
;
1064 loopv4
= "127.0.0.1";
1065 loopv6
= "0:0:0:0:0:0:0:1";
1068 proto
= IPPROTO_UNSPEC
;
1073 proto
= hints
->ai_protocol
;
1074 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1075 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1077 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1079 if ((hints
->ai_flags
& AI_PASSIVE
) == 1)
1082 loopv6
= "0:0:0:0:0:0:0:0";
1085 family
= hints
->ai_family
;
1090 if (family
== PF_INET6
) wantv4
= 0;
1091 if (family
== PF_INET
) wantv6
= 0;
1094 gai_serv_lookupd(servname
, proto
, 0, &list
);
1095 if (list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &list
);
1097 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1099 /* We only want records with port and protocol specified */
1100 if ((d
->port
== NULL
) || (d
->protocol
== NULL
)) continue;
1102 port
= htons(atoi(d
->port
));
1103 proto
= IPPROTO_UDP
;
1104 socktype
= SOCK_DGRAM
;
1105 if (!strcasecmp(d
->protocol
, "tcp"))
1107 proto
= IPPROTO_TCP
;
1108 socktype
= SOCK_STREAM
;
1113 inet_aton(loopv4
, &a4
);
1114 a
= new_addrinfo_v4(0, socktype
, proto
, port
, a4
, NULL
);
1115 append_addrinfo(res
, a
);
1120 gai_inet_pton(loopv6
, &a6
);
1121 a
= new_addrinfo_v6(0, socktype
, proto
, port
, a6
, NULL
);
1122 append_addrinfo(res
, a
);
1128 /* Set cname in first result */
1129 if ((setcname
== 1) && (*res
!= NULL
))
1131 if (res
[0]->ai_canonname
== NULL
) res
[0]->ai_canonname
= strdup("localhost");
1141 gai_node_lookupd(const char *nodename
, int family
, int numerichost
, struct lu_dict
**list
)
1145 memset(&q
, 0, sizeof(struct lu_dict
));
1149 grok_nodename(nodename
, family
, &q
);
1150 if (numerichost
) gai_numerichost(&q
, list
);
1151 else gai_lookupd(&q
, list
);
1158 gai_node(const char *nodename
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1160 int i
, family
, numerichost
, setcname
, a_list_count
, wantv4
, wantv6
;
1161 struct lu_dict
*list
, *d
, *t
;
1166 struct sockaddr
**a_list
;
1167 struct sockaddr_in
*sa4
;
1168 struct sockaddr_in6
*sa6
;
1180 family
= hints
->ai_family
;
1181 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1182 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1187 if (family
== PF_INET6
) wantv4
= 0;
1188 if (family
== PF_INET
) wantv6
= 0;
1191 gai_node_lookupd(nodename
, family
, numerichost
, &t
);
1192 if ((t
== NULL
) && (numerichost
== 0))
1194 gai_node_lookupd(nodename
, family
, 1, &t
);
1197 /* If the nodename is an alias, look up the real name */
1199 for (d
= t
; d
!= NULL
; d
= d
->lu_next
)
1201 if (d
->cname
!= NULL
)
1203 if (cname
== NULL
) cname
= strdup(d
->cname
);
1204 gai_node_lookupd(d
->cname
, family
, 0, &t
);
1208 append_lu_dict(&list
, t
);
1210 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1212 /* Check for cname */
1213 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1215 cname
= strdup(d
->name
);
1218 /* Check for ipv4 address */
1219 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1221 inet_aton(d
->ipv4
, &a4
);
1222 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1225 /* Check for ipv6 address */
1226 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1228 gai_inet_pton(d
->ipv6
, &a6
);
1229 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1233 /* Last chance for a name */
1234 for (d
= list
; (cname
== NULL
) && (d
!= NULL
); d
= d
->lu_next
)
1236 if (d
->name
!= NULL
) cname
= strdup(d
->name
);
1241 for (i
= 0; i
< a_list_count
; i
++)
1243 if (a_list
[i
]->sa_family
== PF_INET
)
1245 sa4
= (struct sockaddr_in
*)a_list
[i
];
1246 a
= new_addrinfo_v4(0, 0, 0, 0, sa4
->sin_addr
, NULL
);
1247 append_addrinfo(res
, a
);
1249 else if (a_list
[i
]->sa_family
== PF_INET6
)
1251 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1252 a
= new_addrinfo_v6(0, 0, 0, 0, sa6
->sin6_addr
, NULL
);
1253 append_addrinfo(res
, a
);
1259 if (a_list_count
> 0) free(a_list
);
1261 /* Set cname in first result */
1262 if ((setcname
== 1) && (*res
!= NULL
))
1264 if (res
[0]->ai_canonname
== NULL
)
1266 res
[0]->ai_canonname
= cname
;
1271 if (cname
!= NULL
) free(cname
);
1277 * Find a service+node.
1280 gai_nodeserv_lookupd(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct lu_dict
**list
)
1282 struct lu_dict q
, *sub
;
1286 proto
= IPPROTO_UNSPEC
;
1290 if (hints
->ai_flags
& AI_NUMERICHOST
) return;
1291 family
= hints
->ai_family
;
1293 proto
= hints
->ai_protocol
;
1294 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1295 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1298 memset(&q
, 0, sizeof(struct lu_dict
));
1302 grok_nodename(nodename
, family
, &q
);
1303 grok_service(servname
, &q
);
1305 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1309 gai_lookupd(&q
, &sub
);
1310 append_lu_dict(list
, sub
);
1311 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1314 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1318 gai_lookupd(&q
, &sub
);
1319 append_lu_dict(list
, sub
);
1320 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1325 gai_node_pp(const char *nodename
, unsigned short port
, int proto
, int family
, int setcname
, struct addrinfo
**res
)
1327 struct lu_dict
*list
, *d
;
1328 int i
, wantv4
, wantv6
, a_list_count
, socktype
;
1330 struct sockaddr
**a_list
;
1333 struct sockaddr_in
*sa4
;
1334 struct sockaddr_in6
*sa6
;
1337 socktype
= SOCK_UNSPEC
;
1338 if (proto
== IPPROTO_UDP
) socktype
= SOCK_DGRAM
;
1339 if (proto
== IPPROTO_TCP
) socktype
= SOCK_STREAM
;
1345 if (family
== PF_INET6
) wantv4
= 0;
1346 if (family
== PF_INET
) wantv6
= 0;
1348 /* Resolve node name */
1350 gai_node_lookupd(nodename
, family
, 0, &list
);
1353 gai_node_lookupd(nodename
, family
, 1, &list
);
1356 /* Resolve aliases */
1357 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1359 if (d
->cname
!= NULL
)
1361 cname
= strdup(d
->cname
);
1362 gai_node_lookupd(d
->cname
, family
, 0, &list
);
1368 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1370 /* Check for cname */
1371 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1373 cname
= strdup(d
->name
);
1376 /* Check for ipv4 address */
1377 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1379 inet_aton(d
->ipv4
, &a4
);
1380 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1383 /* Check for ipv6 address */
1384 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1386 gai_inet_pton(d
->ipv6
, &a6
);
1387 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1393 for (i
= 0; i
< a_list_count
; i
++)
1395 if (a_list
[i
]->sa_family
== PF_INET
)
1397 sa4
= (struct sockaddr_in
*)a_list
[i
];
1398 a
= new_addrinfo_v4(0, socktype
, proto
, port
, sa4
->sin_addr
, NULL
);
1399 append_addrinfo(res
, a
);
1401 else if (a_list
[i
]->sa_family
== PF_INET6
)
1403 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1404 a
= new_addrinfo_v6(0, socktype
, proto
, port
, sa6
->sin6_addr
, NULL
);
1405 append_addrinfo(res
, a
);
1411 if (a_list_count
> 0) free(a_list
);
1413 /* Set cname in first result */
1414 if ((setcname
== 1) && (*res
!= NULL
))
1416 if (res
[0]->ai_canonname
== NULL
)
1418 res
[0]->ai_canonname
= cname
;
1423 if (cname
!= NULL
) free(cname
);
1427 gai_nodeserv(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1429 struct lu_dict
*srv_list
, *node_list
, *s
, *n
;
1430 int numerichost
, family
, proto
, setcname
;
1431 int wantv4
, wantv6
, i
, j
, gotmx
, p_list_count
;
1432 unsigned short port
;
1434 struct sockaddr
**p_list
;
1435 struct sockaddr_in
*sa4
;
1439 proto
= IPPROTO_UNSPEC
;
1447 family
= hints
->ai_family
;
1448 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1449 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1451 proto
= hints
->ai_protocol
;
1452 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1453 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1456 if (family
== PF_INET6
) wantv4
= 0;
1457 if (family
== PF_INET
) wantv6
= 0;
1459 /* First check for this particular host / service (e.g. DNS_SRV) */
1462 gai_nodeserv_lookupd(nodename
, servname
, hints
, &srv_list
);
1463 lu_prioity_sort(&srv_list
);
1465 if (srv_list
!= NULL
)
1467 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1469 if (s
->port
== NULL
) continue;
1470 if (s
->protocol
== NULL
) continue;
1472 i
= htons(atoi(s
->port
));
1474 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1475 gai_node_pp(s
->target
, i
, j
, family
, setcname
, res
);
1478 free_lu_dict(srv_list
);
1483 * Special case for smtp: collect mail_exchangers.
1488 if (!strcmp(servname
, "smtp"))
1490 gai_node_lookupd(nodename
, family
, numerichost
, &node_list
);
1491 if ((node_list
== NULL
) && (numerichost
== 0))
1493 gai_node_lookupd(nodename
, family
, 1, &node_list
);
1496 lu_prioity_sort(&node_list
);
1498 for (n
= node_list
; (n
!= NULL
) && (gotmx
== 0); n
= n
->lu_next
)
1500 if (n
->mx
!= NULL
) gotmx
= 1;
1503 if ((gotmx
== 0) && (node_list
!= NULL
))
1505 free_lu_dict(node_list
);
1511 * Look up service, look up node, and combine port/proto with node addresses.
1514 gai_serv_lookupd(servname
, proto
, 0, &srv_list
);
1515 if (srv_list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &srv_list
);
1516 if (srv_list
== NULL
) return 0;
1519 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1521 if (s
->port
== NULL
) continue;
1522 if (s
->protocol
== NULL
) continue;
1524 i
= htons(atoi(s
->port
));
1526 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1528 merge_plist(i
, j
, (struct sockaddr_in
***)&p_list
, &p_list_count
);
1531 free_lu_dict(srv_list
);
1533 for (i
= 0; i
< p_list_count
; i
++)
1535 sa4
= (struct sockaddr_in
*)p_list
[i
];
1536 port
= sa4
->sin_port
;
1537 /* N.B. sin_family is overloaded */
1538 proto
= sa4
->sin_family
;
1542 for (n
= node_list
; n
!= NULL
; n
= n
->lu_next
)
1544 if (n
->mx
!= NULL
) gai_node_pp(n
->mx
, port
, proto
, family
, setcname
, res
);
1549 gai_node_pp(nodename
, port
, proto
, family
, setcname
, res
);
1555 if (node_list
!= NULL
) free_lu_dict(node_list
);
1557 if (p_list_count
> 0) free(p_list
);
1562 getaddrinfo(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1565 struct lu_dict
*list
;
1567 if (res
== NULL
) return 0;
1572 if ((nodename
== NULL
) && (servname
== NULL
)) return EAI_NONAME
;
1577 if (hints
->ai_addrlen
!= 0) return EAI_BADHINTS
;
1578 if (hints
->ai_canonname
!= NULL
) return EAI_BADHINTS
;
1579 if (hints
->ai_addr
!= NULL
) return EAI_BADHINTS
;
1580 if (hints
->ai_next
!= NULL
) return EAI_BADHINTS
;
1582 /* Check for supported protocol family */
1583 if (gai_family_type_check(hints
->ai_family
) != 0) return EAI_FAMILY
;
1585 /* Check for supported socket */
1586 if (gai_socket_type_check(hints
->ai_socktype
) != 0) return EAI_BADHINTS
;
1588 /* Check for supported protocol */
1589 if (gai_protocol_type_check(hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1591 /* Check that socket type is compatible with protocol */
1592 if (gai_socket_protocol_type_check(hints
->ai_socktype
, hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1597 if (nodename
== NULL
)
1599 /* If node is NULL, find service */
1600 return gai_serv(servname
, hints
, res
);
1603 if (servname
== NULL
)
1605 /* If service is NULL, find node */
1606 return gai_node(nodename
, hints
, res
);
1609 /* Find node + service */
1610 return gai_nodeserv(nodename
, servname
, hints
, res
);