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", 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_canonname
!= NULL
) free(a
->ai_canonname
);
674 static struct addrinfo
*
675 new_addrinfo_v4(int flags
, int sock
, int proto
, unsigned short port
, struct in_addr addr
, char *cname
)
678 struct sockaddr_in
*sa
;
681 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
682 memset(a
, 0, sizeof(struct addrinfo
));
686 a
->ai_family
= PF_INET
;
687 a
->ai_socktype
= sock
;
688 a
->ai_protocol
= proto
;
690 a
->ai_addrlen
= sizeof(struct sockaddr_in
);
691 sa
= (struct sockaddr_in
*)malloc(a
->ai_addrlen
);
692 memset(sa
, 0, a
->ai_addrlen
);
693 sa
->sin_len
= a
->ai_addrlen
;
694 sa
->sin_family
= PF_INET
;
697 a
->ai_addr
= (struct sockaddr
*)sa
;
701 len
= strlen(cname
) + 1;
702 a
->ai_canonname
= malloc(len
);
703 memmove(a
->ai_canonname
, cname
, len
);
709 static struct addrinfo
*
710 new_addrinfo_v6(int flags
, int sock
, int proto
, unsigned short port
, struct in6_addr addr
, char *cname
)
713 struct sockaddr_in6
*sa
;
716 a
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
));
717 memset(a
, 0, sizeof(struct addrinfo
));
721 a
->ai_family
= PF_INET6
;
722 a
->ai_socktype
= sock
;
723 a
->ai_protocol
= proto
;
725 a
->ai_addrlen
= sizeof(struct sockaddr_in6
);
726 sa
= (struct sockaddr_in6
*)malloc(a
->ai_addrlen
);
727 memset(sa
, 0, a
->ai_addrlen
);
728 sa
->sin6_len
= a
->ai_addrlen
;
729 sa
->sin6_family
= PF_INET6
;
730 sa
->sin6_port
= port
;
731 sa
->sin6_addr
= addr
;
732 a
->ai_addr
= (struct sockaddr
*)sa
;
736 len
= strlen(cname
) + 1;
737 a
->ai_canonname
= malloc(len
);
738 memmove(a
->ai_canonname
, cname
, len
);
745 grok_nodename(const char *nodename
, int family
, struct lu_dict
*q
)
747 if (nodename
== NULL
) return;
748 if (q
== NULL
) return;
750 if (((family
== PF_UNSPEC
) || (family
== PF_INET
)) && is_ipv4_address(nodename
))
752 q
->ipv4
= (char *)nodename
;
754 else if (((family
== PF_UNSPEC
) || (family
== PF_INET6
)) && is_ipv6_address(nodename
))
756 q
->ipv6
= (char *)nodename
;
760 q
->name
= (char *)nodename
;
765 grok_service(const char *servname
, struct lu_dict
*q
)
770 if (servname
== NULL
) return;
771 if (q
== NULL
) return;
774 for (p
= (char *)servname
; (port
== 0) && (*p
!= '\0'); p
++)
776 if (!isdigit(*p
)) port
= -1;
779 if (port
== 0) port
= atoi(servname
);
780 if ((port
> 0) && (port
< 0xffff)) q
->port
= (char *)servname
;
781 else q
->service
= (char *)servname
;
785 gai_numerichost(struct lu_dict
*h
, struct lu_dict
**list
)
790 if (h
== NULL
) return 0;
791 if (list
== NULL
) return -1;
797 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
798 memset(a
, 0, sizeof(struct lu_dict
));
799 a
->ipv4
= strdup(h
->ipv4
);
800 append_lu_dict(list
, a
);
806 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
807 memset(a
, 0, sizeof(struct lu_dict
));
808 a
->ipv6
= strdup(h
->ipv6
);
809 append_lu_dict(list
, a
);
817 gai_numericserv(struct lu_dict
*s
, struct lu_dict
**list
)
821 if (s
== NULL
) return 0;
822 if (s
->port
== NULL
) return 0;
823 if (list
== NULL
) return -1;
825 a
= (struct lu_dict
*)malloc(sizeof(struct lu_dict
));
826 memset(a
, 0, sizeof(struct lu_dict
));
827 a
->port
= strdup(s
->port
);
828 append_lu_dict(list
, a
);
833 merge_addr4(struct in_addr a
, struct sockaddr_in
***l
, int *n
)
836 struct sockaddr_in
*sa4
;
838 for (i
= 0; i
< *n
; i
++)
840 if (((*l
)[i
]->sin_family
== PF_INET
) && (a
.s_addr
== (*l
)[i
]->sin_addr
.s_addr
)) return;
843 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
844 memset(sa4
, 0, sizeof(struct sockaddr_in
));
846 sa4
->sin_family
= PF_INET
;
849 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
850 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
857 merge_addr6(struct in6_addr a
, struct sockaddr_in6
***l
, int *n
)
860 struct sockaddr_in6
*sa6
;
862 for (i
= 0; i
< *n
; i
++)
864 if (((*l
)[i
]->sin6_family
== PF_INET6
)
865 && (a
.__u6_addr
.__u6_addr32
[0] == (*l
)[i
]->sin6_addr
.__u6_addr
.__u6_addr32
[0])) return;
868 sa6
= (struct sockaddr_in6
*)malloc(sizeof(struct sockaddr_in6
));
869 memset(sa6
, 0, sizeof(struct sockaddr_in6
));
871 sa6
->sin6_family
= PF_INET6
;
874 if (*n
== 0) *l
= (struct sockaddr_in6
**)malloc(sizeof(struct sockaddr_in6
*));
875 else *l
= (struct sockaddr_in6
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in6
*));
882 * N.B. We use sim_family to store protocol in the sockaddr.
883 * sockaddr is just used here as a data structure to keep
884 * (port, protocol) pairs.
887 merge_plist(unsigned short port
, unsigned short proto
, struct sockaddr_in
***l
, int *n
)
890 struct sockaddr_in
*sa4
;
892 for (i
= 0; i
< *n
; i
++)
894 if ((port
== (*l
)[i
]->sin_port
) && (proto
== (*l
)[i
]->sin_family
)) return;
897 sa4
= (struct sockaddr_in
*)malloc(sizeof(struct sockaddr_in
));
898 memset(sa4
, 0, sizeof(struct sockaddr_in
));
900 sa4
->sin_port
= port
;
901 sa4
->sin_family
= proto
;
903 if (*n
== 0) *l
= (struct sockaddr_in
**)malloc(sizeof(struct sockaddr_in
*));
904 else *l
= (struct sockaddr_in
**)realloc(*l
, (*n
+ 1) * sizeof(struct sockaddr_in
*));
906 (*l
)[*n
] = (struct sockaddr_in
*)sa4
;
911 * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
912 * From "Random number generators: good ones are hard to find",
913 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
914 * October 1988, p. 1195.
919 static int did_init
= 0;
920 static unsigned int randseed
= 1;
926 gettimeofday(&tv
, NULL
);
927 randseed
= tv
.tv_usec
;
928 if(randseed
== 0) randseed
= 1;
934 t
= 16807 * lo
- 2836 * hi
;
935 if (t
<= 0) t
+= 0x7fffffff;
941 * Sort by priority and weight.
944 lu_prioity_sort(struct lu_dict
**l
)
946 struct lu_dict
*d
, **nodes
;
947 unsigned int x
, count
, i
, j
, bottom
, *pri
, *wgt
, swap
, t
;
949 if (*l
== NULL
) return;
952 for (d
= *l
; d
!= NULL
; d
= d
->lu_next
) count
++;
953 nodes
= (struct lu_dict
**)malloc(count
* sizeof(struct lu_dict
*));
954 pri
= (unsigned int *)malloc(count
* sizeof(unsigned int));
955 wgt
= (unsigned int *)malloc(count
* sizeof(unsigned int));
957 for (i
= 0, d
= *l
; d
!= NULL
; d
= d
->lu_next
, i
++)
961 x
= (unsigned int)-1;
962 if (d
->priority
!= NULL
) x
= atoi(d
->priority
);
966 if (d
->weight
!= NULL
) x
= atoi(d
->weight
);
967 wgt
[i
] = (gai_random() % 10000) * x
;
970 /* bubble sort by priority */
977 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++)
979 if (pri
[i
] < pri
[j
]) continue;
980 if ((pri
[i
] == pri
[j
]) && (wgt
[i
] < wgt
[j
])) continue;
1001 for (i
= 0, j
= 1; i
< bottom
; i
++, j
++) nodes
[i
]->lu_next
= nodes
[j
];
1002 nodes
[bottom
]->lu_next
= NULL
;
1010 * Get service records from lookupd
1013 gai_serv_lookupd(const char *servname
, int proto
, int numericserv
, struct lu_dict
**list
)
1015 struct lu_dict q
, *sub
;
1017 memset(&q
, 0, sizeof(struct lu_dict
));
1021 grok_service(servname
, &q
);
1022 if (q
.service
!= NULL
)
1028 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1032 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1033 else gai_lookupd(&q
, &sub
);
1034 append_lu_dict(list
, sub
);
1035 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1038 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1042 if (numericserv
== 1) gai_numericserv(&q
, &sub
);
1043 else gai_lookupd(&q
, &sub
);
1044 append_lu_dict(list
, sub
);
1045 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1053 gai_serv(const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1055 struct lu_dict
*list
, *d
;
1056 int port
, proto
, family
, socktype
, setcname
, wantv4
, wantv6
;
1057 char *loopv4
, *loopv6
;
1062 loopv4
= "127.0.0.1";
1063 loopv6
= "0:0:0:0:0:0:0:1";
1066 proto
= IPPROTO_UNSPEC
;
1071 proto
= hints
->ai_protocol
;
1072 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1073 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1075 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1077 if ((hints
->ai_flags
& AI_PASSIVE
) == 1)
1080 loopv6
= "0:0:0:0:0:0:0:0";
1083 family
= hints
->ai_family
;
1088 if (family
== PF_INET6
) wantv4
= 0;
1089 if (family
== PF_INET
) wantv6
= 0;
1092 gai_serv_lookupd(servname
, proto
, 0, &list
);
1093 if (list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &list
);
1095 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1097 /* We only want records with port and protocol specified */
1098 if ((d
->port
== NULL
) || (d
->protocol
== NULL
)) continue;
1100 port
= atoi(d
->port
);
1101 proto
= IPPROTO_UDP
;
1102 socktype
= SOCK_DGRAM
;
1103 if (!strcasecmp(d
->protocol
, "tcp"))
1105 proto
= IPPROTO_TCP
;
1106 socktype
= SOCK_STREAM
;
1111 inet_aton(loopv4
, &a4
);
1112 a
= new_addrinfo_v4(0, socktype
, proto
, port
, a4
, NULL
);
1113 append_addrinfo(res
, a
);
1118 gai_inet_pton(loopv6
, &a6
);
1119 a
= new_addrinfo_v6(0, socktype
, proto
, port
, a6
, NULL
);
1120 append_addrinfo(res
, a
);
1126 /* Set cname in first result */
1127 if ((setcname
== 1) && (*res
!= NULL
))
1129 if (res
[0]->ai_canonname
== NULL
) res
[0]->ai_canonname
= strdup("localhost");
1139 gai_node_lookupd(const char *nodename
, int family
, int numerichost
, struct lu_dict
**list
)
1143 memset(&q
, 0, sizeof(struct lu_dict
));
1147 grok_nodename(nodename
, family
, &q
);
1148 if (numerichost
) gai_numerichost(&q
, list
);
1149 else gai_lookupd(&q
, list
);
1156 gai_node(const char *nodename
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1158 int i
, family
, numerichost
, setcname
, a_list_count
, wantv4
, wantv6
;
1159 struct lu_dict
*list
, *d
, *t
;
1164 struct sockaddr
**a_list
;
1165 struct sockaddr_in
*sa4
;
1166 struct sockaddr_in6
*sa6
;
1178 family
= hints
->ai_family
;
1179 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1180 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1185 if (family
== PF_INET6
) wantv4
= 0;
1186 if (family
== PF_INET
) wantv6
= 0;
1189 gai_node_lookupd(nodename
, family
, numerichost
, &t
);
1190 if ((t
== NULL
) && (numerichost
== 0))
1192 gai_node_lookupd(nodename
, family
, 1, &t
);
1195 /* If the nodename is an alias, look up the real name */
1197 for (d
= t
; d
!= NULL
; d
= d
->lu_next
)
1199 if (d
->cname
!= NULL
)
1201 if (cname
== NULL
) cname
= strdup(d
->cname
);
1202 gai_node_lookupd(d
->cname
, family
, 0, &t
);
1206 append_lu_dict(&list
, t
);
1208 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1210 /* Check for cname */
1211 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1213 cname
= strdup(d
->name
);
1216 /* Check for ipv4 address */
1217 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1219 inet_aton(d
->ipv4
, &a4
);
1220 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1223 /* Check for ipv6 address */
1224 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1226 gai_inet_pton(d
->ipv6
, &a6
);
1227 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1231 /* Last chance for a name */
1232 for (d
= list
; (cname
== NULL
) && (d
!= NULL
); d
= d
->lu_next
)
1234 if (d
->name
!= NULL
) cname
= strdup(d
->name
);
1239 for (i
= 0; i
< a_list_count
; i
++)
1241 if (a_list
[i
]->sa_family
== PF_INET
)
1243 sa4
= (struct sockaddr_in
*)a_list
[i
];
1244 a
= new_addrinfo_v4(0, 0, 0, 0, sa4
->sin_addr
, NULL
);
1245 append_addrinfo(res
, a
);
1247 else if (a_list
[i
]->sa_family
== PF_INET6
)
1249 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1250 a
= new_addrinfo_v6(0, 0, 0, 0, sa6
->sin6_addr
, NULL
);
1251 append_addrinfo(res
, a
);
1257 if (a_list_count
> 0) free(a_list
);
1259 /* Set cname in first result */
1260 if ((setcname
== 1) && (*res
!= NULL
))
1262 if (res
[0]->ai_canonname
== NULL
)
1264 res
[0]->ai_canonname
= cname
;
1269 if (cname
!= NULL
) free(cname
);
1275 * Find a service+node.
1278 gai_nodeserv_lookupd(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct lu_dict
**list
)
1280 struct lu_dict q
, *sub
;
1284 proto
= IPPROTO_UNSPEC
;
1288 if (hints
->ai_flags
& AI_NUMERICHOST
) return;
1289 family
= hints
->ai_family
;
1291 proto
= hints
->ai_protocol
;
1292 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1293 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1296 memset(&q
, 0, sizeof(struct lu_dict
));
1300 grok_nodename(nodename
, family
, &q
);
1301 grok_service(servname
, &q
);
1303 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
1307 gai_lookupd(&q
, &sub
);
1308 append_lu_dict(list
, sub
);
1309 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("udp");
1312 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
1316 gai_lookupd(&q
, &sub
);
1317 append_lu_dict(list
, sub
);
1318 for (; sub
!= NULL
; sub
= sub
->lu_next
) sub
->protocol
= strdup("tcp");
1323 gai_node_pp(const char *nodename
, int port
, int proto
, int family
, int setcname
, struct addrinfo
**res
)
1325 struct lu_dict
*list
, *d
;
1326 int i
, wantv4
, wantv6
, a_list_count
, socktype
;
1328 struct sockaddr
**a_list
;
1331 struct sockaddr_in
*sa4
;
1332 struct sockaddr_in6
*sa6
;
1335 socktype
= SOCK_UNSPEC
;
1336 if (proto
== IPPROTO_UDP
) socktype
= SOCK_DGRAM
;
1337 if (proto
== IPPROTO_TCP
) socktype
= SOCK_STREAM
;
1343 if (family
== PF_INET6
) wantv4
= 0;
1344 if (family
== PF_INET
) wantv6
= 0;
1346 /* Resolve node name */
1348 gai_node_lookupd(nodename
, family
, 0, &list
);
1351 gai_node_lookupd(nodename
, family
, 1, &list
);
1354 /* Resolve aliases */
1355 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1357 if (d
->cname
!= NULL
)
1359 cname
= strdup(d
->cname
);
1360 gai_node_lookupd(d
->cname
, family
, 0, &list
);
1366 for (d
= list
; d
!= NULL
; d
= d
->lu_next
)
1368 /* Check for cname */
1369 if ((cname
== NULL
) && (d
->name
!= NULL
) && (strchr(d
->name
, '.') != NULL
))
1371 cname
= strdup(d
->name
);
1374 /* Check for ipv4 address */
1375 if ((d
->ipv4
!= NULL
) && (wantv4
== 1))
1377 inet_aton(d
->ipv4
, &a4
);
1378 merge_addr4(a4
, (struct sockaddr_in
***)&a_list
, &a_list_count
);
1381 /* Check for ipv6 address */
1382 if ((d
->ipv6
!= NULL
) && (wantv6
== 1))
1384 gai_inet_pton(d
->ipv6
, &a6
);
1385 merge_addr6(a6
, (struct sockaddr_in6
***)&a_list
, &a_list_count
);
1391 for (i
= 0; i
< a_list_count
; i
++)
1393 if (a_list
[i
]->sa_family
== PF_INET
)
1395 sa4
= (struct sockaddr_in
*)a_list
[i
];
1396 a
= new_addrinfo_v4(0, socktype
, proto
, port
, sa4
->sin_addr
, NULL
);
1397 append_addrinfo(res
, a
);
1399 else if (a_list
[i
]->sa_family
== PF_INET6
)
1401 sa6
= (struct sockaddr_in6
*)a_list
[i
];
1402 a
= new_addrinfo_v6(0, socktype
, proto
, port
, sa6
->sin6_addr
, NULL
);
1403 append_addrinfo(res
, a
);
1409 if (a_list_count
> 0) free(a_list
);
1411 /* Set cname in first result */
1412 if ((setcname
== 1) && (*res
!= NULL
))
1414 if (res
[0]->ai_canonname
== NULL
)
1416 res
[0]->ai_canonname
= cname
;
1421 if (cname
!= NULL
) free(cname
);
1425 gai_nodeserv(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1427 struct lu_dict
*srv_list
, *node_list
, *s
, *n
;
1428 int numerichost
, family
, port
, proto
, setcname
;
1429 int wantv4
, wantv6
, i
, j
, gotmx
, p_list_count
;
1431 struct sockaddr
**p_list
;
1432 struct sockaddr_in
*sa4
;
1436 proto
= IPPROTO_UNSPEC
;
1444 family
= hints
->ai_family
;
1445 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
1446 if (hints
->ai_flags
& AI_CANONNAME
) setcname
= 1;
1448 proto
= hints
->ai_protocol
;
1449 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
1450 if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
1453 if (family
== PF_INET6
) wantv4
= 0;
1454 if (family
== PF_INET
) wantv6
= 0;
1456 /* First check for this particular host / service (e.g. DNS_SRV) */
1459 gai_nodeserv_lookupd(nodename
, servname
, hints
, &srv_list
);
1460 lu_prioity_sort(&srv_list
);
1462 if (srv_list
!= NULL
)
1464 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1466 if (s
->port
== NULL
) continue;
1467 if (s
->protocol
== NULL
) continue;
1471 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1472 gai_node_pp(s
->target
, i
, j
, family
, setcname
, res
);
1475 free_lu_dict(srv_list
);
1480 * Special case for smtp: collect mail_exchangers.
1485 if (!strcmp(servname
, "smtp"))
1487 gai_node_lookupd(nodename
, family
, numerichost
, &node_list
);
1488 if ((node_list
== NULL
) && (numerichost
== 0))
1490 gai_node_lookupd(nodename
, family
, 1, &node_list
);
1493 lu_prioity_sort(&node_list
);
1495 for (n
= node_list
; (n
!= NULL
) && (gotmx
== 0); n
= n
->lu_next
)
1497 if (n
->mx
!= NULL
) gotmx
= 1;
1500 if ((gotmx
== 0) && (node_list
!= NULL
))
1502 free_lu_dict(node_list
);
1508 * Look up service, look up node, and combine port/proto with node addresses.
1511 gai_serv_lookupd(servname
, proto
, 0, &srv_list
);
1512 if (srv_list
== NULL
) gai_serv_lookupd(servname
, proto
, 1, &srv_list
);
1513 if (srv_list
== NULL
) return 0;
1516 for (s
= srv_list
; s
!= NULL
; s
= s
->lu_next
)
1518 if (s
->port
== NULL
) continue;
1519 if (s
->protocol
== NULL
) continue;
1523 if (!strcmp(s
->protocol
, "tcp")) j
= IPPROTO_TCP
;
1525 merge_plist(i
, j
, (struct sockaddr_in
***)&p_list
, &p_list_count
);
1528 free_lu_dict(srv_list
);
1530 for (i
= 0; i
< p_list_count
; i
++)
1532 sa4
= (struct sockaddr_in
*)p_list
[i
];
1533 port
= sa4
->sin_port
;
1534 /* N.B. sin_family is overloaded */
1535 proto
= sa4
->sin_family
;
1539 for (n
= node_list
; n
!= NULL
; n
= n
->lu_next
)
1541 if (n
->mx
!= NULL
) gai_node_pp(n
->mx
, port
, proto
, family
, setcname
, res
);
1546 gai_node_pp(nodename
, port
, proto
, family
, setcname
, res
);
1552 if (node_list
!= NULL
) free_lu_dict(node_list
);
1554 if (p_list_count
> 0) free(p_list
);
1559 getaddrinfo(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
1562 struct lu_dict
*list
;
1564 if (res
== NULL
) return 0;
1569 if ((nodename
== NULL
) && (servname
== NULL
)) return EAI_NONAME
;
1574 if (hints
->ai_addrlen
!= 0) return EAI_BADHINTS
;
1575 if (hints
->ai_canonname
!= NULL
) return EAI_BADHINTS
;
1576 if (hints
->ai_addr
!= NULL
) return EAI_BADHINTS
;
1577 if (hints
->ai_next
!= NULL
) return EAI_BADHINTS
;
1579 /* Check for supported protocol family */
1580 if (gai_family_type_check(hints
->ai_family
) != 0) return EAI_FAMILY
;
1582 /* Check for supported socket */
1583 if (gai_socket_type_check(hints
->ai_socktype
) != 0) return EAI_BADHINTS
;
1585 /* Check for supported protocol */
1586 if (gai_protocol_type_check(hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1588 /* Check that socket type is compatible with protocol */
1589 if (gai_socket_protocol_type_check(hints
->ai_socktype
, hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
1594 if (nodename
== NULL
)
1596 /* If node is NULL, find service */
1597 return gai_serv(servname
, hints
, res
);
1600 if (servname
== NULL
)
1602 /* If service is NULL, find node */
1603 return gai_node(nodename
, hints
, res
);
1606 /* Find node + service */
1607 return gai_nodeserv(nodename
, servname
, hints
, res
);