From fbb69fc3192f250cdee5a5f3bf65d1fec03ff944 Mon Sep 17 00:00:00 2001 From: Dave Hart Date: Sat, 6 Feb 2010 05:22:44 +0000 Subject: [PATCH] Stop using getaddrinfo() to convert numeric address strings to on-wire addresses in favor of is_ip_address() alone. bk: 4b6cfca4XtXrE9lm5sZ9fEvnMGAUeg --- ChangeLog | 2 + include/ntp_rfc2553.h | 11 +++- include/ntpd.h | 21 +++++-- libntp/ntp_rfc2553.c | 92 +++++++++++++++++++++++++++++ ntpd/ntp_config.c | 134 ++++++------------------------------------ ntpd/ntp_intres.c | 11 +++- 6 files changed, 147 insertions(+), 124 deletions(-) diff --git a/ChangeLog b/ChangeLog index 350dfe39a..2beeb49bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ * Include (4.2.6p1-RC5) - [Bug 1480] snprintf() cleanup caused unterminated refclock IDs. +* Stop using getaddrinfo() to convert numeric address strings to on-wire + addresses in favor of is_ip_address() alone. (4.2.7p17) 2010/02/05 Released by Harlan Stenn * Include (4.2.6p1-RC5) - [Bug 1477] First non-gmake make in clone w/VPATH can't make COPYRIGHT. diff --git a/include/ntp_rfc2553.h b/include/ntp_rfc2553.h index 703e972a9..b064658a8 100644 --- a/include/ntp_rfc2553.h +++ b/include/ntp_rfc2553.h @@ -74,7 +74,16 @@ #include "ntp_types.h" - /* +#if !defined(_MSC_VER) || !defined(_DEBUG) +struct addrinfo *copy_addrinfo_list(const struct addrinfo *); +#else +#define copy_addrinfo_list(ai) \ + debug_copy_addrinfo_list((ai), __FILE__, __LINE__) +struct addrinfo *debug_copy_addrinfo_list(const struct addrinfo *, + const char *, int); +#endif + +/* * If various macros are not defined we need to define them */ diff --git a/include/ntpd.h b/include/ntpd.h index 3c5e4a617..a83d8e76b 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -62,23 +62,32 @@ extern void set_sys_var (const char *, u_long, u_short); /* ntp_intres.c */ #ifdef WORKER -typedef void (*gai_sometime_callback) - (int, int, void *, const char *, const char *, - const struct addrinfo *, const struct addrinfo *); /* * you call getaddrinfo_sometime(name, service, &hints, callback_func, context); * later (*callback_func)(rescode, gai_errno, context, name, service, hints, ai_result) is called. */ +typedef void (*gai_sometime_callback) + (int, int, void *, const char *, const char *, + const struct addrinfo *, const struct addrinfo *); extern int getaddrinfo_sometime(const char *, const char *, const struct addrinfo *, gai_sometime_callback, void *); -typedef void (*gni_sometime_callback) - (int, int, sockaddr_u *, int, const char *, - const char *, void *); +/* + * In gai_sometime_callback routines, the resulting addrinfo list is + * only available until the callback returns. To hold on to the list + * of addresses after the callback returns, use copy_addrinfo_list(): + * + * struct addrinfo *copy_addrinfo_list(const struct addrinfo *); + */ + + /* * you call getnameinfo_sometime(sockaddr, namelen, servlen, flags, callback_func, context); * later (*callback_func)(rescode, gni_errno, sockaddr, flags, name, service, context) is called. */ +typedef void (*gni_sometime_callback) + (int, int, sockaddr_u *, int, const char *, + const char *, void *); extern int getnameinfo_sometime(sockaddr_u *, size_t, size_t, int, gni_sometime_callback, void *); #endif /* WORKER */ diff --git a/libntp/ntp_rfc2553.c b/libntp/ntp_rfc2553.c index 03af593cf..95269502b 100644 --- a/libntp/ntp_rfc2553.c +++ b/libntp/ntp_rfc2553.c @@ -82,6 +82,98 @@ #include "ntp_malloc.h" #include "ntp_stdlib.h" #include "ntp_string.h" +#include "ntp_debug.h" + + +/* + * copy_addrinfo_list - copy an addrinfo list + * + * 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_list() is an exception. + */ +#if !defined(_MSC_VER) || !defined(_DEBUG) +struct addrinfo * +copy_addrinfo_list( + const struct addrinfo *src + ) +#else +struct addrinfo * +debug_copy_addrinfo_list( + const struct addrinfo * src, + const char * caller_file, + int caller_line + ) +#endif +{ + const struct addrinfo * ai_src; + 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_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; + +#if !defined(_MSC_VER) || !defined(_DEBUG) + dst = emalloc(octets); +#else + dst = debug_erealloc(NULL, octets, caller_file, caller_line); +#endif + memset(dst, 0, octets); + ai_cpy = dst; + psau = (void *)(ai_cpy + elements); + pcanon = (void *)(psau + elements); + + for (ai_src = src; NULL != ai_src; ai_src = ai_src->ai_next) { + *ai_cpy = *ai_src; + NTP_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) + ai_cpy->ai_next = ai_cpy + 1; + ++ai_cpy; + } + NTP_ENSURE(pcanon == ((char *)dst + octets)); + + return dst; +} + #ifndef ISC_PLATFORM_HAVEIPV6 diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index ef9dbf741..45ae1b6d5 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -286,14 +286,11 @@ do { \ } while (0) void ntpd_set_tod_using(const char *); -static unsigned long get_pfxmatch(char **s,struct masks *m); -static unsigned long get_match(char *s,struct masks *m); +static unsigned long get_pfxmatch(char **s, struct masks *m); +static unsigned long get_match(char *s, struct masks *m); static unsigned long get_logmask(char *s); -static int getnetnum(const char *num,sockaddr_u *addr, int complain, +static int getnetnum(const char *num, sockaddr_u *addr, int complain, enum gnn_type a_type); -static int get_multiple_netnums(const char *num, sockaddr_u *addr, - struct addrinfo **res, int complain, - enum gnn_type a_type); @@ -4294,122 +4291,27 @@ getnetnum( enum gnn_type a_type ) { - int retval; - struct addrinfo *res; - - /* Get all the addresses that resolve to this name */ - retval = get_multiple_netnums(num, addr, &res, complain, a_type); - - if (retval != 1) { - /* Name resolution failed */ - return retval; - } - - memcpy(addr, res->ai_addr, res->ai_addrlen); - - DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr))); - - freeaddrinfo(res); - return 1; -} - - -/* - * get_multiple_netnums - * - * returns 1 for success, and mysteriously, 0 or -1 for failure - */ -static int -get_multiple_netnums( - const char *nameornum, - sockaddr_u *addr, - struct addrinfo **res, - int complain, - enum gnn_type a_type - ) -{ - char lookbuf[1024]; - const char *lookup; - char *pch; - struct addrinfo hints; - struct addrinfo *ptr; - int retval; isc_netaddr_t ipaddr; - memset(&hints, 0, sizeof(hints)); - - if (strlen(nameornum) >= sizeof(lookbuf)) { - NTP_INSIST(strlen(nameornum) < sizeof(lookbuf)); + if (!is_ip_address(num, AF_UNSPEC, &ipaddr)) return 0; - } - - lookup = nameornum; - if (is_ip_address(nameornum, AF_UNSPEC, &ipaddr)) { - hints.ai_flags = AI_NUMERICHOST; - hints.ai_family = ipaddr.family; - if ('[' == nameornum[0]) { - lookup = lookbuf; - strncpy(lookbuf, &nameornum[1], - sizeof(lookbuf)); - pch = strchr(lookbuf, ']'); - if (pch != NULL) - *pch = '\0'; - } - pch = strchr(lookup, '%'); - if (pch != NULL) { - if (lookup != lookbuf) { - lookup = lookbuf; - strncpy(lookbuf, nameornum, - sizeof(lookbuf)); - pch = strchr(lookup, '%'); - } - *pch = '\0'; - } - } - - if (AF_INET6 == hints.ai_family && !ipv6_works) - return 0; - - if (AF_UNSPEC == hints.ai_family) { - if (!ipv6_works) - hints.ai_family = AF_INET; - else if (!ipv4_works) - hints.ai_family = AF_INET6; - else if (IS_IPV4(addr) || IS_IPV6(addr)) - hints.ai_family = AF(addr); - } - - /* Get host address. Looking for UDP datagram connection */ - hints.ai_socktype = SOCK_DGRAM; - DPRINTF(4, ("getaddrinfo %s%s\n", - (AF_UNSPEC == hints.ai_family) - ? "" - : (AF_INET == hints.ai_family) - ? "v4 " - : "v6 ", - lookup)); + if (AF_INET6 == ipaddr.family && !ipv6_works) + return -1; - retval = getaddrinfo(lookup, "ntp", &hints, &ptr); + memset(addr, 0, sizeof(*addr)); + AF(addr) = (u_short)ipaddr.family; +#ifdef ISC_PLATFORM_HAVESALEN + addr->sas.ss_len = SIZEOF_SOCKADDR(AF(addr)); +#endif + if (IS_IPV4(addr)) + memcpy(&addr->sa4.sin_addr, &ipaddr.type.in, + sizeof(addr->sa4.sin_addr)); + else + memcpy(&addr->sa6.sin6_addr, &ipaddr.type.in6, + sizeof(addr->sa6.sin6_addr)); - if (retval || (AF_INET6 == ptr->ai_family && !ipv6_works)) { - if (complain) - msyslog(LOG_ERR, - "getaddrinfo: \"%s\" invalid host address, ignored", - lookup); - else - DPRINTF(1, ("getaddrinfo: \"%s\" invalid host address.\n", - lookup)); - - if (!retval) { - freeaddrinfo(ptr); - return -1; - } else - return 0; - } - *res = ptr; + DPRINTF(2, ("getnetnum given %s, got %s\n", num, stoa(addr))); return 1; } - - diff --git a/ntpd/ntp_intres.c b/ntpd/ntp_intres.c index 5a52bd1b4..5353c27f5 100644 --- a/ntpd/ntp_intres.c +++ b/ntpd/ntp_intres.c @@ -356,7 +356,7 @@ blocking_getaddrinfo( + canons_octets; resp_octets = sizeof(*resp) + gai_resp->octets; - resp = erealloc(resp, resp_octets); + resp = erealloc(resp, resp_octets); gai_resp = (void *)(resp + 1); /* cp serves as our current pointer while serializing */ @@ -516,11 +516,20 @@ getaddrinfo_sometime_complete( if (!gai_resp->ai_count) ai = NULL; +#ifdef DEBUG + else /* exercise copy_addrinfo_list() */ + ai = copy_addrinfo_list(ai); +#endif (*gai_req->callback)(gai_resp->retcode, gai_resp->gai_errno, gai_req->context, node, service, &gai_req->hints, ai); +#ifdef DEBUG + /* exercise copy_addrinfo_list() */ + if (NULL != ai) + free(ai); +#endif free(gai_req); /* gai_resp is part of block freed by process_blocking_response() */ } -- 2.47.3