xref: /freebsd/contrib/ntp/libntp/ntp_rfc2553.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
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  */
110 struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
111 #ifdef EREALLOC_CALLSITE
112 								   ,
113 				       const char *, int
114 #endif
115 				       );
116 
117 
118 struct addrinfo *
119 copy_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 
137 struct addrinfo *
138 copy_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 
156 struct addrinfo *
157 copy_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 	ENSURE(pcanon == ((char *)dst + octets));
225 
226 	return dst;
227 }
228 
229 
230 #ifndef ISC_PLATFORM_HAVEIPV6
231 
232 static 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  */
253 int
254 DNSlookup_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  */
264 int
265 DNSlookup_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 
276 static	int do_nodename (const char *nodename, struct addrinfo *ai,
277     const struct addrinfo *hints);
278 
279 int
280 getaddrinfo (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 
415 void
416 freeaddrinfo(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 
432 int
433 getnameinfo (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 
454 char *
455 gai_strerror(int ecode)
456 {
457 	if (ecode < 0 || ecode > EAI_MAX)
458 		ecode = EAI_MAX;
459 	return ai_errlist[ecode];
460 }
461 
462 static int
463 do_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