aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-05-21 16:49:31 -0700
committerGarrett D'Amore <garrett@damore.org>2018-05-21 21:27:16 -0700
commita3cf238a431e6a454f43a66f3c02a2f17d6dfc61 (patch)
treee66560b9d5422420c4af86b8589324690160fb20
parentd0cf8ce6f43daf6882037dbdcdaa7f2169dd1e6a (diff)
downloadnng-a3cf238a431e6a454f43a66f3c02a2f17d6dfc61.tar.gz
nng-a3cf238a431e6a454f43a66f3c02a2f17d6dfc61.tar.bz2
nng-a3cf238a431e6a454f43a66f3c02a2f17d6dfc61.zip
fixes #471 Linux resolver truncates port number silently
-rw-r--r--src/platform/posix/posix_resolv_gai.c50
-rw-r--r--src/platform/windows/win_resolv.c44
-rw-r--r--tests/CMakeLists.txt2
3 files changed, 78 insertions, 18 deletions
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 <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -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 <ctype.h>
+#include <string.h>
+
#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) {
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a0f54b5d..6a8d5e86 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -196,7 +196,7 @@ add_nng_compat_test(compat_survey 5)
add_nng_compat_test(compat_reqttl 5)
add_nng_compat_test(compat_shutdown 5)
add_nng_compat_test(compat_surveyttl 5)
-add_nng_compat_test(compat_tcp 5)
+add_nng_compat_test(compat_tcp 60)
# These are special tests for compat mode, not inherited from the
# legacy libnanomsg suite.