1/*	$NetBSD: ntp_rfc2553.c,v 1.1.1.1 2009/12/13 16:55:04 kardel Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1982, 1986, 1990, 1993
34 *	The Regents of the University of California.  All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 *    must display the following acknowledgement:
46 *	This product includes software developed by the University of
47 *	California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 *    may be used to endorse or promote products derived from this software
50 *    without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 */
65
66/*
67 * Compatability shims with the rfc2553 API to simplify ntp.
68 */
69
70#include <config.h>
71
72#include <sys/types.h>
73#include <ctype.h>
74#ifdef HAVE_SYS_SOCKET_H
75#include <sys/socket.h>
76#endif
77#include <isc/net.h>
78#ifdef HAVE_NETINET_IN_H
79#include <netinet/in.h>
80#endif
81#include "ntp_rfc2553.h"
82
83#include "ntpd.h"
84#include "ntp_malloc.h"
85#include "ntp_stdlib.h"
86#include "ntp_string.h"
87
88#ifndef ISC_PLATFORM_HAVEIPV6
89
90static char *ai_errlist[] = {
91	"Success",
92	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
93	"Temporary failure in name resolution",		/* EAI_AGAIN      */
94	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
95	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
96	"ai_family not supported",			/* EAI_FAMILY     */
97	"Memory allocation failure", 			/* EAI_MEMORY     */
98	"No address associated with hostname", 		/* EAI_NODATA     */
99	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
100	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
101	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
102	"System error returned in errno", 		/* EAI_SYSTEM     */
103	"Invalid value for hints",			/* EAI_BADHINTS	  */
104	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
105	"Unknown error", 				/* EAI_MAX        */
106};
107
108/*
109 * Local declaration
110 */
111int
112DNSlookup_name(
113	const char *name,
114	int ai_family,
115	struct hostent **Addresses
116);
117
118#ifndef SYS_WINNT
119/*
120 * Encapsulate gethostbyname to control the error code
121 */
122int
123DNSlookup_name(
124	const char *name,
125	int ai_family,
126	struct hostent **Addresses
127)
128{
129	*Addresses = gethostbyname(name);
130	return (h_errno);
131}
132#endif
133
134static	int do_nodename (const char *nodename, struct addrinfo *ai,
135    const struct addrinfo *hints);
136
137int
138getaddrinfo (const char *nodename, const char *servname,
139	const struct addrinfo *hints, struct addrinfo **res)
140{
141	int rval;
142	struct servent *sp;
143	struct addrinfo *ai = NULL;
144	int port;
145	const char *proto = NULL;
146	int family, socktype, flags, protocol;
147
148
149	/*
150	 * If no name is provide just return an error
151	 */
152	if (nodename == NULL && servname == NULL)
153		return (EAI_NONAME);
154
155	ai = calloc(sizeof(struct addrinfo), 1);
156	if (ai == NULL)
157		return (EAI_MEMORY);
158
159	/*
160	 * Copy default values from hints, if available
161	 */
162	if (hints != NULL) {
163		ai->ai_flags = hints->ai_flags;
164		ai->ai_family = hints->ai_family;
165		ai->ai_socktype = hints->ai_socktype;
166		ai->ai_protocol = hints->ai_protocol;
167
168		family = hints->ai_family;
169		socktype = hints->ai_socktype;
170		protocol = hints->ai_protocol;
171		flags = hints->ai_flags;
172
173		switch (family) {
174		case AF_UNSPEC:
175			switch (hints->ai_socktype) {
176			case SOCK_STREAM:
177				proto = "tcp";
178				break;
179			case SOCK_DGRAM:
180				proto = "udp";
181				break;
182			}
183			break;
184		case AF_INET:
185		case AF_INET6:
186			switch (hints->ai_socktype) {
187			case 0:
188				break;
189			case SOCK_STREAM:
190				proto = "tcp";
191				break;
192			case SOCK_DGRAM:
193				proto = "udp";
194				break;
195			case SOCK_RAW:
196				break;
197			default:
198				return (EAI_SOCKTYPE);
199			}
200			break;
201#ifdef	AF_LOCAL
202		case AF_LOCAL:
203			switch (hints->ai_socktype) {
204			case 0:
205				break;
206			case SOCK_STREAM:
207				break;
208			case SOCK_DGRAM:
209				break;
210			default:
211				return (EAI_SOCKTYPE);
212			}
213			break;
214#endif
215		default:
216			return (EAI_FAMILY);
217		}
218	} else {
219		protocol = 0;
220		family = 0;
221		socktype = 0;
222		flags = 0;
223	}
224
225	rval = do_nodename(nodename, ai, hints);
226	if (rval != 0) {
227		freeaddrinfo(ai);
228		return (rval);
229	}
230
231	/*
232	 * First, look up the service name (port) if it was
233	 * requested.  If the socket type wasn't specified, then
234	 * try and figure it out.
235	 */
236	if (servname != NULL) {
237		char *e;
238
239		port = strtol(servname, &e, 10);
240		if (*e == '\0') {
241			if (socktype == 0)
242				return (EAI_SOCKTYPE);
243			if (port < 0 || port > 65535)
244				return (EAI_SERVICE);
245			port = htons((unsigned short) port);
246		} else {
247			sp = getservbyname(servname, proto);
248			if (sp == NULL)
249				return (EAI_SERVICE);
250			port = sp->s_port;
251			if (socktype == 0) {
252				if (strcmp(sp->s_proto, "tcp") == 0)
253					socktype = SOCK_STREAM;
254				else if (strcmp(sp->s_proto, "udp") == 0)
255					socktype = SOCK_DGRAM;
256			}
257		}
258	} else
259		port = 0;
260
261	/*
262	 *
263	 * Set up the port number
264	 */
265	if (ai->ai_family == AF_INET)
266		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
267	else if (ai->ai_family == AF_INET6)
268		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
269	*res = ai;
270	return (0);
271}
272
273void
274freeaddrinfo(struct addrinfo *ai)
275{
276	if (ai->ai_canonname != NULL)
277	{
278		free(ai->ai_canonname);
279		ai->ai_canonname = NULL;
280	}
281	if (ai->ai_addr != NULL)
282	{
283		free(ai->ai_addr);
284		ai->ai_addr = NULL;
285	}
286	free(ai);
287	ai = NULL;
288}
289
290int
291getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
292	size_t hostlen, char *serv, size_t servlen, int flags)
293{
294	struct hostent *hp;
295	int namelen;
296
297	if (sa->sa_family != AF_INET)
298		return (EAI_FAMILY);
299	hp = gethostbyaddr(
300	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
301	    4, AF_INET);
302	if (hp == NULL) {
303		if (h_errno == TRY_AGAIN)
304			return (EAI_AGAIN);
305		else
306			return (EAI_FAIL);
307	}
308	if (host != NULL && hostlen > 0) {
309		/*
310		 * Don't exceed buffer
311		 */
312		namelen = min(strlen(hp->h_name), hostlen - 1);
313		if (namelen > 0) {
314			strncpy(host, hp->h_name, namelen);
315			host[namelen] = '\0';
316		}
317	}
318	return (0);
319}
320
321char *
322gai_strerror(int ecode)
323{
324	if (ecode < 0 || ecode > EAI_MAX)
325		ecode = EAI_MAX;
326	return ai_errlist[ecode];
327}
328
329static int
330do_nodename(
331	const char *nodename,
332	struct addrinfo *ai,
333	const struct addrinfo *hints)
334{
335	struct hostent *hp = NULL;
336	struct sockaddr_in *sockin;
337	struct sockaddr_in6 *sockin6;
338	int errval;
339
340	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
341	if (ai->ai_addr == NULL)
342		return (EAI_MEMORY);
343
344	/*
345	 * For an empty node name just use the wildcard.
346	 * NOTE: We need to assume that the address family is
347	 * set elsewhere so that we can set the appropriate wildcard
348	 */
349	if (nodename == NULL) {
350		ai->ai_addrlen = sizeof(struct sockaddr_storage);
351		if (ai->ai_family == AF_INET)
352		{
353			sockin = (struct sockaddr_in *)ai->ai_addr;
354			sockin->sin_family = (short) ai->ai_family;
355			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
356		}
357		else
358		{
359			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
360			sockin6->sin6_family = (short) ai->ai_family;
361			/*
362			 * we have already zeroed out the address
363			 * so we don't actually need to do this
364			 * This assignment is causing problems so
365			 * we don't do what this would do.
366			 sockin6->sin6_addr = in6addr_any;
367			 */
368		}
369#ifdef ISC_PLATFORM_HAVESALEN
370		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
371#endif
372
373		return (0);
374	}
375
376	/*
377	 * See if we have an IPv6 address
378	 */
379	if(strchr(nodename, ':') != NULL) {
380		if (inet_pton(AF_INET6, nodename,
381		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
382			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
383			ai->ai_family = AF_INET6;
384			ai->ai_addrlen = sizeof(struct sockaddr_in6);
385			return (0);
386		}
387	}
388
389	/*
390	 * See if we have an IPv4 address
391	 */
392	if (inet_pton(AF_INET, nodename,
393	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
394		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
395		ai->ai_family = AF_INET;
396		ai->ai_addrlen = sizeof(struct sockaddr_in);
397		return (0);
398	}
399
400	/*
401	 * If the numeric host flag is set, don't attempt resolution
402	 */
403	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
404		return (EAI_NONAME);
405
406	/*
407	 * Look for a name
408	 */
409
410	errval = DNSlookup_name(nodename, AF_INET, &hp);
411
412	if (hp == NULL) {
413		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
414			return (EAI_AGAIN);
415		else if (errval == EAI_NONAME) {
416			if (inet_pton(AF_INET, nodename,
417			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
418				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
419				ai->ai_family = AF_INET;
420				ai->ai_addrlen = sizeof(struct sockaddr_in);
421				return (0);
422			}
423			return (errval);
424		}
425		else
426		{
427			return (errval);
428		}
429	}
430	ai->ai_family = hp->h_addrtype;
431	ai->ai_addrlen = sizeof(struct sockaddr);
432	sockin = (struct sockaddr_in *)ai->ai_addr;
433	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
434	ai->ai_addr->sa_family = hp->h_addrtype;
435#ifdef ISC_PLATFORM_HAVESALEN
436	ai->ai_addr->sa_len = sizeof(struct sockaddr);
437#endif
438	if (hints != NULL && hints->ai_flags & AI_CANONNAME)
439		ai->ai_canonname = estrdup(hp->h_name);
440	return (0);
441}
442
443#endif /* !ISC_PLATFORM_HAVEIPV6 */
444