ntp_rfc2553.c revision 280849
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		REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u));
207		memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
208		ai_cpy->ai_addr = &psau->sa;
209		++psau;
210		if (NULL != ai_cpy->ai_canonname) {
211			ai_cpy->ai_canonname = pcanon;
212			str_octets = 1 + strlen(ai_src->ai_canonname);
213			memcpy(pcanon, ai_src->ai_canonname, str_octets);
214			pcanon += str_octets;
215		}
216		if (NULL != ai_cpy->ai_next) {
217			if (just_one)
218				ai_cpy->ai_next = NULL;
219			else
220				ai_cpy->ai_next = ai_cpy + 1;
221		}
222		++ai_cpy;
223	}
224	NTP_ENSURE(pcanon == ((char *)dst + octets));
225
226	return dst;
227}
228
229
230#ifndef ISC_PLATFORM_HAVEIPV6
231
232static char *ai_errlist[] = {
233	"Success",
234	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
235	"Temporary failure in name resolution",		/* EAI_AGAIN      */
236	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
237	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
238	"ai_family not supported",			/* EAI_FAMILY     */
239	"Memory allocation failure", 			/* EAI_MEMORY     */
240	"No address associated with hostname", 		/* EAI_NODATA     */
241	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
242	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
243	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
244	"System error returned in errno", 		/* EAI_SYSTEM     */
245	"Invalid value for hints",			/* EAI_BADHINTS	  */
246	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
247	"Unknown error", 				/* EAI_MAX        */
248};
249
250/*
251 * Local declaration
252 */
253int
254DNSlookup_name(
255	const char *name,
256	int ai_family,
257	struct hostent **Addresses
258);
259
260#ifndef SYS_WINNT
261/*
262 * Encapsulate gethostbyname to control the error code
263 */
264int
265DNSlookup_name(
266	const char *name,
267	int ai_family,
268	struct hostent **Addresses
269)
270{
271	*Addresses = gethostbyname(name);
272	return (h_errno);
273}
274#endif
275
276static	int do_nodename (const char *nodename, struct addrinfo *ai,
277    const struct addrinfo *hints);
278
279int
280getaddrinfo (const char *nodename, const char *servname,
281	const struct addrinfo *hints, struct addrinfo **res)
282{
283	int rval;
284	struct servent *sp;
285	struct addrinfo *ai = NULL;
286	int port;
287	const char *proto = NULL;
288	int family, socktype, flags, protocol;
289
290
291	/*
292	 * If no name is provide just return an error
293	 */
294	if (nodename == NULL && servname == NULL)
295		return (EAI_NONAME);
296
297	ai = calloc(sizeof(struct addrinfo), 1);
298	if (ai == NULL)
299		return (EAI_MEMORY);
300
301	/*
302	 * Copy default values from hints, if available
303	 */
304	if (hints != NULL) {
305		ai->ai_flags = hints->ai_flags;
306		ai->ai_family = hints->ai_family;
307		ai->ai_socktype = hints->ai_socktype;
308		ai->ai_protocol = hints->ai_protocol;
309
310		family = hints->ai_family;
311		socktype = hints->ai_socktype;
312		protocol = hints->ai_protocol;
313		flags = hints->ai_flags;
314
315		switch (family) {
316		case AF_UNSPEC:
317			switch (hints->ai_socktype) {
318			case SOCK_STREAM:
319				proto = "tcp";
320				break;
321			case SOCK_DGRAM:
322				proto = "udp";
323				break;
324			}
325			break;
326		case AF_INET:
327		case AF_INET6:
328			switch (hints->ai_socktype) {
329			case 0:
330				break;
331			case SOCK_STREAM:
332				proto = "tcp";
333				break;
334			case SOCK_DGRAM:
335				proto = "udp";
336				break;
337			case SOCK_RAW:
338				break;
339			default:
340				return (EAI_SOCKTYPE);
341			}
342			break;
343#ifdef	AF_LOCAL
344		case AF_LOCAL:
345			switch (hints->ai_socktype) {
346			case 0:
347				break;
348			case SOCK_STREAM:
349				break;
350			case SOCK_DGRAM:
351				break;
352			default:
353				return (EAI_SOCKTYPE);
354			}
355			break;
356#endif
357		default:
358			return (EAI_FAMILY);
359		}
360	} else {
361		protocol = 0;
362		family = 0;
363		socktype = 0;
364		flags = 0;
365	}
366
367	rval = do_nodename(nodename, ai, hints);
368	if (rval != 0) {
369		freeaddrinfo(ai);
370		return (rval);
371	}
372
373	/*
374	 * First, look up the service name (port) if it was
375	 * requested.  If the socket type wasn't specified, then
376	 * try and figure it out.
377	 */
378	if (servname != NULL) {
379		char *e;
380
381		port = strtol(servname, &e, 10);
382		if (*e == '\0') {
383			if (socktype == 0)
384				return (EAI_SOCKTYPE);
385			if (port < 0 || port > 65535)
386				return (EAI_SERVICE);
387			port = htons((unsigned short) port);
388		} else {
389			sp = getservbyname(servname, proto);
390			if (sp == NULL)
391				return (EAI_SERVICE);
392			port = sp->s_port;
393			if (socktype == 0) {
394				if (strcmp(sp->s_proto, "tcp") == 0)
395					socktype = SOCK_STREAM;
396				else if (strcmp(sp->s_proto, "udp") == 0)
397					socktype = SOCK_DGRAM;
398			}
399		}
400	} else
401		port = 0;
402
403	/*
404	 *
405	 * Set up the port number
406	 */
407	if (ai->ai_family == AF_INET)
408		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
409	else if (ai->ai_family == AF_INET6)
410		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
411	*res = ai;
412	return (0);
413}
414
415void
416freeaddrinfo(struct addrinfo *ai)
417{
418	if (ai->ai_canonname != NULL)
419	{
420		free(ai->ai_canonname);
421		ai->ai_canonname = NULL;
422	}
423	if (ai->ai_addr != NULL)
424	{
425		free(ai->ai_addr);
426		ai->ai_addr = NULL;
427	}
428	free(ai);
429	ai = NULL;
430}
431
432int
433getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
434	size_t hostlen, char *serv, size_t servlen, int flags)
435{
436	struct hostent *hp;
437
438	if (sa->sa_family != AF_INET)
439		return (EAI_FAMILY);
440	hp = gethostbyaddr(
441	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
442	    4, AF_INET);
443	if (hp == NULL) {
444		if (h_errno == TRY_AGAIN)
445			return (EAI_AGAIN);
446		else
447			return (EAI_FAIL);
448	}
449	if (host != NULL && hostlen > 0)
450		strlcpy(host, hp->h_name, hostlen);
451	return (0);
452}
453
454char *
455gai_strerror(int ecode)
456{
457	if (ecode < 0 || ecode > EAI_MAX)
458		ecode = EAI_MAX;
459	return ai_errlist[ecode];
460}
461
462static int
463do_nodename(
464	const char *nodename,
465	struct addrinfo *ai,
466	const struct addrinfo *hints)
467{
468	struct hostent *hp = NULL;
469	struct sockaddr_in *sockin;
470	struct sockaddr_in6 *sockin6;
471	int errval;
472
473	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
474	if (ai->ai_addr == NULL)
475		return (EAI_MEMORY);
476
477	/*
478	 * For an empty node name just use the wildcard.
479	 * NOTE: We need to assume that the address family is
480	 * set elsewhere so that we can set the appropriate wildcard
481	 */
482	if (nodename == NULL) {
483		ai->ai_addrlen = sizeof(struct sockaddr_storage);
484		if (ai->ai_family == AF_INET)
485		{
486			sockin = (struct sockaddr_in *)ai->ai_addr;
487			sockin->sin_family = (short) ai->ai_family;
488			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
489		}
490		else
491		{
492			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
493			sockin6->sin6_family = (short) ai->ai_family;
494			/*
495			 * we have already zeroed out the address
496			 * so we don't actually need to do this
497			 * This assignment is causing problems so
498			 * we don't do what this would do.
499			 sockin6->sin6_addr = in6addr_any;
500			 */
501		}
502#ifdef ISC_PLATFORM_HAVESALEN
503		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
504#endif
505
506		return (0);
507	}
508
509	/*
510	 * See if we have an IPv6 address
511	 */
512	if(strchr(nodename, ':') != NULL) {
513		if (inet_pton(AF_INET6, nodename,
514		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
515			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
516			ai->ai_family = AF_INET6;
517			ai->ai_addrlen = sizeof(struct sockaddr_in6);
518			return (0);
519		}
520	}
521
522	/*
523	 * See if we have an IPv4 address
524	 */
525	if (inet_pton(AF_INET, nodename,
526	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
527		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
528		ai->ai_family = AF_INET;
529		ai->ai_addrlen = sizeof(struct sockaddr_in);
530		return (0);
531	}
532
533	/*
534	 * If the numeric host flag is set, don't attempt resolution
535	 */
536	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
537		return (EAI_NONAME);
538
539	/*
540	 * Look for a name
541	 */
542
543	errval = DNSlookup_name(nodename, AF_INET, &hp);
544
545	if (hp == NULL) {
546		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
547			return (EAI_AGAIN);
548		else if (errval == EAI_NONAME) {
549			if (inet_pton(AF_INET, nodename,
550			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
551				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
552				ai->ai_family = AF_INET;
553				ai->ai_addrlen = sizeof(struct sockaddr_in);
554				return (0);
555			}
556			return (errval);
557		}
558		else
559		{
560			return (errval);
561		}
562	}
563	ai->ai_family = hp->h_addrtype;
564	ai->ai_addrlen = sizeof(struct sockaddr);
565	sockin = (struct sockaddr_in *)ai->ai_addr;
566	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
567	ai->ai_addr->sa_family = hp->h_addrtype;
568#ifdef ISC_PLATFORM_HAVESALEN
569	ai->ai_addr->sa_len = sizeof(struct sockaddr);
570#endif
571	if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
572		ai->ai_canonname = estrdup(hp->h_name);
573	return (0);
574}
575
576#endif /* !ISC_PLATFORM_HAVEIPV6 */
577