ntp_rfc2553.c revision 293896
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * Copyright (c) 1982, 1986, 1990, 1993
32 *	The Regents of the University of California.  All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 *    notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 *    notice, this list of conditions and the following disclaimer in the
41 *    documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 *    must display the following acknowledgement:
44 *	This product includes software developed by the University of
45 *	California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 */
63
64/*
65 * Compatability shims with the rfc2553 API to simplify ntp.
66 */
67
68#include <config.h>
69
70#include <sys/types.h>
71#include <ctype.h>
72#ifdef HAVE_SYS_SOCKET_H
73#include <sys/socket.h>
74#endif
75#include <isc/net.h>
76#ifdef HAVE_NETINET_IN_H
77#include <netinet/in.h>
78#endif
79#include "ntp_rfc2553.h"
80
81#include "ntpd.h"
82#include "ntp_malloc.h"
83#include "ntp_string.h"
84#include "ntp_debug.h"
85
86
87/*
88 * copy_addrinfo()	- copy a single addrinfo to malloc()'d block.
89 * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
90 *
91 * Copies an addrinfo list and its associated data to a contiguous block
92 * of storage from emalloc().  Callback routines invoked via
93 * getaddrinfo_sometime() have access to the resulting addrinfo list
94 * only until they return.  This routine provides an easy way to make a
95 * persistent copy.  Although the list provided to gai_sometime_callback
96 * routines is similarly contiguous, to keep this code usable in any
97 * context where we might want to duplicate an addrinfo list, it does
98 * not require the input list be contiguous.
99 *
100 * The returned list head pointer is passed to free() to release the
101 * entire list.
102 *
103 * In keeping with the rest of the NTP distribution, sockaddr_u is used
104 * in preference to struct sockaddr_storage, which is a member of the
105 * former union and so compatible.
106 *
107 * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
108 * not being defined, copy_addrinfo_*() are exceptions.
109 */
110struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
111#ifdef EREALLOC_CALLSITE
112								   ,
113				       const char *, int
114#endif
115				       );
116
117
118struct addrinfo *
119copy_addrinfo_impl(
120	const struct addrinfo *	src
121#ifdef EREALLOC_CALLSITE
122				   ,
123	const char *		caller_file,
124	int			caller_line
125#endif
126	)
127{
128	return copy_addrinfo_common(src, TRUE
129#ifdef EREALLOC_CALLSITE
130					      ,
131				    caller_file, caller_line
132#endif
133				    );
134}
135
136
137struct addrinfo *
138copy_addrinfo_list_impl(
139	const struct addrinfo *	src
140#ifdef EREALLOC_CALLSITE
141				   ,
142	const char *		caller_file,
143	int			caller_line
144#endif
145	)
146{
147	return copy_addrinfo_common(src, FALSE
148#ifdef EREALLOC_CALLSITE
149					      ,
150				    caller_file, caller_line
151#endif
152				    );
153}
154
155
156struct addrinfo *
157copy_addrinfo_common(
158	const struct addrinfo *	src,
159	int			just_one
160#ifdef EREALLOC_CALLSITE
161					,
162	const char *		caller_file,
163	int			caller_line
164#endif
165	)
166{
167	const struct addrinfo *	ai_src;
168	const struct addrinfo *	ai_nxt;
169	struct addrinfo *	ai_cpy;
170	struct addrinfo *	dst;
171	sockaddr_u *		psau;
172	char *			pcanon;
173	u_int			elements;
174	size_t			octets;
175	size_t			canons_octets;
176	size_t			str_octets;
177
178	elements = 0;
179	canons_octets = 0;
180
181	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
182		if (just_one)
183			ai_nxt = NULL;
184		else
185			ai_nxt = ai_src->ai_next;
186		++elements;
187		if (NULL != ai_src->ai_canonname)
188			canons_octets += 1 + strlen(ai_src->ai_canonname);
189	}
190
191	octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
192	octets += canons_octets;
193
194	dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
195			    caller_line);
196	ai_cpy = dst;
197	psau = (void *)(ai_cpy + elements);
198	pcanon = (void *)(psau + elements);
199
200	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
201		if (just_one)
202			ai_nxt = NULL;
203		else
204			ai_nxt = ai_src->ai_next;
205		*ai_cpy = *ai_src;
206		DEBUG_INSIST(ai_cpy->ai_canonname == ai_src->ai_canonname);
207		INSIST(ai_src->ai_addrlen <= sizeof(sockaddr_u));
208		memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
209		ai_cpy->ai_addr = &psau->sa;
210		++psau;
211		if (NULL != ai_src->ai_canonname) {
212			ai_cpy->ai_canonname = pcanon;
213			str_octets = 1 + strlen(ai_src->ai_canonname);
214			memcpy(pcanon, ai_src->ai_canonname, str_octets);
215			pcanon += str_octets;
216		}
217		if (NULL != ai_cpy->ai_next) {
218			if (just_one)
219				ai_cpy->ai_next = NULL;
220			else
221				ai_cpy->ai_next = ai_cpy + 1;
222		}
223		++ai_cpy;
224	}
225	ENSURE(pcanon == ((char *)dst + octets));
226
227	return dst;
228}
229
230
231#ifndef ISC_PLATFORM_HAVEIPV6
232
233static char *ai_errlist[] = {
234	"Success",
235	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
236	"Temporary failure in name resolution",		/* EAI_AGAIN      */
237	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
238	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
239	"ai_family not supported",			/* EAI_FAMILY     */
240	"Memory allocation failure", 			/* EAI_MEMORY     */
241	"No address associated with hostname", 		/* EAI_NODATA     */
242	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
243	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
244	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
245	"System error returned in errno", 		/* EAI_SYSTEM     */
246	"Invalid value for hints",			/* EAI_BADHINTS	  */
247	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
248	"Unknown error", 				/* EAI_MAX        */
249};
250
251/*
252 * Local declaration
253 */
254int
255DNSlookup_name(
256	const char *name,
257	int ai_family,
258	struct hostent **Addresses
259);
260
261#ifndef SYS_WINNT
262/*
263 * Encapsulate gethostbyname to control the error code
264 */
265int
266DNSlookup_name(
267	const char *name,
268	int ai_family,
269	struct hostent **Addresses
270)
271{
272	*Addresses = gethostbyname(name);
273	return (h_errno);
274}
275#endif
276
277static	int do_nodename (const char *nodename, struct addrinfo *ai,
278    const struct addrinfo *hints);
279
280int
281getaddrinfo (const char *nodename, const char *servname,
282	const struct addrinfo *hints, struct addrinfo **res)
283{
284	int rval;
285	struct servent *sp;
286	struct addrinfo *ai = NULL;
287	int port;
288	const char *proto = NULL;
289	int family, socktype, flags, protocol;
290
291
292	/*
293	 * If no name is provide just return an error
294	 */
295	if (nodename == NULL && servname == NULL)
296		return (EAI_NONAME);
297
298	ai = calloc(sizeof(struct addrinfo), 1);
299	if (ai == NULL)
300		return (EAI_MEMORY);
301
302	/*
303	 * Copy default values from hints, if available
304	 */
305	if (hints != NULL) {
306		ai->ai_flags = hints->ai_flags;
307		ai->ai_family = hints->ai_family;
308		ai->ai_socktype = hints->ai_socktype;
309		ai->ai_protocol = hints->ai_protocol;
310
311		family = hints->ai_family;
312		socktype = hints->ai_socktype;
313		protocol = hints->ai_protocol;
314		flags = hints->ai_flags;
315
316		switch (family) {
317		case AF_UNSPEC:
318			switch (hints->ai_socktype) {
319			case SOCK_STREAM:
320				proto = "tcp";
321				break;
322			case SOCK_DGRAM:
323				proto = "udp";
324				break;
325			}
326			break;
327		case AF_INET:
328		case AF_INET6:
329			switch (hints->ai_socktype) {
330			case 0:
331				break;
332			case SOCK_STREAM:
333				proto = "tcp";
334				break;
335			case SOCK_DGRAM:
336				proto = "udp";
337				break;
338			case SOCK_RAW:
339				break;
340			default:
341				return (EAI_SOCKTYPE);
342			}
343			break;
344#ifdef	AF_LOCAL
345		case AF_LOCAL:
346			switch (hints->ai_socktype) {
347			case 0:
348				break;
349			case SOCK_STREAM:
350				break;
351			case SOCK_DGRAM:
352				break;
353			default:
354				return (EAI_SOCKTYPE);
355			}
356			break;
357#endif
358		default:
359			return (EAI_FAMILY);
360		}
361	} else {
362		protocol = 0;
363		family = 0;
364		socktype = 0;
365		flags = 0;
366	}
367
368	rval = do_nodename(nodename, ai, hints);
369	if (rval != 0) {
370		freeaddrinfo(ai);
371		return (rval);
372	}
373
374	/*
375	 * First, look up the service name (port) if it was
376	 * requested.  If the socket type wasn't specified, then
377	 * try and figure it out.
378	 */
379	if (servname != NULL) {
380		char *e;
381
382		port = strtol(servname, &e, 10);
383		if (*e == '\0') {
384			if (socktype == 0)
385				return (EAI_SOCKTYPE);
386			if (port < 0 || port > 65535)
387				return (EAI_SERVICE);
388			port = htons((unsigned short) port);
389		} else {
390			sp = getservbyname(servname, proto);
391			if (sp == NULL)
392				return (EAI_SERVICE);
393			port = sp->s_port;
394			if (socktype == 0) {
395				if (strcmp(sp->s_proto, "tcp") == 0)
396					socktype = SOCK_STREAM;
397				else if (strcmp(sp->s_proto, "udp") == 0)
398					socktype = SOCK_DGRAM;
399			}
400		}
401	} else
402		port = 0;
403
404	/*
405	 *
406	 * Set up the port number
407	 */
408	if (ai->ai_family == AF_INET)
409		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
410	else if (ai->ai_family == AF_INET6)
411		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
412	*res = ai;
413	return (0);
414}
415
416void
417freeaddrinfo(struct addrinfo *ai)
418{
419	if (ai->ai_canonname != NULL)
420	{
421		free(ai->ai_canonname);
422		ai->ai_canonname = NULL;
423	}
424	if (ai->ai_addr != NULL)
425	{
426		free(ai->ai_addr);
427		ai->ai_addr = NULL;
428	}
429	free(ai);
430	ai = NULL;
431}
432
433int
434getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
435	size_t hostlen, char *serv, size_t servlen, int flags)
436{
437	struct hostent *hp;
438
439	if (sa->sa_family != AF_INET)
440		return (EAI_FAMILY);
441	hp = gethostbyaddr(
442	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
443	    4, AF_INET);
444	if (hp == NULL) {
445		if (h_errno == TRY_AGAIN)
446			return (EAI_AGAIN);
447		else
448			return (EAI_FAIL);
449	}
450	if (host != NULL && hostlen > 0)
451		strlcpy(host, hp->h_name, hostlen);
452	return (0);
453}
454
455char *
456gai_strerror(int ecode)
457{
458	if (ecode < 0 || ecode > EAI_MAX)
459		ecode = EAI_MAX;
460	return ai_errlist[ecode];
461}
462
463static int
464do_nodename(
465	const char *nodename,
466	struct addrinfo *ai,
467	const struct addrinfo *hints)
468{
469	struct hostent *hp = NULL;
470	struct sockaddr_in *sockin;
471	struct sockaddr_in6 *sockin6;
472	int errval;
473
474	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
475	if (ai->ai_addr == NULL)
476		return (EAI_MEMORY);
477
478	/*
479	 * For an empty node name just use the wildcard.
480	 * NOTE: We need to assume that the address family is
481	 * set elsewhere so that we can set the appropriate wildcard
482	 */
483	if (nodename == NULL) {
484		if (ai->ai_family == AF_INET)
485		{
486			ai->ai_addrlen = sizeof(struct sockaddr_in);
487			sockin = (struct sockaddr_in *)ai->ai_addr;
488			sockin->sin_family = (short) ai->ai_family;
489			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
490		}
491		else
492		{
493			ai->ai_addrlen = sizeof(struct sockaddr_in6);
494			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
495			sockin6->sin6_family = (short) ai->ai_family;
496			/*
497			 * we have already zeroed out the address
498			 * so we don't actually need to do this
499			 * This assignment is causing problems so
500			 * we don't do what this would do.
501			 sockin6->sin6_addr = in6addr_any;
502			 */
503		}
504#ifdef ISC_PLATFORM_HAVESALEN
505		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
506#endif
507
508		return (0);
509	}
510
511	/*
512	 * See if we have an IPv6 address
513	 */
514	if(strchr(nodename, ':') != NULL) {
515		if (inet_pton(AF_INET6, nodename,
516		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
517			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
518			ai->ai_family = AF_INET6;
519			ai->ai_addrlen = sizeof(struct sockaddr_in6);
520			return (0);
521		}
522	}
523
524	/*
525	 * See if we have an IPv4 address
526	 */
527	if (inet_pton(AF_INET, nodename,
528	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
529		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
530		ai->ai_family = AF_INET;
531		ai->ai_addrlen = sizeof(struct sockaddr_in);
532		return (0);
533	}
534
535	/*
536	 * If the numeric host flag is set, don't attempt resolution
537	 */
538	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
539		return (EAI_NONAME);
540
541	/*
542	 * Look for a name
543	 */
544
545	errval = DNSlookup_name(nodename, AF_INET, &hp);
546
547	if (hp == NULL) {
548		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
549			return (EAI_AGAIN);
550		else if (errval == EAI_NONAME) {
551			if (inet_pton(AF_INET, nodename,
552			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
553				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
554				ai->ai_family = AF_INET;
555				ai->ai_addrlen = sizeof(struct sockaddr_in);
556				return (0);
557			}
558			return (errval);
559		}
560		else
561		{
562			return (errval);
563		}
564	}
565	ai->ai_family = hp->h_addrtype;
566	ai->ai_addrlen = sizeof(struct sockaddr);
567	sockin = (struct sockaddr_in *)ai->ai_addr;
568	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
569	ai->ai_addr->sa_family = hp->h_addrtype;
570#ifdef ISC_PLATFORM_HAVESALEN
571	ai->ai_addr->sa_len = sizeof(struct sockaddr);
572#endif
573	if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
574		ai->ai_canonname = estrdup(hp->h_name);
575	return (0);
576}
577
578#endif /* !ISC_PLATFORM_HAVEIPV6 */
579