Home | History | Annotate | Line # | Download | only in libntp
ntp_rfc2553.c revision 1.1.1.2.4.1
      1 /*	$NetBSD: ntp_rfc2553.c,v 1.1.1.2.4.1 2014/12/24 00:05:20 riz 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_string.h"
     86 #include "ntp_debug.h"
     87 
     88 
     89 /*
     90  * copy_addrinfo()	- copy a single addrinfo to malloc()'d block.
     91  * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
     92  *
     93  * Copies an addrinfo list and its associated data to a contiguous block
     94  * of storage from emalloc().  Callback routines invoked via
     95  * getaddrinfo_sometime() have access to the resulting addrinfo list
     96  * only until they return.  This routine provides an easy way to make a
     97  * persistent copy.  Although the list provided to gai_sometime_callback
     98  * routines is similarly contiguous, to keep this code usable in any
     99  * context where we might want to duplicate an addrinfo list, it does
    100  * not require the input list be contiguous.
    101  *
    102  * The returned list head pointer is passed to free() to release the
    103  * entire list.
    104  *
    105  * In keeping with the rest of the NTP distribution, sockaddr_u is used
    106  * in preference to struct sockaddr_storage, which is a member of the
    107  * former union and so compatible.
    108  *
    109  * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
    110  * not being defined, copy_addrinfo_*() are exceptions.
    111  */
    112 struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
    113 #ifdef EREALLOC_CALLSITE
    114 								   ,
    115 				       const char *, int
    116 #endif
    117 				       );
    118 
    119 
    120 struct addrinfo *
    121 copy_addrinfo_impl(
    122 	const struct addrinfo *	src
    123 #ifdef EREALLOC_CALLSITE
    124 				   ,
    125 	const char *		caller_file,
    126 	int			caller_line
    127 #endif
    128 	)
    129 {
    130 	return copy_addrinfo_common(src, TRUE
    131 #ifdef EREALLOC_CALLSITE
    132 					      ,
    133 				    caller_file, caller_line
    134 #endif
    135 				    );
    136 }
    137 
    138 
    139 struct addrinfo *
    140 copy_addrinfo_list_impl(
    141 	const struct addrinfo *	src
    142 #ifdef EREALLOC_CALLSITE
    143 				   ,
    144 	const char *		caller_file,
    145 	int			caller_line
    146 #endif
    147 	)
    148 {
    149 	return copy_addrinfo_common(src, FALSE
    150 #ifdef EREALLOC_CALLSITE
    151 					      ,
    152 				    caller_file, caller_line
    153 #endif
    154 				    );
    155 }
    156 
    157 
    158 struct addrinfo *
    159 copy_addrinfo_common(
    160 	const struct addrinfo *	src,
    161 	int			just_one
    162 #ifdef EREALLOC_CALLSITE
    163 					,
    164 	const char *		caller_file,
    165 	int			caller_line
    166 #endif
    167 	)
    168 {
    169 	const struct addrinfo *	ai_src;
    170 	const struct addrinfo *	ai_nxt;
    171 	struct addrinfo *	ai_cpy;
    172 	struct addrinfo *	dst;
    173 	sockaddr_u *		psau;
    174 	char *			pcanon;
    175 	u_int			elements;
    176 	size_t			octets;
    177 	size_t			canons_octets;
    178 	size_t			str_octets;
    179 
    180 	elements = 0;
    181 	canons_octets = 0;
    182 
    183 	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
    184 		if (just_one)
    185 			ai_nxt = NULL;
    186 		else
    187 			ai_nxt = ai_src->ai_next;
    188 		++elements;
    189 		if (NULL != ai_src->ai_canonname)
    190 			canons_octets += 1 + strlen(ai_src->ai_canonname);
    191 	}
    192 
    193 	octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
    194 	octets += canons_octets;
    195 
    196 	dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
    197 			    caller_line);
    198 	ai_cpy = dst;
    199 	psau = (void *)(ai_cpy + elements);
    200 	pcanon = (void *)(psau + elements);
    201 
    202 	for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
    203 		if (just_one)
    204 			ai_nxt = NULL;
    205 		else
    206 			ai_nxt = ai_src->ai_next;
    207 		*ai_cpy = *ai_src;
    208 		REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u));
    209 		memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
    210 		ai_cpy->ai_addr = &psau->sa;
    211 		++psau;
    212 		if (NULL != ai_cpy->ai_canonname) {
    213 			ai_cpy->ai_canonname = pcanon;
    214 			str_octets = 1 + strlen(ai_src->ai_canonname);
    215 			memcpy(pcanon, ai_src->ai_canonname, str_octets);
    216 			pcanon += str_octets;
    217 		}
    218 		if (NULL != ai_cpy->ai_next) {
    219 			if (just_one)
    220 				ai_cpy->ai_next = NULL;
    221 			else
    222 				ai_cpy->ai_next = ai_cpy + 1;
    223 		}
    224 		++ai_cpy;
    225 	}
    226 	NTP_ENSURE(pcanon == ((char *)dst + octets));
    227 
    228 	return dst;
    229 }
    230 
    231 
    232 #ifndef ISC_PLATFORM_HAVEIPV6
    233 
    234 static char *ai_errlist[] = {
    235 	"Success",
    236 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
    237 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
    238 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
    239 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
    240 	"ai_family not supported",			/* EAI_FAMILY     */
    241 	"Memory allocation failure", 			/* EAI_MEMORY     */
    242 	"No address associated with hostname", 		/* EAI_NODATA     */
    243 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
    244 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
    245 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
    246 	"System error returned in errno", 		/* EAI_SYSTEM     */
    247 	"Invalid value for hints",			/* EAI_BADHINTS	  */
    248 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
    249 	"Unknown error", 				/* EAI_MAX        */
    250 };
    251 
    252 /*
    253  * Local declaration
    254  */
    255 int
    256 DNSlookup_name(
    257 	const char *name,
    258 	int ai_family,
    259 	struct hostent **Addresses
    260 );
    261 
    262 #ifndef SYS_WINNT
    263 /*
    264  * Encapsulate gethostbyname to control the error code
    265  */
    266 int
    267 DNSlookup_name(
    268 	const char *name,
    269 	int ai_family,
    270 	struct hostent **Addresses
    271 )
    272 {
    273 	*Addresses = gethostbyname(name);
    274 	return (h_errno);
    275 }
    276 #endif
    277 
    278 static	int do_nodename (const char *nodename, struct addrinfo *ai,
    279     const struct addrinfo *hints);
    280 
    281 int
    282 getaddrinfo (const char *nodename, const char *servname,
    283 	const struct addrinfo *hints, struct addrinfo **res)
    284 {
    285 	int rval;
    286 	struct servent *sp;
    287 	struct addrinfo *ai = NULL;
    288 	int port;
    289 	const char *proto = NULL;
    290 	int family, socktype, flags, protocol;
    291 
    292 
    293 	/*
    294 	 * If no name is provide just return an error
    295 	 */
    296 	if (nodename == NULL && servname == NULL)
    297 		return (EAI_NONAME);
    298 
    299 	ai = calloc(sizeof(struct addrinfo), 1);
    300 	if (ai == NULL)
    301 		return (EAI_MEMORY);
    302 
    303 	/*
    304 	 * Copy default values from hints, if available
    305 	 */
    306 	if (hints != NULL) {
    307 		ai->ai_flags = hints->ai_flags;
    308 		ai->ai_family = hints->ai_family;
    309 		ai->ai_socktype = hints->ai_socktype;
    310 		ai->ai_protocol = hints->ai_protocol;
    311 
    312 		family = hints->ai_family;
    313 		socktype = hints->ai_socktype;
    314 		protocol = hints->ai_protocol;
    315 		flags = hints->ai_flags;
    316 
    317 		switch (family) {
    318 		case AF_UNSPEC:
    319 			switch (hints->ai_socktype) {
    320 			case SOCK_STREAM:
    321 				proto = "tcp";
    322 				break;
    323 			case SOCK_DGRAM:
    324 				proto = "udp";
    325 				break;
    326 			}
    327 			break;
    328 		case AF_INET:
    329 		case AF_INET6:
    330 			switch (hints->ai_socktype) {
    331 			case 0:
    332 				break;
    333 			case SOCK_STREAM:
    334 				proto = "tcp";
    335 				break;
    336 			case SOCK_DGRAM:
    337 				proto = "udp";
    338 				break;
    339 			case SOCK_RAW:
    340 				break;
    341 			default:
    342 				return (EAI_SOCKTYPE);
    343 			}
    344 			break;
    345 #ifdef	AF_LOCAL
    346 		case AF_LOCAL:
    347 			switch (hints->ai_socktype) {
    348 			case 0:
    349 				break;
    350 			case SOCK_STREAM:
    351 				break;
    352 			case SOCK_DGRAM:
    353 				break;
    354 			default:
    355 				return (EAI_SOCKTYPE);
    356 			}
    357 			break;
    358 #endif
    359 		default:
    360 			return (EAI_FAMILY);
    361 		}
    362 	} else {
    363 		protocol = 0;
    364 		family = 0;
    365 		socktype = 0;
    366 		flags = 0;
    367 	}
    368 
    369 	rval = do_nodename(nodename, ai, hints);
    370 	if (rval != 0) {
    371 		freeaddrinfo(ai);
    372 		return (rval);
    373 	}
    374 
    375 	/*
    376 	 * First, look up the service name (port) if it was
    377 	 * requested.  If the socket type wasn't specified, then
    378 	 * try and figure it out.
    379 	 */
    380 	if (servname != NULL) {
    381 		char *e;
    382 
    383 		port = strtol(servname, &e, 10);
    384 		if (*e == '\0') {
    385 			if (socktype == 0)
    386 				return (EAI_SOCKTYPE);
    387 			if (port < 0 || port > 65535)
    388 				return (EAI_SERVICE);
    389 			port = htons((unsigned short) port);
    390 		} else {
    391 			sp = getservbyname(servname, proto);
    392 			if (sp == NULL)
    393 				return (EAI_SERVICE);
    394 			port = sp->s_port;
    395 			if (socktype == 0) {
    396 				if (strcmp(sp->s_proto, "tcp") == 0)
    397 					socktype = SOCK_STREAM;
    398 				else if (strcmp(sp->s_proto, "udp") == 0)
    399 					socktype = SOCK_DGRAM;
    400 			}
    401 		}
    402 	} else
    403 		port = 0;
    404 
    405 	/*
    406 	 *
    407 	 * Set up the port number
    408 	 */
    409 	if (ai->ai_family == AF_INET)
    410 		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
    411 	else if (ai->ai_family == AF_INET6)
    412 		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
    413 	*res = ai;
    414 	return (0);
    415 }
    416 
    417 void
    418 freeaddrinfo(struct addrinfo *ai)
    419 {
    420 	if (ai->ai_canonname != NULL)
    421 	{
    422 		free(ai->ai_canonname);
    423 		ai->ai_canonname = NULL;
    424 	}
    425 	if (ai->ai_addr != NULL)
    426 	{
    427 		free(ai->ai_addr);
    428 		ai->ai_addr = NULL;
    429 	}
    430 	free(ai);
    431 	ai = NULL;
    432 }
    433 
    434 int
    435 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
    436 	size_t hostlen, char *serv, size_t servlen, int flags)
    437 {
    438 	struct hostent *hp;
    439 
    440 	if (sa->sa_family != AF_INET)
    441 		return (EAI_FAMILY);
    442 	hp = gethostbyaddr(
    443 	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
    444 	    4, AF_INET);
    445 	if (hp == NULL) {
    446 		if (h_errno == TRY_AGAIN)
    447 			return (EAI_AGAIN);
    448 		else
    449 			return (EAI_FAIL);
    450 	}
    451 	if (host != NULL && hostlen > 0)
    452 		strlcpy(host, hp->h_name, hostlen);
    453 	return (0);
    454 }
    455 
    456 char *
    457 gai_strerror(int ecode)
    458 {
    459 	if (ecode < 0 || ecode > EAI_MAX)
    460 		ecode = EAI_MAX;
    461 	return ai_errlist[ecode];
    462 }
    463 
    464 static int
    465 do_nodename(
    466 	const char *nodename,
    467 	struct addrinfo *ai,
    468 	const struct addrinfo *hints)
    469 {
    470 	struct hostent *hp = NULL;
    471 	struct sockaddr_in *sockin;
    472 	struct sockaddr_in6 *sockin6;
    473 	int errval;
    474 
    475 	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
    476 	if (ai->ai_addr == NULL)
    477 		return (EAI_MEMORY);
    478 
    479 	/*
    480 	 * For an empty node name just use the wildcard.
    481 	 * NOTE: We need to assume that the address family is
    482 	 * set elsewhere so that we can set the appropriate wildcard
    483 	 */
    484 	if (nodename == NULL) {
    485 		ai->ai_addrlen = sizeof(struct sockaddr_storage);
    486 		if (ai->ai_family == AF_INET)
    487 		{
    488 			sockin = (struct sockaddr_in *)ai->ai_addr;
    489 			sockin->sin_family = (short) ai->ai_family;
    490 			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
    491 		}
    492 		else
    493 		{
    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