From 23a38d766780f4749945d84316b4e0a71e707b15 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 4 Mar 2018 17:04:11 -0800 Subject: fixes #262 NNG_OPT_URL should be resolved This causes TCP, TLS, and ZT endpoints to resolve any wildcards, and even IP addresses, when reporting the listen URL. The dialer URL is reported unresolved. Test cases for this are added as well, and nngcat actually reports this if --verbose is supplied. --- src/core/defs.h | 4 +-- src/core/endpt.c | 11 ++++--- src/core/platform.h | 8 ++++- src/platform/posix/posix_aio.h | 1 + src/platform/posix/posix_epdesc.c | 12 ++++++++ src/platform/posix/posix_tcp.c | 51 ++++++++++++++++++++++++++++++-- src/platform/windows/win_tcp.c | 58 +++++++++++++++++++++++++++++++++++-- src/supplemental/http/http_server.c | 2 +- src/transport/tcp/tcp.c | 26 ++++++++++++++++- src/transport/tls/tls.c | 28 ++++++++++++++++-- src/transport/zerotier/zerotier.c | 21 +++++++++++++- 11 files changed, 205 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core/defs.h b/src/core/defs.h index b08ce838..c449aa32 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -111,8 +111,8 @@ typedef struct { } while (0) #define NNI_GET16(ptr, v) \ - v = (((uint32_t)((uint8_t)(ptr)[0])) << 8) + \ - (((uint32_t)(uint8_t)(ptr)[1])) + v = (((uint16_t)((uint8_t)(ptr)[0])) << 8) + \ + (((uint16_t)(uint8_t)(ptr)[1])) #define NNI_GET32(ptr, v) \ v = (((uint32_t)((uint8_t)(ptr)[0])) << 24) + \ diff --git a/src/core/endpt.c b/src/core/endpt.c index 4d3727bc..4d3d9031 100644 --- a/src/core/endpt.c +++ b/src/core/endpt.c @@ -618,10 +618,6 @@ nni_ep_getopt(nni_ep *ep, const char *name, void *valp, size_t *szp) { nni_tran_ep_option *eo; - if (strcmp(name, NNG_OPT_URL) == 0) { - return (nni_getopt_str(ep->ep_url->u_rawurl, valp, szp)); - } - for (eo = ep->ep_ops.ep_options; eo && eo->eo_name; eo++) { int rv; if (strcmp(eo->eo_name, name) != 0) { @@ -636,6 +632,13 @@ nni_ep_getopt(nni_ep *ep, const char *name, void *valp, size_t *szp) return (rv); } + // We provide a fallback on the URL, but let the implementation + // override. This allows the URL to be created with wildcards, + // that are resolved later. + if (strcmp(name, NNG_OPT_URL) == 0) { + return (nni_getopt_str(ep->ep_url->u_rawurl, valp, szp)); + } + return (nni_sock_getopt(ep->ep_sock, name, valp, szp)); } diff --git a/src/core/platform.h b/src/core/platform.h index cf635f4a..3f336f11 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -207,7 +207,7 @@ extern void nni_plat_tcp_ep_close(nni_plat_tcp_ep *); // nni_plat_tcp_listen creates an TCP socket in listening mode, bound // to the specified path. -extern int nni_plat_tcp_ep_listen(nni_plat_tcp_ep *); +extern int nni_plat_tcp_ep_listen(nni_plat_tcp_ep *, nni_sockaddr *); // nni_plat_tcp_ep_accept starts an accept to receive an incoming connection. // An accepted connection will be passed back in the a_pipe member. @@ -248,6 +248,12 @@ extern int nni_plat_tcp_pipe_peername(nni_plat_tcp_pipe *, nni_sockaddr *); // nni_plat_tcp_pipe_sockname gets the local name. extern int nni_plat_tcp_pipe_sockname(nni_plat_tcp_pipe *, nni_sockaddr *); +// nni_plat_tcp_ntop obtains the IP address for the socket (enclosing it +// in brackets if it is IPv6) and port. Enough space for both must +// be present (48 bytes and 6 bytes each), although if either is NULL then +// those components are skipped. +extern int nni_plat_tcp_ntop(const nni_sockaddr *, char *, char *); + // nni_plat_tcp_resolv resolves a TCP name asynchronously. The family // should be one of NNG_AF_INET, NNG_AF_INET6, or NNG_AF_UNSPEC. The // first two constrain the name to those families, while the third will diff --git a/src/platform/posix/posix_aio.h b/src/platform/posix/posix_aio.h index 71656391..2073f6d6 100644 --- a/src/platform/posix/posix_aio.h +++ b/src/platform/posix/posix_aio.h @@ -40,5 +40,6 @@ extern void nni_posix_epdesc_close(nni_posix_epdesc *); extern void nni_posix_epdesc_connect(nni_posix_epdesc *, nni_aio *); extern int nni_posix_epdesc_listen(nni_posix_epdesc *); extern void nni_posix_epdesc_accept(nni_posix_epdesc *, nni_aio *); +extern int nni_posix_epdesc_sockname(nni_posix_epdesc *, nni_sockaddr *); #endif // PLATFORM_POSIX_AIO_H diff --git a/src/platform/posix/posix_epdesc.c b/src/platform/posix/posix_epdesc.c index 3da36fa2..16c0d09f 100644 --- a/src/platform/posix/posix_epdesc.c +++ b/src/platform/posix/posix_epdesc.c @@ -343,6 +343,18 @@ nni_posix_epdesc_accept(nni_posix_epdesc *ed, nni_aio *aio) nni_mtx_unlock(&ed->mtx); } +int +nni_posix_epdesc_sockname(nni_posix_epdesc *ed, nni_sockaddr *sa) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + + if (getsockname(ed->node.fd, (void *) &ss, &sslen) != 0) { + return (nni_plat_errno(errno)); + } + return (nni_posix_sockaddr2nn(sa, &ss)); +} + void nni_posix_epdesc_connect(nni_posix_epdesc *ed, nni_aio *aio) { diff --git a/src/platform/posix/posix_tcp.c b/src/platform/posix/posix_tcp.c index 79e241a3..8a6fe9d1 100644 --- a/src/platform/posix/posix_tcp.c +++ b/src/platform/posix/posix_tcp.c @@ -13,6 +13,7 @@ #ifdef NNG_PLATFORM_POSIX #include "platform/posix/posix_aio.h" +#include #include #include #include @@ -65,9 +66,14 @@ nni_plat_tcp_ep_close(nni_plat_tcp_ep *ep) } int -nni_plat_tcp_ep_listen(nni_plat_tcp_ep *ep) +nni_plat_tcp_ep_listen(nni_plat_tcp_ep *ep, nng_sockaddr *bsa) { - return (nni_posix_epdesc_listen((void *) ep)); + int rv; + rv = nni_posix_epdesc_listen((void *) ep); + if ((rv == 0) && (bsa != NULL)) { + rv = nni_posix_epdesc_sockname((void *) ep, bsa); + } + return (rv); } void @@ -118,4 +124,45 @@ nni_plat_tcp_pipe_sockname(nni_plat_tcp_pipe *p, nni_sockaddr *sa) return (nni_posix_pipedesc_sockname((void *) p, sa)); } +int +nni_plat_tcp_ntop(const nni_sockaddr *sa, char *ipstr, char *portstr) +{ + const void *ap; + uint16_t port; + int af; + switch (sa->s_un.s_family) { + case NNG_AF_INET: + ap = &sa->s_un.s_in.sa_addr; + port = sa->s_un.s_in.sa_port; + af = AF_INET; + break; + case NNG_AF_INET6: + ap = &sa->s_un.s_in6.sa_addr; + port = sa->s_un.s_in6.sa_port; + af = AF_INET6; + break; + default: + return (NNG_EINVAL); + } + if (ipstr != NULL) { + if (af == AF_INET6) { + size_t l; + ipstr[0] = '['; + inet_ntop(af, ap, ipstr + 1, INET6_ADDRSTRLEN); + l = strlen(ipstr); + ipstr[l++] = ']'; + ipstr[l++] = '\0'; + } else { + inet_ntop(af, ap, ipstr, INET6_ADDRSTRLEN); + } + } + if (portstr != NULL) { +#ifdef NNG_LITTLE_ENDIAN + port = ((port >> 8) & 0xff) | ((port & 0xff) << 8); +#endif + snprintf(portstr, 6, "%u", port); + } + return (0); +} + #endif // NNG_PLATFORM_POSIX diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c index 20f324b3..da661588 100644 --- a/src/platform/windows/win_tcp.c +++ b/src/platform/windows/win_tcp.c @@ -355,7 +355,7 @@ nni_plat_tcp_ep_fini(nni_plat_tcp_ep *ep) } static int -nni_win_tcp_listen(nni_plat_tcp_ep *ep) +nni_win_tcp_listen(nni_plat_tcp_ep *ep, nni_sockaddr *bsa) { int rv; BOOL yes; @@ -392,6 +392,17 @@ nni_win_tcp_listen(nni_plat_tcp_ep *ep) goto fail; } + if (bsa != NULL) { + SOCKADDR_STORAGE bound; + int len = sizeof(bound); + rv = getsockname(s, (SOCKADDR *) &bound, &len); + if (rv != 0) { + rv = nni_win_error(GetLastError()); + goto fail; + } + nni_win_sockaddr2nn(bsa, &bound); + } + if (listen(s, SOMAXCONN) != 0) { rv = nni_win_error(GetLastError()); goto fail; @@ -410,12 +421,12 @@ fail: } int -nni_plat_tcp_ep_listen(nni_plat_tcp_ep *ep) +nni_plat_tcp_ep_listen(nni_plat_tcp_ep *ep, nng_sockaddr *bsa) { int rv; nni_mtx_lock(&ep->acc_ev.mtx); - rv = nni_win_tcp_listen(ep); + rv = nni_win_tcp_listen(ep, bsa); nni_mtx_unlock(&ep->acc_ev.mtx); return (rv); } @@ -642,6 +653,47 @@ nni_plat_tcp_ep_connect(nni_plat_tcp_ep *ep, nni_aio *aio) nni_win_event_submit(&ep->con_ev, aio); } +int +nni_plat_tcp_ntop(const nni_sockaddr *sa, char *ipstr, char *portstr) +{ + const void *ap; + uint16_t port; + int af; + switch (sa->s_un.s_family) { + case NNG_AF_INET: + ap = &sa->s_un.s_in.sa_addr; + port = sa->s_un.s_in.sa_port; + af = AF_INET; + break; + case NNG_AF_INET6: + ap = &sa->s_un.s_in6.sa_addr; + port = sa->s_un.s_in6.sa_port; + af = AF_INET6; + break; + default: + return (NNG_EINVAL); + } + if (ipstr != NULL) { + if (af == AF_INET6) { + size_t l; + ipstr[0] = '['; + InetNtopA(af, ap, ipstr + 1, INET6_ADDRSTRLEN); + l = strlen(ipstr); + ipstr[l++] = ']'; + ipstr[l++] = '\0'; + } else { + InetNtopA(af, ap, ipstr, INET6_ADDRSTRLEN); + } + } + if (portstr != NULL) { +#ifdef NNG_LITTLE_ENDIAN + port = ((port >> 8) & 0xff) | ((port & 0xff) << 8); +#endif + snprintf(portstr, 6, "%u", port); + } + return (0); +} + int nni_win_tcp_sysinit(void) { diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 503ab1dd..7feadc96 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -895,7 +895,7 @@ http_server_start(nni_http_server *s) if (rv != 0) { return (rv); } - if ((rv = nni_plat_tcp_ep_listen(s->tep)) != 0) { + if ((rv = nni_plat_tcp_ep_listen(s->tep, NULL)) != 0) { nni_plat_tcp_ep_fini(s->tep); s->tep = NULL; return (rv); diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c index 475a77ff..2a23b88b 100644 --- a/src/transport/tcp/tcp.c +++ b/src/transport/tcp/tcp.c @@ -53,6 +53,8 @@ struct nni_tcp_ep { nni_aio * aio; nni_aio * user_aio; nni_url * url; + nng_sockaddr bsa; // bound addr + int mode; nni_mtx mtx; }; @@ -591,6 +593,7 @@ nni_tcp_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) return (rv); } ep->proto = nni_sock_proto(sock); + ep->mode = mode; *epp = ep; return (0); @@ -615,7 +618,7 @@ nni_tcp_ep_bind(void *arg) int rv; nni_mtx_lock(&ep->mtx); - rv = nni_plat_tcp_ep_listen(ep->tep); + rv = nni_plat_tcp_ep_listen(ep->tep, &ep->bsa); nni_mtx_unlock(&ep->mtx); return (rv); @@ -733,6 +736,22 @@ nni_tcp_ep_setopt_recvmaxsz(void *arg, const void *v, size_t sz) return (nni_setopt_size(&ep->rcvmax, v, sz, 0, NNI_MAXSZ)); } +static int +nni_tcp_ep_getopt_url(void *arg, void *v, size_t *szp) +{ + nni_tcp_ep *ep = arg; + char ustr[128]; + char ipstr[48]; // max for IPv6 addresses including [] + char portstr[6]; // max for 16-bit port + + if (ep->mode == NNI_EP_MODE_DIAL) { + return (nni_getopt_str(ep->url->u_rawurl, v, szp)); + } + nni_plat_tcp_ntop(&ep->bsa, ipstr, portstr); + snprintf(ustr, sizeof(ustr), "tcp://%s:%s", ipstr, portstr); + return (nni_getopt_str(ustr, v, szp)); +} + static int nni_tcp_ep_getopt_recvmaxsz(void *arg, void *v, size_t *szp) { @@ -780,6 +799,11 @@ static nni_tran_ep_option nni_tcp_ep_options[] = { .eo_getopt = nni_tcp_ep_getopt_recvmaxsz, .eo_setopt = nni_tcp_ep_setopt_recvmaxsz, }, + { + .eo_name = NNG_OPT_URL, + .eo_getopt = nni_tcp_ep_getopt_url, + .eo_setopt = NULL, + }, { .eo_name = NNG_OPT_LINGER, .eo_getopt = nni_tcp_ep_getopt_linger, diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c index f9de3367..cf849373 100644 --- a/src/transport/tls/tls.c +++ b/src/transport/tls/tls.c @@ -61,7 +61,9 @@ struct nni_tls_ep { nni_aio * user_aio; nni_mtx mtx; nng_tls_config * cfg; + nng_sockaddr bsa; nni_url * url; + int mode; }; static void nni_tls_pipe_send_cb(void *); @@ -597,7 +599,8 @@ nni_tls_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) return (NNG_ENOMEM); } nni_mtx_init(&ep->mtx); - ep->url = url; + ep->url = url; + ep->mode = mode; if (((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) || ((rv = nni_tls_config_init(&ep->cfg, tlsmode)) != 0) || @@ -638,7 +641,7 @@ nni_tls_ep_bind(void *arg) int rv; nni_mtx_lock(&ep->mtx); - rv = nni_plat_tcp_ep_listen(ep->tep); + rv = nni_plat_tcp_ep_listen(ep->tep, &ep->bsa); nni_mtx_unlock(&ep->mtx); return (rv); @@ -746,6 +749,22 @@ nni_tls_ep_connect(void *arg, nni_aio *aio) nni_mtx_unlock(&ep->mtx); } +static int +nni_tls_ep_getopt_url(void *arg, void *v, size_t *szp) +{ + nni_tls_ep *ep = arg; + char ustr[128]; + char ipstr[48]; // max for IPv6 addresses including [] + char portstr[6]; // max for 16-bit port + + if (ep->mode == NNI_EP_MODE_DIAL) { + return (nni_getopt_str(ep->url->u_rawurl, v, szp)); + } + nni_plat_tcp_ntop(&ep->bsa, ipstr, portstr); + snprintf(ustr, sizeof(ustr), "tls+tcp://%s:%s", ipstr, portstr); + return (nni_getopt_str(ustr, v, szp)); +} + static int nni_tls_ep_setopt_recvmaxsz(void *arg, const void *v, size_t sz) { @@ -906,6 +925,11 @@ static nni_tran_ep_option nni_tls_ep_options[] = { .eo_getopt = nni_tls_ep_getopt_linger, .eo_setopt = nni_tls_ep_setopt_linger, }, + { + .eo_name = NNG_OPT_URL, + .eo_getopt = nni_tls_ep_getopt_url, + .eo_setopt = NULL, + }, { .eo_name = NNG_OPT_TLS_CONFIG, .eo_getopt = tls_getopt_config, diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c index f8ed4626..4a846301 100644 --- a/src/transport/zerotier/zerotier.c +++ b/src/transport/zerotier/zerotier.c @@ -230,7 +230,6 @@ struct zt_ep { uint64_t ze_nwid; int ze_mode; int ze_running; - nni_sockaddr ze_addr; uint64_t ze_raddr; // remote node address uint64_t ze_laddr; // local node address uint16_t ze_proto; @@ -2556,6 +2555,21 @@ zt_ep_getopt_home(void *arg, void *data, size_t *szp) return (nni_getopt_str(ep->ze_home, data, szp)); } +static int +zt_ep_getopt_url(void *arg, void *data, size_t *szp) +{ + char ustr[64]; // more than plenty + zt_ep * ep = arg; + uint64_t addr; + + addr = ep->ze_mode == NNI_EP_MODE_DIAL ? ep->ze_raddr : ep->ze_laddr; + snprintf(ustr, sizeof(ustr), "zt://%llx.%llx:%u", + (unsigned long long) addr >> zt_port_shift, + (unsigned long long) ep->ze_nwid, + (unsigned) (addr & zt_port_mask)); + return (nni_getopt_str(ustr, data, szp)); +} + static int zt_ep_setopt_orbit(void *arg, const void *data, size_t sz) { @@ -2724,6 +2738,11 @@ static nni_tran_ep_option zt_ep_options[] = { .eo_getopt = zt_ep_getopt_recvmaxsz, .eo_setopt = zt_ep_setopt_recvmaxsz, }, + { + .eo_name = NNG_OPT_URL, + .eo_getopt = zt_ep_getopt_url, + .eo_setopt = NULL, + }, { .eo_name = NNG_OPT_ZT_HOME, .eo_getopt = zt_ep_getopt_home, -- cgit v1.2.3-70-g09d2