From a3cf238a431e6a454f43a66f3c02a2f17d6dfc61 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 21 May 2018 16:49:31 -0700 Subject: fixes #471 Linux resolver truncates port number silently --- src/platform/posix/posix_resolv_gai.c | 50 ++++++++++++++++++++++++++++------- src/platform/windows/win_resolv.c | 44 +++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 17 deletions(-) (limited to 'src/platform') diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c index dcaef409..8c003362 100644 --- a/src/platform/posix/posix_resolv_gai.c +++ b/src/platform/posix/posix_resolv_gai.c @@ -13,6 +13,7 @@ #ifdef NNG_USE_POSIX_RESOLV_GAI #include "platform/posix/posix_aio.h" +#include #include #include #include @@ -48,8 +49,8 @@ struct resolv_item { int family; int passive; const char * name; - const char * serv; int proto; + uint16_t port; nni_aio * aio; nng_sockaddr sa; }; @@ -110,7 +111,7 @@ posix_gai_errno(int rv) return (NNG_ENOTSUP); default: - return (NNG_ESYSERR); + return (NNG_ESYSERR + rv); } } @@ -127,9 +128,10 @@ resolv_task(resolv_item *item) // We treat these all as IP addresses. The service and the // host part are split. memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_NUMERICSERV; #ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; +#else + hints.ai_flags = AI_NUMERICSERV; #endif if (item->passive) { hints.ai_flags |= AI_PASSIVE; @@ -137,8 +139,9 @@ resolv_task(resolv_item *item) hints.ai_protocol = item->proto; hints.ai_family = item->family; - rv = getaddrinfo(item->name, item->serv, &hints, &results); - if (rv != 0) { + // We can pass any non-zero service number, but we have to pass + // *something*, in case we are using a NULL hostname. + if ((rv = getaddrinfo(item->name, "80", &hints, &results)) != 0) { rv = posix_gai_errno(rv); goto done; } @@ -164,14 +167,14 @@ resolv_task(resolv_item *item) rv = 0; sin = (void *) probe->ai_addr; sa->s_in.sa_family = NNG_AF_INET; - sa->s_in.sa_port = sin->sin_port; + sa->s_in.sa_port = item->port; sa->s_in.sa_addr = sin->sin_addr.s_addr; break; case AF_INET6: rv = 0; sin6 = (void *) probe->ai_addr; sa->s_in6.sa_family = NNG_AF_INET6; - sa->s_in6.sa_port = sin6->sin6_port; + sa->s_in6.sa_port = item->port; memcpy(sa->s_in6.sa_addr, sin6->sin6_addr.s6_addr, 16); break; } @@ -193,6 +196,7 @@ resolv_ip(const char *host, const char *serv, int passive, int family, resolv_item *item; sa_family_t fam; int rv; + int port; if (nni_aio_begin(aio) != 0) { return; @@ -212,6 +216,32 @@ resolv_ip(const char *host, const char *serv, int passive, int family, return; } + // We can't use the resolver to look up up ports with AI_NUMERICSERV, + // because some resolver(s) is(are?) broken. For example, the + // systemd resolver takes a port number of 1000000 and just rips off + // the high order bits and lets it through! + port = 0; + if (serv != NULL) { + while (isdigit(*serv)) { + port *= 10; + port += (*serv - '0'); + if (port > 0xffff) { + // Port number out of range. + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + serv++; + } + if (*serv != '\0') { + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + } + if ((port == 0) && (!passive)) { + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { nni_aio_finish_error(aio, NNG_ENOMEM); return; @@ -219,12 +249,12 @@ resolv_ip(const char *host, const char *serv, int passive, int family, // NB: host and serv must remain valid until this is completed. memset(&item->sa, 0, sizeof(item->sa)); - item->passive = passive; item->name = host; - item->serv = serv; item->proto = proto; item->aio = aio; item->family = fam; + item->passive = passive; + item->port = htons((uint16_t) port); nni_mtx_lock(&resolv_mtx); if (resolv_fini) { diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c index c0fa1e0a..fb9d6751 100644 --- a/src/platform/windows/win_resolv.c +++ b/src/platform/windows/win_resolv.c @@ -10,6 +10,9 @@ #include "core/nng_impl.h" +#include +#include + #ifdef NNG_PLATFORM_WINDOWS // Modern Windows has an asynchronous resolver, but there are problems @@ -33,8 +36,8 @@ struct resolv_item { int family; int passive; const char * name; - const char * serv; int proto; + uint16_t port; nni_aio * aio; nng_sockaddr sa; }; @@ -112,8 +115,7 @@ resolv_task(resolv_item *item) hints.ai_protocol = item->proto; hints.ai_family = item->family; - rv = getaddrinfo(item->name, item->serv, &hints, &results); - if (rv != 0) { + if ((rv = getaddrinfo(item->name, "80", &hints, &results)) != 0) { rv = resolv_gai_errno(rv); goto done; } @@ -139,14 +141,14 @@ resolv_task(resolv_item *item) rv = 0; sin = (void *) probe->ai_addr; sa->s_in.sa_family = NNG_AF_INET; - sa->s_in.sa_port = sin->sin_port; + sa->s_in.sa_port = item->port; sa->s_in.sa_addr = sin->sin_addr.s_addr; break; case AF_INET6: rv = 0; sin6 = (void *) probe->ai_addr; sa->s_in6.sa_family = NNG_AF_INET6; - sa->s_in6.sa_port = sin6->sin6_port; + sa->s_in6.sa_port = item->port; memcpy(sa->s_in6.sa_addr, sin6->sin6_addr.s6_addr, 16); break; } @@ -167,6 +169,7 @@ resolv_ip(const char *host, const char *serv, int passive, int family, resolv_item *item; int fam; int rv; + int port; if (nni_aio_begin(aio) != 0) { return; @@ -186,17 +189,44 @@ resolv_ip(const char *host, const char *serv, int passive, int family, return; } + // We can't use the resolver to look up up ports with AI_NUMERICSERV, + // because Windows' resolver is broken. For example, the resolver + // takes a port number of 1000000 and just rips off the high order + // bits and lets it through! (It seems to time out though, so + // maybe it is ignoring AI_NUMERICSERV.) + port = 0; + if (serv != NULL) { + while (isdigit(*serv)) { + port *= 10; + port += (*serv - '0'); + if (port > 0xffff) { + // Port number out of range. + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + serv++; + } + if (*serv != '\0') { + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + } + if ((port == 0) && (!passive)) { + nni_aio_finish_error(aio, NNG_EADDRINVAL); + return; + } + if ((item = NNI_ALLOC_STRUCT(item)) == NULL) { nni_aio_finish_error(aio, NNG_ENOMEM); return; } - + memset(&item->sa, 0, sizeof(item->sa)); item->passive = passive; item->name = host; - item->serv = serv; item->proto = proto; item->aio = aio; item->family = fam; + item->port = htons((uint16_t) port); nni_mtx_lock(&resolv_mtx); if (resolv_fini) { -- cgit v1.2.3-70-g09d2