summaryrefslogtreecommitdiff
path: root/libntp/ntp_rfc2553.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/ntp_rfc2553.c')
-rw-r--r--libntp/ntp_rfc2553.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/libntp/ntp_rfc2553.c b/libntp/ntp_rfc2553.c
new file mode 100644
index 0000000..f267999
--- /dev/null
+++ b/libntp/ntp_rfc2553.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * Compatability shims with the rfc2553 API to simplify ntp.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <isc/net.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include "ntp_rfc2553.h"
+
+#include "ntpd.h"
+#include "ntp_malloc.h"
+#include "ntp_string.h"
+#include "ntp_debug.h"
+
+
+/*
+ * copy_addrinfo() - copy a single addrinfo to malloc()'d block.
+ * copy_addrinfo_list() - copy an addrinfo list to malloc()'d block.
+ *
+ * Copies an addrinfo list and its associated data to a contiguous block
+ * of storage from emalloc(). Callback routines invoked via
+ * getaddrinfo_sometime() have access to the resulting addrinfo list
+ * only until they return. This routine provides an easy way to make a
+ * persistent copy. Although the list provided to gai_sometime_callback
+ * routines is similarly contiguous, to keep this code usable in any
+ * context where we might want to duplicate an addrinfo list, it does
+ * not require the input list be contiguous.
+ *
+ * The returned list head pointer is passed to free() to release the
+ * entire list.
+ *
+ * In keeping with the rest of the NTP distribution, sockaddr_u is used
+ * in preference to struct sockaddr_storage, which is a member of the
+ * former union and so compatible.
+ *
+ * The rest of ntp_rfc2553.c is conditioned on ISC_PLATFORM_HAVEIPV6
+ * not being defined, copy_addrinfo_*() are exceptions.
+ */
+struct addrinfo * copy_addrinfo_common(const struct addrinfo *, int
+#ifdef EREALLOC_CALLSITE
+ ,
+ const char *, int
+#endif
+ );
+
+
+struct addrinfo *
+copy_addrinfo_impl(
+ const struct addrinfo * src
+#ifdef EREALLOC_CALLSITE
+ ,
+ const char * caller_file,
+ int caller_line
+#endif
+ )
+{
+ return copy_addrinfo_common(src, TRUE
+#ifdef EREALLOC_CALLSITE
+ ,
+ caller_file, caller_line
+#endif
+ );
+}
+
+
+struct addrinfo *
+copy_addrinfo_list_impl(
+ const struct addrinfo * src
+#ifdef EREALLOC_CALLSITE
+ ,
+ const char * caller_file,
+ int caller_line
+#endif
+ )
+{
+ return copy_addrinfo_common(src, FALSE
+#ifdef EREALLOC_CALLSITE
+ ,
+ caller_file, caller_line
+#endif
+ );
+}
+
+
+struct addrinfo *
+copy_addrinfo_common(
+ const struct addrinfo * src,
+ int just_one
+#ifdef EREALLOC_CALLSITE
+ ,
+ const char * caller_file,
+ int caller_line
+#endif
+ )
+{
+ const struct addrinfo * ai_src;
+ const struct addrinfo * ai_nxt;
+ struct addrinfo * ai_cpy;
+ struct addrinfo * dst;
+ sockaddr_u * psau;
+ char * pcanon;
+ u_int elements;
+ size_t octets;
+ size_t canons_octets;
+ size_t str_octets;
+
+ elements = 0;
+ canons_octets = 0;
+
+ for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
+ if (just_one)
+ ai_nxt = NULL;
+ else
+ ai_nxt = ai_src->ai_next;
+ ++elements;
+ if (NULL != ai_src->ai_canonname)
+ canons_octets += 1 + strlen(ai_src->ai_canonname);
+ }
+
+ octets = elements * (sizeof(*ai_cpy) + sizeof(*psau));
+ octets += canons_octets;
+
+ dst = erealloczsite(NULL, octets, 0, TRUE, caller_file,
+ caller_line);
+ ai_cpy = dst;
+ psau = (void *)(ai_cpy + elements);
+ pcanon = (void *)(psau + elements);
+
+ for (ai_src = src; NULL != ai_src; ai_src = ai_nxt) {
+ if (just_one)
+ ai_nxt = NULL;
+ else
+ ai_nxt = ai_src->ai_next;
+ *ai_cpy = *ai_src;
+ REQUIRE(ai_src->ai_addrlen <= sizeof(sockaddr_u));
+ memcpy(psau, ai_src->ai_addr, ai_src->ai_addrlen);
+ ai_cpy->ai_addr = &psau->sa;
+ ++psau;
+ if (NULL != ai_cpy->ai_canonname) {
+ ai_cpy->ai_canonname = pcanon;
+ str_octets = 1 + strlen(ai_src->ai_canonname);
+ memcpy(pcanon, ai_src->ai_canonname, str_octets);
+ pcanon += str_octets;
+ }
+ if (NULL != ai_cpy->ai_next) {
+ if (just_one)
+ ai_cpy->ai_next = NULL;
+ else
+ ai_cpy->ai_next = ai_cpy + 1;
+ }
+ ++ai_cpy;
+ }
+ NTP_ENSURE(pcanon == ((char *)dst + octets));
+
+ return dst;
+}
+
+
+#ifndef ISC_PLATFORM_HAVEIPV6
+
+static char *ai_errlist[] = {
+ "Success",
+ "Address family for hostname not supported", /* EAI_ADDRFAMILY */
+ "Temporary failure in name resolution", /* EAI_AGAIN */
+ "Invalid value for ai_flags", /* EAI_BADFLAGS */
+ "Non-recoverable failure in name resolution", /* EAI_FAIL */
+ "ai_family not supported", /* EAI_FAMILY */
+ "Memory allocation failure", /* EAI_MEMORY */
+ "No address associated with hostname", /* EAI_NODATA */
+ "hostname nor servname provided, or not known", /* EAI_NONAME */
+ "servname not supported for ai_socktype", /* EAI_SERVICE */
+ "ai_socktype not supported", /* EAI_SOCKTYPE */
+ "System error returned in errno", /* EAI_SYSTEM */
+ "Invalid value for hints", /* EAI_BADHINTS */
+ "Resolved protocol is unknown", /* EAI_PROTOCOL */
+ "Unknown error", /* EAI_MAX */
+};
+
+/*
+ * Local declaration
+ */
+int
+DNSlookup_name(
+ const char *name,
+ int ai_family,
+ struct hostent **Addresses
+);
+
+#ifndef SYS_WINNT
+/*
+ * Encapsulate gethostbyname to control the error code
+ */
+int
+DNSlookup_name(
+ const char *name,
+ int ai_family,
+ struct hostent **Addresses
+)
+{
+ *Addresses = gethostbyname(name);
+ return (h_errno);
+}
+#endif
+
+static int do_nodename (const char *nodename, struct addrinfo *ai,
+ const struct addrinfo *hints);
+
+int
+getaddrinfo (const char *nodename, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ int rval;
+ struct servent *sp;
+ struct addrinfo *ai = NULL;
+ int port;
+ const char *proto = NULL;
+ int family, socktype, flags, protocol;
+
+
+ /*
+ * If no name is provide just return an error
+ */
+ if (nodename == NULL && servname == NULL)
+ return (EAI_NONAME);
+
+ ai = calloc(sizeof(struct addrinfo), 1);
+ if (ai == NULL)
+ return (EAI_MEMORY);
+
+ /*
+ * Copy default values from hints, if available
+ */
+ if (hints != NULL) {
+ ai->ai_flags = hints->ai_flags;
+ ai->ai_family = hints->ai_family;
+ ai->ai_socktype = hints->ai_socktype;
+ ai->ai_protocol = hints->ai_protocol;
+
+ family = hints->ai_family;
+ socktype = hints->ai_socktype;
+ protocol = hints->ai_protocol;
+ flags = hints->ai_flags;
+
+ switch (family) {
+ case AF_UNSPEC:
+ switch (hints->ai_socktype) {
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ }
+ break;
+ case AF_INET:
+ case AF_INET6:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_RAW:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#ifdef AF_LOCAL
+ case AF_LOCAL:
+ switch (hints->ai_socktype) {
+ case 0:
+ break;
+ case SOCK_STREAM:
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ return (EAI_SOCKTYPE);
+ }
+ break;
+#endif
+ default:
+ return (EAI_FAMILY);
+ }
+ } else {
+ protocol = 0;
+ family = 0;
+ socktype = 0;
+ flags = 0;
+ }
+
+ rval = do_nodename(nodename, ai, hints);
+ if (rval != 0) {
+ freeaddrinfo(ai);
+ return (rval);
+ }
+
+ /*
+ * First, look up the service name (port) if it was
+ * requested. If the socket type wasn't specified, then
+ * try and figure it out.
+ */
+ if (servname != NULL) {
+ char *e;
+
+ port = strtol(servname, &e, 10);
+ if (*e == '\0') {
+ if (socktype == 0)
+ return (EAI_SOCKTYPE);
+ if (port < 0 || port > 65535)
+ return (EAI_SERVICE);
+ port = htons((unsigned short) port);
+ } else {
+ sp = getservbyname(servname, proto);
+ if (sp == NULL)
+ return (EAI_SERVICE);
+ port = sp->s_port;
+ if (socktype == 0) {
+ if (strcmp(sp->s_proto, "tcp") == 0)
+ socktype = SOCK_STREAM;
+ else if (strcmp(sp->s_proto, "udp") == 0)
+ socktype = SOCK_DGRAM;
+ }
+ }
+ } else
+ port = 0;
+
+ /*
+ *
+ * Set up the port number
+ */
+ if (ai->ai_family == AF_INET)
+ ((struct sockaddr_in *)ai->ai_addr)->sin_port = (unsigned short) port;
+ else if (ai->ai_family == AF_INET6)
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = (unsigned short) port;
+ *res = ai;
+ return (0);
+}
+
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+ if (ai->ai_canonname != NULL)
+ {
+ free(ai->ai_canonname);
+ ai->ai_canonname = NULL;
+ }
+ if (ai->ai_addr != NULL)
+ {
+ free(ai->ai_addr);
+ ai->ai_addr = NULL;
+ }
+ free(ai);
+ ai = NULL;
+}
+
+int
+getnameinfo (const struct sockaddr *sa, u_int salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ struct hostent *hp;
+
+ if (sa->sa_family != AF_INET)
+ return (EAI_FAMILY);
+ hp = gethostbyaddr(
+ (const char *)&((const struct sockaddr_in *)sa)->sin_addr,
+ 4, AF_INET);
+ if (hp == NULL) {
+ if (h_errno == TRY_AGAIN)
+ return (EAI_AGAIN);
+ else
+ return (EAI_FAIL);
+ }
+ if (host != NULL && hostlen > 0)
+ strlcpy(host, hp->h_name, hostlen);
+ return (0);
+}
+
+char *
+gai_strerror(int ecode)
+{
+ if (ecode < 0 || ecode > EAI_MAX)
+ ecode = EAI_MAX;
+ return ai_errlist[ecode];
+}
+
+static int
+do_nodename(
+ const char *nodename,
+ struct addrinfo *ai,
+ const struct addrinfo *hints)
+{
+ struct hostent *hp = NULL;
+ struct sockaddr_in *sockin;
+ struct sockaddr_in6 *sockin6;
+ int errval;
+
+ ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1);
+ if (ai->ai_addr == NULL)
+ return (EAI_MEMORY);
+
+ /*
+ * For an empty node name just use the wildcard.
+ * NOTE: We need to assume that the address family is
+ * set elsewhere so that we can set the appropriate wildcard
+ */
+ if (nodename == NULL) {
+ ai->ai_addrlen = sizeof(struct sockaddr_storage);
+ if (ai->ai_family == AF_INET)
+ {
+ sockin = (struct sockaddr_in *)ai->ai_addr;
+ sockin->sin_family = (short) ai->ai_family;
+ sockin->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else
+ {
+ sockin6 = (struct sockaddr_in6 *)ai->ai_addr;
+ sockin6->sin6_family = (short) ai->ai_family;
+ /*
+ * we have already zeroed out the address
+ * so we don't actually need to do this
+ * This assignment is causing problems so
+ * we don't do what this would do.
+ sockin6->sin6_addr = in6addr_any;
+ */
+ }
+#ifdef ISC_PLATFORM_HAVESALEN
+ ai->ai_addr->sa_len = SOCKLEN(ai->ai_addr);
+#endif
+
+ return (0);
+ }
+
+ /*
+ * See if we have an IPv6 address
+ */
+ if(strchr(nodename, ':') != NULL) {
+ if (inet_pton(AF_INET6, nodename,
+ &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr) == 1) {
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_family = AF_INET6;
+ ai->ai_family = AF_INET6;
+ ai->ai_addrlen = sizeof(struct sockaddr_in6);
+ return (0);
+ }
+ }
+
+ /*
+ * See if we have an IPv4 address
+ */
+ if (inet_pton(AF_INET, nodename,
+ &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
+ ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
+ ai->ai_family = AF_INET;
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ return (0);
+ }
+
+ /*
+ * If the numeric host flag is set, don't attempt resolution
+ */
+ if (hints != NULL && (hints->ai_flags & AI_NUMERICHOST))
+ return (EAI_NONAME);
+
+ /*
+ * Look for a name
+ */
+
+ errval = DNSlookup_name(nodename, AF_INET, &hp);
+
+ if (hp == NULL) {
+ if (errval == TRY_AGAIN || errval == EAI_AGAIN)
+ return (EAI_AGAIN);
+ else if (errval == EAI_NONAME) {
+ if (inet_pton(AF_INET, nodename,
+ &((struct sockaddr_in *)ai->ai_addr)->sin_addr) == 1) {
+ ((struct sockaddr *)ai->ai_addr)->sa_family = AF_INET;
+ ai->ai_family = AF_INET;
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ return (0);
+ }
+ return (errval);
+ }
+ else
+ {
+ return (errval);
+ }
+ }
+ ai->ai_family = hp->h_addrtype;
+ ai->ai_addrlen = sizeof(struct sockaddr);
+ sockin = (struct sockaddr_in *)ai->ai_addr;
+ memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length);
+ ai->ai_addr->sa_family = hp->h_addrtype;
+#ifdef ISC_PLATFORM_HAVESALEN
+ ai->ai_addr->sa_len = sizeof(struct sockaddr);
+#endif
+ if (hints != NULL && (hints->ai_flags & AI_CANONNAME))
+ ai->ai_canonname = estrdup(hp->h_name);
+ return (0);
+}
+
+#endif /* !ISC_PLATFORM_HAVEIPV6 */