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