Home | History | Annotate | Line # | Download | only in libntp
ntp_rfc2553.c revision 1.1.1.8
      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 		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 
    233 static 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  */
    254 int
    255 DNSlookup_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  */
    265 int
    266 DNSlookup_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 
    277 static	int do_nodename (const char *nodename, struct addrinfo *ai,
    278     const struct addrinfo *hints);
    279 
    280 int
    281 getaddrinfo (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 
    416 void
    417 freeaddrinfo(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 
    433 int
    434 getnameinfo (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 
    455 char *
    456 gai_strerror(int ecode)
    457 {
    458 	if (ecode < 0 || ecode > EAI_MAX)
    459 		ecode = EAI_MAX;
    460 	return ai_errlist[ecode];
    461 }
    462 
    463 static int
    464 do_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