Home | History | Annotate | Line # | Download | only in libntp
ntp_rfc2553.c revision 1.1.1.3
      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 	NTP_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