xref: /freebsd/contrib/ntp/libntp/ntp_rfc2553.c (revision 009e81b16465ea457c0e63fd49fe77f47cc27a5a)
19c2daa00SOllivier Robert /*
29c2daa00SOllivier Robert  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
39c2daa00SOllivier Robert  * All rights reserved.
49c2daa00SOllivier Robert  *
59c2daa00SOllivier Robert  * Redistribution and use in source and binary forms, with or without
69c2daa00SOllivier Robert  * modification, are permitted provided that the following conditions
79c2daa00SOllivier Robert  * are met:
89c2daa00SOllivier Robert  * 1. Redistributions of source code must retain the above copyright
99c2daa00SOllivier Robert  *    notice, this list of conditions and the following disclaimer.
109c2daa00SOllivier Robert  * 2. Redistributions in binary form must reproduce the above copyright
119c2daa00SOllivier Robert  *    notice, this list of conditions and the following disclaimer in the
129c2daa00SOllivier Robert  *    documentation and/or other materials provided with the distribution.
139c2daa00SOllivier Robert  * 3. Neither the name of the project nor the names of its contributors
149c2daa00SOllivier Robert  *    may be used to endorse or promote products derived from this software
159c2daa00SOllivier Robert  *    without specific prior written permission.
169c2daa00SOllivier Robert  *
179c2daa00SOllivier Robert  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
189c2daa00SOllivier Robert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199c2daa00SOllivier Robert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209c2daa00SOllivier Robert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
219c2daa00SOllivier Robert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229c2daa00SOllivier Robert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239c2daa00SOllivier Robert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249c2daa00SOllivier Robert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259c2daa00SOllivier Robert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269c2daa00SOllivier Robert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279c2daa00SOllivier Robert  * SUCH DAMAGE.
289c2daa00SOllivier Robert  */
299c2daa00SOllivier Robert 
309c2daa00SOllivier Robert /*
319c2daa00SOllivier Robert  * Copyright (c) 1982, 1986, 1990, 1993
329c2daa00SOllivier Robert  *	The Regents of the University of California.  All rights reserved.
339c2daa00SOllivier Robert  *
349c2daa00SOllivier Robert  * Redistribution and use in source and binary forms, with or without
359c2daa00SOllivier Robert  * modification, are permitted provided that the following conditions
369c2daa00SOllivier Robert  * are met:
379c2daa00SOllivier Robert  * 1. Redistributions of source code must retain the above copyright
389c2daa00SOllivier Robert  *    notice, this list of conditions and the following disclaimer.
399c2daa00SOllivier Robert  * 2. Redistributions in binary form must reproduce the above copyright
409c2daa00SOllivier Robert  *    notice, this list of conditions and the following disclaimer in the
419c2daa00SOllivier Robert  *    documentation and/or other materials provided with the distribution.
429c2daa00SOllivier Robert  * 3. All advertising materials mentioning features or use of this software
439c2daa00SOllivier Robert  *    must display the following acknowledgement:
449c2daa00SOllivier Robert  *	This product includes software developed by the University of
459c2daa00SOllivier Robert  *	California, Berkeley and its contributors.
469c2daa00SOllivier Robert  * 4. Neither the name of the University nor the names of its contributors
479c2daa00SOllivier Robert  *    may be used to endorse or promote products derived from this software
489c2daa00SOllivier Robert  *    without specific prior written permission.
499c2daa00SOllivier Robert  *
509c2daa00SOllivier Robert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
519c2daa00SOllivier Robert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
529c2daa00SOllivier Robert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
539c2daa00SOllivier Robert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
549c2daa00SOllivier Robert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
559c2daa00SOllivier Robert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
569c2daa00SOllivier Robert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
579c2daa00SOllivier Robert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
589c2daa00SOllivier Robert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
599c2daa00SOllivier Robert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
609c2daa00SOllivier Robert  * SUCH DAMAGE.
619c2daa00SOllivier Robert  *
629c2daa00SOllivier Robert  */
639c2daa00SOllivier Robert 
649c2daa00SOllivier Robert /*
659c2daa00SOllivier Robert  * Compatability shims with the rfc2553 API to simplify ntp.
669c2daa00SOllivier Robert  */
679c2daa00SOllivier Robert 
689c2daa00SOllivier Robert #include <config.h>
699c2daa00SOllivier Robert 
709c2daa00SOllivier Robert #include <sys/types.h>
719c2daa00SOllivier Robert #include <ctype.h>
722b15cb3dSCy Schubert #ifdef HAVE_SYS_SOCKET_H
739c2daa00SOllivier Robert #include <sys/socket.h>
742b15cb3dSCy Schubert #endif
75ea906c41SOllivier Robert #include <isc/net.h>
769c2daa00SOllivier Robert #ifdef HAVE_NETINET_IN_H
779c2daa00SOllivier Robert #include <netinet/in.h>
789c2daa00SOllivier Robert #endif
79ea906c41SOllivier Robert #include "ntp_rfc2553.h"
809c2daa00SOllivier Robert 
819c2daa00SOllivier Robert #include "ntpd.h"
829c2daa00SOllivier Robert #include "ntp_malloc.h"
839c2daa00SOllivier Robert #include "ntp_string.h"
842b15cb3dSCy Schubert #include "ntp_debug.h"
852b15cb3dSCy Schubert 
862b15cb3dSCy Schubert 
872b15cb3dSCy Schubert /*
882b15cb3dSCy Schubert  * copy_addrinfo()	- copy a single addrinfo to malloc()'d block.
892b15cb3dSCy Schubert  * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
902b15cb3dSCy Schubert  *
912b15cb3dSCy Schubert  * Copies an addrinfo list and its associated data to a contiguous block
922b15cb3dSCy Schubert  * of storage from emalloc().  Callback routines invoked via
932b15cb3dSCy Schubert  * getaddrinfo_sometime() have access to the resulting addrinfo list
942b15cb3dSCy Schubert  * only until they return.  This routine provides an easy way to make a
952b15cb3dSCy Schubert  * persistent copy.  Although the list provided to gai_sometime_callback
962b15cb3dSCy Schubert  * routines is similarly contiguous, to keep this code usable in any
972b15cb3dSCy Schubert  * context where we might want to duplicate an addrinfo list, it does
982b15cb3dSCy Schubert  * not require the input list be contiguous.
992b15cb3dSCy Schubert  *
1002b15cb3dSCy Schubert  * The returned list head pointer is passed to free() to release the
1012b15cb3dSCy Schubert  * entire list.
1022b15cb3dSCy Schubert  *
1032b15cb3dSCy Schubert  * In keeping with the rest of the NTP distribution, sockaddr_u is used
1042b15cb3dSCy Schubert  * in preference to struct sockaddr_storage, which is a member of the
1052b15cb3dSCy Schubert  * former union and so compatible.
1062b15cb3dSCy Schubert  *
1072b15cb3dSCy Schubert  * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
1082b15cb3dSCy Schubert  * not being defined, copy_addrinfo_*() are exceptions.
1092b15cb3dSCy Schubert  */
1102b15cb3dSCy Schubert struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
1112b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1122b15cb3dSCy Schubert 								   ,
1132b15cb3dSCy Schubert 				       const char *, int
1142b15cb3dSCy Schubert #endif
1152b15cb3dSCy Schubert 				       );
1162b15cb3dSCy Schubert 
1172b15cb3dSCy Schubert 
1182b15cb3dSCy Schubert struct addrinfo *
copy_addrinfo_impl(const struct addrinfo * src,const char * caller_file,int caller_line)1192b15cb3dSCy Schubert copy_addrinfo_impl(
1202b15cb3dSCy Schubert 	const struct addrinfo *	src
1212b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1222b15cb3dSCy Schubert 				   ,
1232b15cb3dSCy Schubert 	const char *		caller_file,
1242b15cb3dSCy Schubert 	int			caller_line
1252b15cb3dSCy Schubert #endif
1262b15cb3dSCy Schubert 	)
1272b15cb3dSCy Schubert {
1282b15cb3dSCy Schubert 	return copy_addrinfo_common(src, TRUE
1292b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1302b15cb3dSCy Schubert 					      ,
1312b15cb3dSCy Schubert 				    caller_file, caller_line
1322b15cb3dSCy Schubert #endif
1332b15cb3dSCy Schubert 				    );
1342b15cb3dSCy Schubert }
1352b15cb3dSCy Schubert 
1362b15cb3dSCy Schubert 
1372b15cb3dSCy Schubert struct addrinfo *
copy_addrinfo_list_impl(const struct addrinfo * src,const char * caller_file,int caller_line)1382b15cb3dSCy Schubert copy_addrinfo_list_impl(
1392b15cb3dSCy Schubert 	const struct addrinfo *	src
1402b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1412b15cb3dSCy Schubert 				   ,
1422b15cb3dSCy Schubert 	const char *		caller_file,
1432b15cb3dSCy Schubert 	int			caller_line
1442b15cb3dSCy Schubert #endif
1452b15cb3dSCy Schubert 	)
1462b15cb3dSCy Schubert {
1472b15cb3dSCy Schubert 	return copy_addrinfo_common(src, FALSE
1482b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1492b15cb3dSCy Schubert 					      ,
1502b15cb3dSCy Schubert 				    caller_file, caller_line
1512b15cb3dSCy Schubert #endif
1522b15cb3dSCy Schubert 				    );
1532b15cb3dSCy Schubert }
1542b15cb3dSCy Schubert 
1552b15cb3dSCy Schubert 
1562b15cb3dSCy Schubert struct addrinfo *
copy_addrinfo_common(const struct addrinfo * src,int just_one,const char * caller_file,int caller_line)1572b15cb3dSCy Schubert copy_addrinfo_common(
1582b15cb3dSCy Schubert 	const struct addrinfo *	src,
1592b15cb3dSCy Schubert 	int			just_one
1602b15cb3dSCy Schubert #ifdef EREALLOC_CALLSITE
1612b15cb3dSCy Schubert 					,
1622b15cb3dSCy Schubert 	const char *		caller_file,
1632b15cb3dSCy Schubert 	int			caller_line
1642b15cb3dSCy Schubert #endif
1652b15cb3dSCy Schubert 	)
1662b15cb3dSCy Schubert {
1672b15cb3dSCy Schubert 	const struct addrinfo *	ai_src;
1682b15cb3dSCy Schubert 	const struct addrinfo *	ai_nxt;
1692b15cb3dSCy Schubert 	struct addrinfo *	ai_cpy;
1702b15cb3dSCy Schubert 	struct addrinfo *	dst;
1712b15cb3dSCy Schubert 	sockaddr_u *		psau;
1722b15cb3dSCy Schubert 	char *			pcanon;
1732b15cb3dSCy Schubert 	u_int			elements;
1742b15cb3dSCy Schubert 	size_t			octets;
1752b15cb3dSCy Schubert 	size_t			canons_octets;
1762b15cb3dSCy Schubert 	size_t			str_octets;
1772b15cb3dSCy Schubert 
1782b15cb3dSCy Schubert 	elements = 0;
1792b15cb3dSCy Schubert 	canons_octets = 0;
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert 	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
1822b15cb3dSCy Schubert 		if (just_one)
1832b15cb3dSCy Schubert 			ai_nxt = NULL;
1842b15cb3dSCy Schubert 		else
1852b15cb3dSCy Schubert 			ai_nxt = ai_src->ai_next;
1862b15cb3dSCy Schubert 		++elements;
1872b15cb3dSCy Schubert 		if (NULL != ai_src->ai_canonname)
1882b15cb3dSCy Schubert 			canons_octets += 1 + strlen(ai_src->ai_canonname);
1892b15cb3dSCy Schubert 	}
1902b15cb3dSCy Schubert 
1912b15cb3dSCy Schubert 	octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
1922b15cb3dSCy Schubert 	octets += canons_octets;
1932b15cb3dSCy Schubert 
1942b15cb3dSCy Schubert 	dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
1952b15cb3dSCy Schubert 			    caller_line);
1962b15cb3dSCy Schubert 	ai_cpy = dst;
1972b15cb3dSCy Schubert 	psau = (void *)(ai_cpy + elements);
1982b15cb3dSCy Schubert 	pcanon = (void *)(psau + elements);
1992b15cb3dSCy Schubert 
2002b15cb3dSCy Schubert 	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
2012b15cb3dSCy Schubert 		if (just_one)
2022b15cb3dSCy Schubert 			ai_nxt = NULL;
2032b15cb3dSCy Schubert 		else
2042b15cb3dSCy Schubert 			ai_nxt = ai_src->ai_next;
2052b15cb3dSCy Schubert 		*ai_cpy = *ai_src;
206*3311ff84SXin LI 		DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname);
207*3311ff84SXin LI 		INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u));
2082b15cb3dSCy Schubert 		memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
2092b15cb3dSCy Schubert 		ai_cpy->ai_addr = &psau->sa;
2102b15cb3dSCy Schubert 		++psau;
211*3311ff84SXin LI 		if (NULL != ai_src->ai_canonname) {
2122b15cb3dSCy Schubert 			ai_cpy->ai_canonname = pcanon;
2132b15cb3dSCy Schubert 			str_octets = 1 + strlen(ai_src->ai_canonname);
2142b15cb3dSCy Schubert 			memcpy(pcanon, ai_src->ai_canonname, str_octets);
2152b15cb3dSCy Schubert 			pcanon += str_octets;
2162b15cb3dSCy Schubert 		}
2172b15cb3dSCy Schubert 		if (NULL != ai_cpy->ai_next) {
2182b15cb3dSCy Schubert 			if (just_one)
2192b15cb3dSCy Schubert 				ai_cpy->ai_next = NULL;
2202b15cb3dSCy Schubert 			else
2212b15cb3dSCy Schubert 				ai_cpy->ai_next = ai_cpy + 1;
2222b15cb3dSCy Schubert 		}
2232b15cb3dSCy Schubert 		++ai_cpy;
2242b15cb3dSCy Schubert 	}
2259034852cSGleb Smirnoff 	ENSURE(pcanon == ((char *)dst + octets));
2262b15cb3dSCy Schubert 
2272b15cb3dSCy Schubert 	return dst;
2282b15cb3dSCy Schubert }
2292b15cb3dSCy Schubert 
2309c2daa00SOllivier Robert 
231ea906c41SOllivier Robert #ifndef ISC_PLATFORM_HAVEIPV6
2329c2daa00SOllivier Robert 
2339c2daa00SOllivier Robert static char *ai_errlist[] = {
2349c2daa00SOllivier Robert 	"Success",
2359c2daa00SOllivier Robert 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
2369c2daa00SOllivier Robert 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
2379c2daa00SOllivier Robert 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
2389c2daa00SOllivier Robert 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
2399c2daa00SOllivier Robert 	"ai_family not supported",			/* EAI_FAMILY     */
2409c2daa00SOllivier Robert 	"Memory allocation failure", 			/* EAI_MEMORY     */
2419c2daa00SOllivier Robert 	"No address associated with hostname", 		/* EAI_NODATA     */
2429c2daa00SOllivier Robert 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
2439c2daa00SOllivier Robert 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
2449c2daa00SOllivier Robert 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
2459c2daa00SOllivier Robert 	"System error returned in errno", 		/* EAI_SYSTEM     */
2469c2daa00SOllivier Robert 	"Invalid value for hints",			/* EAI_BADHINTS	  */
2479c2daa00SOllivier Robert 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
2489c2daa00SOllivier Robert 	"Unknown error", 				/* EAI_MAX        */
2499c2daa00SOllivier Robert };
2509c2daa00SOllivier Robert 
251ea906c41SOllivier Robert /*
252ea906c41SOllivier Robert  * Local declaration
253ea906c41SOllivier Robert  */
254ea906c41SOllivier Robert int
255ea906c41SOllivier Robert DNSlookup_name(
256ea906c41SOllivier Robert 	const char *name,
257ea906c41SOllivier Robert 	int ai_family,
258ea906c41SOllivier Robert 	struct hostent **Addresses
259ea906c41SOllivier Robert );
260ea906c41SOllivier Robert 
261ea906c41SOllivier Robert #ifndef SYS_WINNT
262ea906c41SOllivier Robert /*
263ea906c41SOllivier Robert  * Encapsulate gethostbyname to control the error code
264ea906c41SOllivier Robert  */
265ea906c41SOllivier Robert int
DNSlookup_name(const char * name,int ai_family,struct hostent ** Addresses)266ea906c41SOllivier Robert DNSlookup_name(
267ea906c41SOllivier Robert 	const char *name,
268ea906c41SOllivier Robert 	int ai_family,
269ea906c41SOllivier Robert 	struct hostent **Addresses
270ea906c41SOllivier Robert )
271ea906c41SOllivier Robert {
272ea906c41SOllivier Robert 	*Addresses = gethostbyname(name);
273ea906c41SOllivier Robert 	return (h_errno);
274ea906c41SOllivier Robert }
275ea906c41SOllivier Robert #endif
276ea906c41SOllivier Robert 
2772b15cb3dSCy Schubert static	int do_nodename (const char *nodename, struct addrinfo *ai,
2782b15cb3dSCy Schubert     const struct addrinfo *hints);
2799c2daa00SOllivier Robert 
2809c2daa00SOllivier Robert int
getaddrinfo(const char * nodename,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)2819c2daa00SOllivier Robert getaddrinfo (const char *nodename, const char *servname,
2829c2daa00SOllivier Robert 	const struct addrinfo *hints, struct addrinfo **res)
2839c2daa00SOllivier Robert {
2849c2daa00SOllivier Robert 	int rval;
285ea906c41SOllivier Robert 	struct servent *sp;
286ea906c41SOllivier Robert 	struct addrinfo *ai = NULL;
287ea906c41SOllivier Robert 	int port;
288ea906c41SOllivier Robert 	const char *proto = NULL;
289ea906c41SOllivier Robert 	int family, socktype, flags, protocol;
290ea906c41SOllivier Robert 
291ea906c41SOllivier Robert 
292ea906c41SOllivier Robert 	/*
293ea906c41SOllivier Robert 	 * If no name is provide just return an error
294ea906c41SOllivier Robert 	 */
295ea906c41SOllivier Robert 	if (nodename == NULL && servname == NULL)
296ea906c41SOllivier Robert 		return (EAI_NONAME);
2979c2daa00SOllivier Robert 
2989c2daa00SOllivier Robert 	ai = calloc(sizeof(struct addrinfo), 1);
2999c2daa00SOllivier Robert 	if (ai == NULL)
3009c2daa00SOllivier Robert 		return (EAI_MEMORY);
3019c2daa00SOllivier Robert 
302ea906c41SOllivier Robert 	/*
303ea906c41SOllivier Robert 	 * Copy default values from hints, if available
304ea906c41SOllivier Robert 	 */
305ea906c41SOllivier Robert 	if (hints != NULL) {
306ea906c41SOllivier Robert 		ai->ai_flags = hints->ai_flags;
307ea906c41SOllivier Robert 		ai->ai_family = hints->ai_family;
308ea906c41SOllivier Robert 		ai->ai_socktype = hints->ai_socktype;
309ea906c41SOllivier Robert 		ai->ai_protocol = hints->ai_protocol;
310ea906c41SOllivier Robert 
311ea906c41SOllivier Robert 		family = hints->ai_family;
312ea906c41SOllivier Robert 		socktype = hints->ai_socktype;
313ea906c41SOllivier Robert 		protocol = hints->ai_protocol;
314ea906c41SOllivier Robert 		flags = hints->ai_flags;
315ea906c41SOllivier Robert 
316ea906c41SOllivier Robert 		switch (family) {
317ea906c41SOllivier Robert 		case AF_UNSPEC:
318ea906c41SOllivier Robert 			switch (hints->ai_socktype) {
319ea906c41SOllivier Robert 			case SOCK_STREAM:
320ea906c41SOllivier Robert 				proto = "tcp";
321ea906c41SOllivier Robert 				break;
322ea906c41SOllivier Robert 			case SOCK_DGRAM:
323ea906c41SOllivier Robert 				proto = "udp";
324ea906c41SOllivier Robert 				break;
325ea906c41SOllivier Robert 			}
326ea906c41SOllivier Robert 			break;
327ea906c41SOllivier Robert 		case AF_INET:
328ea906c41SOllivier Robert 		case AF_INET6:
329ea906c41SOllivier Robert 			switch (hints->ai_socktype) {
330ea906c41SOllivier Robert 			case 0:
331ea906c41SOllivier Robert 				break;
332ea906c41SOllivier Robert 			case SOCK_STREAM:
333ea906c41SOllivier Robert 				proto = "tcp";
334ea906c41SOllivier Robert 				break;
335ea906c41SOllivier Robert 			case SOCK_DGRAM:
336ea906c41SOllivier Robert 				proto = "udp";
337ea906c41SOllivier Robert 				break;
338ea906c41SOllivier Robert 			case SOCK_RAW:
339ea906c41SOllivier Robert 				break;
340ea906c41SOllivier Robert 			default:
341ea906c41SOllivier Robert 				return (EAI_SOCKTYPE);
342ea906c41SOllivier Robert 			}
343ea906c41SOllivier Robert 			break;
344ea906c41SOllivier Robert #ifdef	AF_LOCAL
345ea906c41SOllivier Robert 		case AF_LOCAL:
346ea906c41SOllivier Robert 			switch (hints->ai_socktype) {
347ea906c41SOllivier Robert 			case 0:
348ea906c41SOllivier Robert 				break;
349ea906c41SOllivier Robert 			case SOCK_STREAM:
350ea906c41SOllivier Robert 				break;
351ea906c41SOllivier Robert 			case SOCK_DGRAM:
352ea906c41SOllivier Robert 				break;
353ea906c41SOllivier Robert 			default:
354ea906c41SOllivier Robert 				return (EAI_SOCKTYPE);
355ea906c41SOllivier Robert 			}
356ea906c41SOllivier Robert 			break;
357ea906c41SOllivier Robert #endif
358ea906c41SOllivier Robert 		default:
359ea906c41SOllivier Robert 			return (EAI_FAMILY);
360ea906c41SOllivier Robert 		}
361ea906c41SOllivier Robert 	} else {
362ea906c41SOllivier Robert 		protocol = 0;
363ea906c41SOllivier Robert 		family = 0;
364ea906c41SOllivier Robert 		socktype = 0;
365ea906c41SOllivier Robert 		flags = 0;
366ea906c41SOllivier Robert 	}
367ea906c41SOllivier Robert 
3689c2daa00SOllivier Robert 	rval = do_nodename(nodename, ai, hints);
3699c2daa00SOllivier Robert 	if (rval != 0) {
3709c2daa00SOllivier Robert 		freeaddrinfo(ai);
3719c2daa00SOllivier Robert 		return (rval);
3729c2daa00SOllivier Robert 	}
373ea906c41SOllivier Robert 
374ea906c41SOllivier Robert 	/*
375ea906c41SOllivier Robert 	 * First, look up the service name (port) if it was
376ea906c41SOllivier Robert 	 * requested.  If the socket type wasn't specified, then
377ea906c41SOllivier Robert 	 * try and figure it out.
378ea906c41SOllivier Robert 	 */
3799c2daa00SOllivier Robert 	if (servname != NULL) {
380ea906c41SOllivier Robert 		char *e;
381ea906c41SOllivier Robert 
382ea906c41SOllivier Robert 		port = strtol(servname, &e, 10);
383ea906c41SOllivier Robert 		if (*e == '\0') {
384ea906c41SOllivier Robert 			if (socktype == 0)
385ea906c41SOllivier Robert 				return (EAI_SOCKTYPE);
386ea906c41SOllivier Robert 			if (port < 0 || port > 65535)
3879c2daa00SOllivier Robert 				return (EAI_SERVICE);
388ea906c41SOllivier Robert 			port = htons((unsigned short) port);
389ea906c41SOllivier Robert 		} else {
390ea906c41SOllivier Robert 			sp = getservbyname(servname, proto);
391ea906c41SOllivier Robert 			if (sp == NULL)
392ea906c41SOllivier Robert 				return (EAI_SERVICE);
393ea906c41SOllivier Robert 			port = sp->s_port;
394ea906c41SOllivier Robert 			if (socktype == 0) {
395ea906c41SOllivier Robert 				if (strcmp(sp->s_proto, "tcp") == 0)
396ea906c41SOllivier Robert 					socktype = SOCK_STREAM;
397ea906c41SOllivier Robert 				else if (strcmp(sp->s_proto, "udp") == 0)
398ea906c41SOllivier Robert 					socktype = SOCK_DGRAM;
3999c2daa00SOllivier Robert 			}
4009c2daa00SOllivier Robert 		}
401ea906c41SOllivier Robert 	} else
402ea906c41SOllivier Robert 		port = 0;
403ea906c41SOllivier Robert 
404ea906c41SOllivier Robert 	/*
405ea906c41SOllivier Robert 	 *
406ea906c41SOllivier Robert 	 * Set up the port number
407ea906c41SOllivier Robert 	 */
408ea906c41SOllivier Robert 	if (ai->ai_family == AF_INET)
409ea906c41SOllivier Robert 		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
410ea906c41SOllivier Robert 	else if (ai->ai_family == AF_INET6)
411ea906c41SOllivier Robert 		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
4129c2daa00SOllivier Robert 	*res = ai;
4139c2daa00SOllivier Robert 	return (0);
4149c2daa00SOllivier Robert }
4159c2daa00SOllivier Robert 
4169c2daa00SOllivier Robert void
freeaddrinfo(struct addrinfo * ai)4179c2daa00SOllivier Robert freeaddrinfo(struct addrinfo *ai)
4189c2daa00SOllivier Robert {
4199c2daa00SOllivier Robert 	if (ai->ai_canonname != NULL)
420ea906c41SOllivier Robert 	{
4219c2daa00SOllivier Robert 		free(ai->ai_canonname);
422ea906c41SOllivier Robert 		ai->ai_canonname = NULL;
423ea906c41SOllivier Robert 	}
4249c2daa00SOllivier Robert 	if (ai->ai_addr != NULL)
425ea906c41SOllivier Robert 	{
4269c2daa00SOllivier Robert 		free(ai->ai_addr);
427ea906c41SOllivier Robert 		ai->ai_addr = NULL;
428ea906c41SOllivier Robert 	}
4299c2daa00SOllivier Robert 	free(ai);
430ea906c41SOllivier Robert 	ai = NULL;
4319c2daa00SOllivier Robert }
4329c2daa00SOllivier Robert 
4339c2daa00SOllivier Robert int
getnameinfo(const struct sockaddr * sa,u_int salen,char * host,size_t hostlen,char * serv,size_t servlen,int flags)4349c2daa00SOllivier Robert getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
4359c2daa00SOllivier Robert 	size_t hostlen, char *serv, size_t servlen, int flags)
4369c2daa00SOllivier Robert {
4379c2daa00SOllivier Robert 	struct hostent *hp;
4389c2daa00SOllivier Robert 
4399c2daa00SOllivier Robert 	if (sa->sa_family != AF_INET)
4409c2daa00SOllivier Robert 		return (EAI_FAMILY);
4419c2daa00SOllivier Robert 	hp = gethostbyaddr(
4429c2daa00SOllivier Robert 	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
4439c2daa00SOllivier Robert 	    4, AF_INET);
4449c2daa00SOllivier Robert 	if (hp == NULL) {
4459c2daa00SOllivier Robert 		if (h_errno == TRY_AGAIN)
4469c2daa00SOllivier Robert 			return (EAI_AGAIN);
4479c2daa00SOllivier Robert 		else
4489c2daa00SOllivier Robert 			return (EAI_FAIL);
4499c2daa00SOllivier Robert 	}
4502b15cb3dSCy Schubert 	if (host != NULL && hostlen > 0)
4512b15cb3dSCy Schubert 		strlcpy(host, hp->h_name, hostlen);
4529c2daa00SOllivier Robert 	return (0);
4539c2daa00SOllivier Robert }
4549c2daa00SOllivier Robert 
4559c2daa00SOllivier Robert char *
gai_strerror(int ecode)4569c2daa00SOllivier Robert gai_strerror(int ecode)
4579c2daa00SOllivier Robert {
4589c2daa00SOllivier Robert 	if (ecode < 0 || ecode > EAI_MAX)
4599c2daa00SOllivier Robert 		ecode = EAI_MAX;
4609c2daa00SOllivier Robert 	return ai_errlist[ecode];
4619c2daa00SOllivier Robert }
4629c2daa00SOllivier Robert 
4639c2daa00SOllivier Robert static int
do_nodename(const char * nodename,struct addrinfo * ai,const struct addrinfo * hints)4649c2daa00SOllivier Robert do_nodename(
4659c2daa00SOllivier Robert 	const char *nodename,
4669c2daa00SOllivier Robert 	struct addrinfo *ai,
4679c2daa00SOllivier Robert 	const struct addrinfo *hints)
4689c2daa00SOllivier Robert {
469ea906c41SOllivier Robert 	struct hostent *hp = NULL;
4709c2daa00SOllivier Robert 	struct sockaddr_in *sockin;
471ea906c41SOllivier Robert 	struct sockaddr_in6 *sockin6;
472ea906c41SOllivier Robert 	int errval;
4739c2daa00SOllivier Robert 
4749c2daa00SOllivier Robert 	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
4759c2daa00SOllivier Robert 	if (ai->ai_addr == NULL)
4769c2daa00SOllivier Robert 		return (EAI_MEMORY);
4779c2daa00SOllivier Robert 
478ea906c41SOllivier Robert 	/*
479ea906c41SOllivier Robert 	 * For an empty node name just use the wildcard.
480ea906c41SOllivier Robert 	 * NOTE: We need to assume that the address family is
481ea906c41SOllivier Robert 	 * set elsewhere so that we can set the appropriate wildcard
482ea906c41SOllivier Robert 	 */
483ea906c41SOllivier Robert 	if (nodename == NULL) {
484ea906c41SOllivier Robert 		if (ai->ai_family == AF_INET)
485ea906c41SOllivier Robert 		{
486*3311ff84SXin LI 			ai->ai_addrlen = sizeof(struct sockaddr_in);
487ea906c41SOllivier Robert 			sockin = (struct sockaddr_in *)ai->ai_addr;
488ea906c41SOllivier Robert 			sockin->sin_family = (short) ai->ai_family;
489ea906c41SOllivier Robert 			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
490ea906c41SOllivier Robert 		}
491ea906c41SOllivier Robert 		else
492ea906c41SOllivier Robert 		{
493*3311ff84SXin LI 			ai->ai_addrlen = sizeof(struct sockaddr_in6);
494ea906c41SOllivier Robert 			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
495ea906c41SOllivier Robert 			sockin6->sin6_family = (short) ai->ai_family;
496ea906c41SOllivier Robert 			/*
497ea906c41SOllivier Robert 			 * we have already zeroed out the address
498ea906c41SOllivier Robert 			 * so we don't actually need to do this
499ea906c41SOllivier Robert 			 * This assignment is causing problems so
500ea906c41SOllivier Robert 			 * we don't do what this would do.
501ea906c41SOllivier Robert 			 sockin6->sin6_addr = in6addr_any;
502ea906c41SOllivier Robert 			 */
503ea906c41SOllivier Robert 		}
5042b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
505ea906c41SOllivier Robert 		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
506ea906c41SOllivier Robert #endif
507ea906c41SOllivier Robert 
508ea906c41SOllivier Robert 		return (0);
509ea906c41SOllivier Robert 	}
510ea906c41SOllivier Robert 
511ea906c41SOllivier Robert 	/*
512ea906c41SOllivier Robert 	 * See if we have an IPv6 address
513ea906c41SOllivier Robert 	 */
514ea906c41SOllivier Robert 	if(strchr(nodename, ':') != NULL) {
515ea906c41SOllivier Robert 		if (inet_pton(AF_INET6, nodename,
516ea906c41SOllivier Robert 		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
517ea906c41SOllivier Robert 			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
518ea906c41SOllivier Robert 			ai->ai_family = AF_INET6;
519ea906c41SOllivier Robert 			ai->ai_addrlen = sizeof(struct sockaddr_in6);
520ea906c41SOllivier Robert 			return (0);
521ea906c41SOllivier Robert 		}
522ea906c41SOllivier Robert 	}
523ea906c41SOllivier Robert 
524ea906c41SOllivier Robert 	/*
525ea906c41SOllivier Robert 	 * See if we have an IPv4 address
526ea906c41SOllivier Robert 	 */
527ea906c41SOllivier Robert 	if (inet_pton(AF_INET, nodename,
528ea906c41SOllivier Robert 	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
529ea906c41SOllivier Robert 		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
5309c2daa00SOllivier Robert 		ai->ai_family = AF_INET;
5319c2daa00SOllivier Robert 		ai->ai_addrlen = sizeof(struct sockaddr_in);
5329c2daa00SOllivier Robert 		return (0);
5339c2daa00SOllivier Robert 	}
534ea906c41SOllivier Robert 
535ea906c41SOllivier Robert 	/*
536ea906c41SOllivier Robert 	 * If the numeric host flag is set, don't attempt resolution
537ea906c41SOllivier Robert 	 */
538ea906c41SOllivier Robert 	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
5399c2daa00SOllivier Robert 		return (EAI_NONAME);
540ea906c41SOllivier Robert 
541ea906c41SOllivier Robert 	/*
542ea906c41SOllivier Robert 	 * Look for a name
543ea906c41SOllivier Robert 	 */
544ea906c41SOllivier Robert 
545ea906c41SOllivier Robert 	errval = DNSlookup_name(nodename, AF_INET, &hp);
546ea906c41SOllivier Robert 
5479c2daa00SOllivier Robert 	if (hp == NULL) {
548ea906c41SOllivier Robert 		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
5499c2daa00SOllivier Robert 			return (EAI_AGAIN);
550ea906c41SOllivier Robert 		else if (errval == EAI_NONAME) {
551ea906c41SOllivier Robert 			if (inet_pton(AF_INET, nodename,
552ea906c41SOllivier Robert 			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
553ea906c41SOllivier Robert 				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
5549c2daa00SOllivier Robert 				ai->ai_family = AF_INET;
5559c2daa00SOllivier Robert 				ai->ai_addrlen = sizeof(struct sockaddr_in);
5569c2daa00SOllivier Robert 				return (0);
5579c2daa00SOllivier Robert 			}
558ea906c41SOllivier Robert 			return (errval);
559ea906c41SOllivier Robert 		}
560ea906c41SOllivier Robert 		else
561ea906c41SOllivier Robert 		{
562ea906c41SOllivier Robert 			return (errval);
5639c2daa00SOllivier Robert 		}
5649c2daa00SOllivier Robert 	}
5659c2daa00SOllivier Robert 	ai->ai_family = hp->h_addrtype;
5669c2daa00SOllivier Robert 	ai->ai_addrlen = sizeof(struct sockaddr);
5679c2daa00SOllivier Robert 	sockin = (struct sockaddr_in *)ai->ai_addr;
5689c2daa00SOllivier Robert 	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
5699c2daa00SOllivier Robert 	ai->ai_addr->sa_family = hp->h_addrtype;
5702b15cb3dSCy Schubert #ifdef ISC_PLATFORM_HAVESALEN
5719c2daa00SOllivier Robert 	ai->ai_addr->sa_len = sizeof(struct sockaddr);
5729c2daa00SOllivier Robert #endif
5732b15cb3dSCy Schubert 	if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
5742b15cb3dSCy Schubert 		ai->ai_canonname = estrdup(hp->h_name);
5759c2daa00SOllivier Robert 	return (0);
5769c2daa00SOllivier Robert }
5779c2daa00SOllivier Robert 
578ea906c41SOllivier Robert #endif /* !ISC_PLATFORM_HAVEIPV6 */
579