Home | History | Annotate | Line # | Download | only in libntp
ntp_rfc2553.c revision 1.1
      1 /*	$NetBSD: ntp_rfc2553.c,v 1.1 2009/12/13 16:55:04 kardel 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_stdlib.h"
     86 #include "ntp_string.h"
     87 
     88 #ifndef ISC_PLATFORM_HAVEIPV6
     89 
     90 static char *ai_errlist[] = {
     91 	"Success",
     92 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
     93 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
     94 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
     95 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
     96 	"ai_family not supported",			/* EAI_FAMILY     */
     97 	"Memory allocation failure", 			/* EAI_MEMORY     */
     98 	"No address associated with hostname", 		/* EAI_NODATA     */
     99 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
    100 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
    101 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
    102 	"System error returned in errno", 		/* EAI_SYSTEM     */
    103 	"Invalid value for hints",			/* EAI_BADHINTS	  */
    104 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
    105 	"Unknown error", 				/* EAI_MAX        */
    106 };
    107 
    108 /*
    109  * Local declaration
    110  */
    111 int
    112 DNSlookup_name(
    113 	const char *name,
    114 	int ai_family,
    115 	struct hostent **Addresses
    116 );
    117 
    118 #ifndef SYS_WINNT
    119 /*
    120  * Encapsulate gethostbyname to control the error code
    121  */
    122 int
    123 DNSlookup_name(
    124 	const char *name,
    125 	int ai_family,
    126 	struct hostent **Addresses
    127 )
    128 {
    129 	*Addresses = gethostbyname(name);
    130 	return (h_errno);
    131 }
    132 #endif
    133 
    134 static	int do_nodename (const char *nodename, struct addrinfo *ai,
    135     const struct addrinfo *hints);
    136 
    137 int
    138 getaddrinfo (const char *nodename, const char *servname,
    139 	const struct addrinfo *hints, struct addrinfo **res)
    140 {
    141 	int rval;
    142 	struct servent *sp;
    143 	struct addrinfo *ai = NULL;
    144 	int port;
    145 	const char *proto = NULL;
    146 	int family, socktype, flags, protocol;
    147 
    148 
    149 	/*
    150 	 * If no name is provide just return an error
    151 	 */
    152 	if (nodename == NULL && servname == NULL)
    153 		return (EAI_NONAME);
    154 
    155 	ai = calloc(sizeof(struct addrinfo), 1);
    156 	if (ai == NULL)
    157 		return (EAI_MEMORY);
    158 
    159 	/*
    160 	 * Copy default values from hints, if available
    161 	 */
    162 	if (hints != NULL) {
    163 		ai->ai_flags = hints->ai_flags;
    164 		ai->ai_family = hints->ai_family;
    165 		ai->ai_socktype = hints->ai_socktype;
    166 		ai->ai_protocol = hints->ai_protocol;
    167 
    168 		family = hints->ai_family;
    169 		socktype = hints->ai_socktype;
    170 		protocol = hints->ai_protocol;
    171 		flags = hints->ai_flags;
    172 
    173 		switch (family) {
    174 		case AF_UNSPEC:
    175 			switch (hints->ai_socktype) {
    176 			case SOCK_STREAM:
    177 				proto = "tcp";
    178 				break;
    179 			case SOCK_DGRAM:
    180 				proto = "udp";
    181 				break;
    182 			}
    183 			break;
    184 		case AF_INET:
    185 		case AF_INET6:
    186 			switch (hints->ai_socktype) {
    187 			case 0:
    188 				break;
    189 			case SOCK_STREAM:
    190 				proto = "tcp";
    191 				break;
    192 			case SOCK_DGRAM:
    193 				proto = "udp";
    194 				break;
    195 			case SOCK_RAW:
    196 				break;
    197 			default:
    198 				return (EAI_SOCKTYPE);
    199 			}
    200 			break;
    201 #ifdef	AF_LOCAL
    202 		case AF_LOCAL:
    203 			switch (hints->ai_socktype) {
    204 			case 0:
    205 				break;
    206 			case SOCK_STREAM:
    207 				break;
    208 			case SOCK_DGRAM:
    209 				break;
    210 			default:
    211 				return (EAI_SOCKTYPE);
    212 			}
    213 			break;
    214 #endif
    215 		default:
    216 			return (EAI_FAMILY);
    217 		}
    218 	} else {
    219 		protocol = 0;
    220 		family = 0;
    221 		socktype = 0;
    222 		flags = 0;
    223 	}
    224 
    225 	rval = do_nodename(nodename, ai, hints);
    226 	if (rval != 0) {
    227 		freeaddrinfo(ai);
    228 		return (rval);
    229 	}
    230 
    231 	/*
    232 	 * First, look up the service name (port) if it was
    233 	 * requested.  If the socket type wasn't specified, then
    234 	 * try and figure it out.
    235 	 */
    236 	if (servname != NULL) {
    237 		char *e;
    238 
    239 		port = strtol(servname, &e, 10);
    240 		if (*e == '\0') {
    241 			if (socktype == 0)
    242 				return (EAI_SOCKTYPE);
    243 			if (port < 0 || port > 65535)
    244 				return (EAI_SERVICE);
    245 			port = htons((unsigned short) port);
    246 		} else {
    247 			sp = getservbyname(servname, proto);
    248 			if (sp == NULL)
    249 				return (EAI_SERVICE);
    250 			port = sp->s_port;
    251 			if (socktype == 0) {
    252 				if (strcmp(sp->s_proto, "tcp") == 0)
    253 					socktype = SOCK_STREAM;
    254 				else if (strcmp(sp->s_proto, "udp") == 0)
    255 					socktype = SOCK_DGRAM;
    256 			}
    257 		}
    258 	} else
    259 		port = 0;
    260 
    261 	/*
    262 	 *
    263 	 * Set up the port number
    264 	 */
    265 	if (ai->ai_family == AF_INET)
    266 		((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
    267 	else if (ai->ai_family == AF_INET6)
    268 		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
    269 	*res = ai;
    270 	return (0);
    271 }
    272 
    273 void
    274 freeaddrinfo(struct addrinfo *ai)
    275 {
    276 	if (ai->ai_canonname != NULL)
    277 	{
    278 		free(ai->ai_canonname);
    279 		ai->ai_canonname = NULL;
    280 	}
    281 	if (ai->ai_addr != NULL)
    282 	{
    283 		free(ai->ai_addr);
    284 		ai->ai_addr = NULL;
    285 	}
    286 	free(ai);
    287 	ai = NULL;
    288 }
    289 
    290 int
    291 getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
    292 	size_t hostlen, char *serv, size_t servlen, int flags)
    293 {
    294 	struct hostent *hp;
    295 	int namelen;
    296 
    297 	if (sa->sa_family != AF_INET)
    298 		return (EAI_FAMILY);
    299 	hp = gethostbyaddr(
    300 	    (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
    301 	    4, AF_INET);
    302 	if (hp == NULL) {
    303 		if (h_errno == TRY_AGAIN)
    304 			return (EAI_AGAIN);
    305 		else
    306 			return (EAI_FAIL);
    307 	}
    308 	if (host != NULL && hostlen > 0) {
    309 		/*
    310 		 * Don't exceed buffer
    311 		 */
    312 		namelen = min(strlen(hp->h_name), hostlen - 1);
    313 		if (namelen > 0) {
    314 			strncpy(host, hp->h_name, namelen);
    315 			host[namelen] = '\0';
    316 		}
    317 	}
    318 	return (0);
    319 }
    320 
    321 char *
    322 gai_strerror(int ecode)
    323 {
    324 	if (ecode < 0 || ecode > EAI_MAX)
    325 		ecode = EAI_MAX;
    326 	return ai_errlist[ecode];
    327 }
    328 
    329 static int
    330 do_nodename(
    331 	const char *nodename,
    332 	struct addrinfo *ai,
    333 	const struct addrinfo *hints)
    334 {
    335 	struct hostent *hp = NULL;
    336 	struct sockaddr_in *sockin;
    337 	struct sockaddr_in6 *sockin6;
    338 	int errval;
    339 
    340 	ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
    341 	if (ai->ai_addr == NULL)
    342 		return (EAI_MEMORY);
    343 
    344 	/*
    345 	 * For an empty node name just use the wildcard.
    346 	 * NOTE: We need to assume that the address family is
    347 	 * set elsewhere so that we can set the appropriate wildcard
    348 	 */
    349 	if (nodename == NULL) {
    350 		ai->ai_addrlen = sizeof(struct sockaddr_storage);
    351 		if (ai->ai_family == AF_INET)
    352 		{
    353 			sockin = (struct sockaddr_in *)ai->ai_addr;
    354 			sockin->sin_family = (short) ai->ai_family;
    355 			sockin->sin_addr.s_addr = htonl(INADDR_ANY);
    356 		}
    357 		else
    358 		{
    359 			sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
    360 			sockin6->sin6_family = (short) ai->ai_family;
    361 			/*
    362 			 * we have already zeroed out the address
    363 			 * so we don't actually need to do this
    364 			 * This assignment is causing problems so
    365 			 * we don't do what this would do.
    366 			 sockin6->sin6_addr = in6addr_any;
    367 			 */
    368 		}
    369 #ifdef ISC_PLATFORM_HAVESALEN
    370 		ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
    371 #endif
    372 
    373 		return (0);
    374 	}
    375 
    376 	/*
    377 	 * See if we have an IPv6 address
    378 	 */
    379 	if(strchr(nodename, ':') != NULL) {
    380 		if (inet_pton(AF_INET6, nodename,
    381 		    &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
    382 			((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
    383 			ai->ai_family = AF_INET6;
    384 			ai->ai_addrlen = sizeof(struct sockaddr_in6);
    385 			return (0);
    386 		}
    387 	}
    388 
    389 	/*
    390 	 * See if we have an IPv4 address
    391 	 */
    392 	if (inet_pton(AF_INET, nodename,
    393 	    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
    394 		((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
    395 		ai->ai_family = AF_INET;
    396 		ai->ai_addrlen = sizeof(struct sockaddr_in);
    397 		return (0);
    398 	}
    399 
    400 	/*
    401 	 * If the numeric host flag is set, don't attempt resolution
    402 	 */
    403 	if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
    404 		return (EAI_NONAME);
    405 
    406 	/*
    407 	 * Look for a name
    408 	 */
    409 
    410 	errval = DNSlookup_name(nodename, AF_INET, &hp);
    411 
    412 	if (hp == NULL) {
    413 		if (errval == TRY_AGAIN || errval == EAI_AGAIN)
    414 			return (EAI_AGAIN);
    415 		else if (errval == EAI_NONAME) {
    416 			if (inet_pton(AF_INET, nodename,
    417 			    &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
    418 				((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
    419 				ai->ai_family = AF_INET;
    420 				ai->ai_addrlen = sizeof(struct sockaddr_in);
    421 				return (0);
    422 			}
    423 			return (errval);
    424 		}
    425 		else
    426 		{
    427 			return (errval);
    428 		}
    429 	}
    430 	ai->ai_family = hp->h_addrtype;
    431 	ai->ai_addrlen = sizeof(struct sockaddr);
    432 	sockin = (struct sockaddr_in *)ai->ai_addr;
    433 	memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
    434 	ai->ai_addr->sa_family = hp->h_addrtype;
    435 #ifdef ISC_PLATFORM_HAVESALEN
    436 	ai->ai_addr->sa_len = sizeof(struct sockaddr);
    437 #endif
    438 	if (hints != NULL && hints->ai_flags & AI_CANONNAME)
    439 		ai->ai_canonname = estrdup(hp->h_name);
    440 	return (0);
    441 }
    442 
    443 #endif /* !ISC_PLATFORM_HAVEIPV6 */
    444