aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-12-29 14:21:20 -0800
committerGarrett D'Amore <garrett@damore.org>2017-12-30 19:05:41 -0800
commit6a50035b242b972c1d9b659ba63e037a0a8afe71 (patch)
treefe2600235a01e72d1e7bd5fad1d5e2ea62aada2e /src/transport
parenta0364185784895c4bc748a6e6453a132d618c96c (diff)
downloadnng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.gz
nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.bz2
nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.zip
fixes #166 Websocket TLS mapping
This introduces the wss:// scheme, which is available and works like the ws:// scheme if TLS is enabled in the library. The library modularization is refactored somewhat, to make it easier to use. There is now a single NNG_ENABLE_TLS that enables TLS support under the hood. This also adds a new option for the TLS transport, NNG_OPT_TLS_CONFIG (and a similar one for WSS, NNG_OPT_TLS_WSS_CONFIG) that offer access to the underlying TLS configuration object, which now has a public API to go with it as well. Note that it is also possible to use pure HTTPS using the *private* API, which will be exposed in a public form soon.
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/tls/tls.c107
-rw-r--r--src/transport/tls/tls.h6
-rw-r--r--src/transport/ws/websocket.c132
-rw-r--r--src/transport/ws/websocket.h22
-rw-r--r--src/transport/zerotier/CMakeLists.txt1
-rw-r--r--src/transport/zerotier/zerotier.c3
6 files changed, 219 insertions, 52 deletions
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c
index 9c794e64..f2ca6d35 100644
--- a/src/transport/tls/tls.c
+++ b/src/transport/tls/tls.c
@@ -14,7 +14,7 @@
#include "core/nng_impl.h"
-#include "supplemental/tls.h"
+#include "supplemental/tls/tls.h"
#include "tls.h"
// TLS over TCP transport. Platform specific TCP operations must be
@@ -61,7 +61,7 @@ struct nni_tls_ep {
nni_aio * aio;
nni_aio * user_aio;
nni_mtx mtx;
- nni_tls_config * cfg;
+ nng_tls_config * cfg;
};
static void nni_tls_pipe_send_cb(void *);
@@ -477,7 +477,7 @@ nni_tls_pipe_getopt_locaddr(void *arg, void *v, size_t *szp)
nng_sockaddr sa;
memset(&sa, 0, sizeof(sa));
- if ((rv = nni_plat_tcp_pipe_sockname(p->tcp, &sa)) == 0) {
+ if ((rv = nni_tls_sockname(p->tls, &sa)) == 0) {
rv = nni_getopt_sockaddr(&sa, v, szp);
}
return (rv);
@@ -491,7 +491,7 @@ nni_tls_pipe_getopt_remaddr(void *arg, void *v, size_t *szp)
nng_sockaddr sa;
memset(&sa, 0, sizeof(sa));
- if ((rv = nni_plat_tcp_pipe_peername(p->tcp, &sa)) == 0) {
+ if ((rv = nni_tls_peername(p->tls, &sa)) == 0) {
rv = nni_getopt_sockaddr(&sa, v, szp);
}
return (rv);
@@ -589,7 +589,7 @@ nni_tls_ep_fini(void *arg)
nni_plat_tcp_ep_fini(ep->tep);
}
if (ep->cfg) {
- nni_tls_config_fini(ep->cfg);
+ nng_tls_config_fini(ep->cfg);
}
nni_aio_fini(ep->aio);
nni_mtx_fini(&ep->mtx);
@@ -599,18 +599,18 @@ nni_tls_ep_fini(void *arg)
static int
nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
{
- nni_tls_ep * ep;
- int rv;
- char buf[NNG_MAXADDRLEN + 1];
- char * rhost;
- char * rserv;
- char * lhost;
- char * lserv;
- nni_sockaddr rsa, lsa;
- nni_aio * aio;
- int passive;
- int tlsmode;
- int authmode;
+ nni_tls_ep * ep;
+ int rv;
+ char buf[NNG_MAXADDRLEN + 1];
+ char * rhost;
+ char * rserv;
+ char * lhost;
+ char * lserv;
+ nni_sockaddr rsa, lsa;
+ nni_aio * aio;
+ int passive;
+ nng_tls_mode tlsmode;
+ nng_tls_auth_mode authmode;
// Make a copy of the url (to allow for destructive operations)
if (nni_strlcpy(buf, url, sizeof(buf)) >= sizeof(buf)) {
@@ -628,12 +628,12 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
}
if (mode == NNI_EP_MODE_DIAL) {
passive = 0;
- tlsmode = NNI_TLS_CONFIG_CLIENT;
- authmode = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED;
+ tlsmode = NNG_TLS_MODE_CLIENT;
+ authmode = NNG_TLS_AUTH_MODE_REQUIRED;
} else {
passive = 1;
- tlsmode = NNI_TLS_CONFIG_SERVER;
- authmode = NNI_TLS_CONFIG_AUTH_MODE_NONE;
+ tlsmode = NNG_TLS_MODE_SERVER;
+ authmode = NNG_TLS_AUTH_MODE_NONE;
}
// XXX: arguably we could defer this part to the point we do a bind
@@ -684,15 +684,15 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
}
if (((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) ||
- ((rv = nni_tls_config_init(&ep->cfg, tlsmode)) != 0) ||
- ((rv = nni_tls_config_auth_mode(ep->cfg, authmode)) != 0) ||
+ ((rv = nng_tls_config_init(&ep->cfg, tlsmode)) != 0) ||
+ ((rv = nng_tls_config_auth_mode(ep->cfg, authmode)) != 0) ||
((rv = nni_aio_init(&ep->aio, nni_tls_ep_cb, ep)) != 0)) {
nni_strfree(rhost);
nni_tls_ep_fini(ep);
return (rv);
}
- if ((tlsmode == NNI_TLS_CONFIG_CLIENT) && (rhost != NULL)) {
- if ((rv = nni_tls_config_server_name(ep->cfg, rhost)) != 0) {
+ if ((tlsmode == NNG_TLS_MODE_CLIENT) && (rhost != NULL)) {
+ if ((rv = nng_tls_config_server_name(ep->cfg, rhost)) != 0) {
nni_strfree(rhost);
nni_tls_ep_fini(ep);
return (rv);
@@ -868,6 +868,38 @@ nni_tls_ep_getopt_linger(void *arg, void *v, size_t *szp)
}
static int
+tls_setopt_config(void *arg, const void *data, size_t sz)
+{
+ nni_tls_ep * ep = arg;
+ nng_tls_config *cfg, *old;
+
+ if (sz != sizeof(cfg)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&cfg, data, sz);
+ if (cfg == NULL) {
+ return (NNG_EINVAL);
+ }
+ if (ep == NULL) {
+ return (0);
+ }
+ old = ep->cfg;
+ nni_tls_config_hold(cfg);
+ ep->cfg = cfg;
+ if (old != NULL) {
+ nng_tls_config_fini(old);
+ }
+ return (0);
+}
+
+static int
+tls_getopt_config(void *arg, void *v, size_t *szp)
+{
+ nni_tls_ep *ep = arg;
+ return (nni_getopt_ptr(ep->cfg, v, szp));
+}
+
+static int
tls_setopt_ca_cert(void *arg, const void *data, size_t sz)
{
nni_tls_ep *ep = arg;
@@ -875,7 +907,7 @@ tls_setopt_ca_cert(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_ca_cert(ep->cfg, data, sz));
+ return (nng_tls_config_ca_cert(ep->cfg, data, sz));
}
static int
@@ -886,7 +918,7 @@ tls_setopt_cert(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_cert(ep->cfg, data, sz));
+ return (nng_tls_config_cert(ep->cfg, data, sz));
}
static int
@@ -897,7 +929,7 @@ tls_setopt_private_key(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_key(ep->cfg, data, sz));
+ return (nng_tls_config_key(ep->cfg, data, sz));
}
static int
@@ -914,13 +946,9 @@ tls_setopt_pass(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_pass(ep->cfg, data));
+ return (nng_tls_config_pass(ep->cfg, data));
}
-int nng_tls_auth_mode_none = NNI_TLS_CONFIG_AUTH_MODE_NONE;
-int nng_tls_auth_mode_required = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED;
-int nng_tls_auth_mode_optional = NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL;
-
static int
tls_getopt_auth_mode(void *arg, void *v, size_t *szp)
{
@@ -938,9 +966,9 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz)
rv = nni_setopt_int(&mode, data, sz, -100, 100);
if (rv == 0) {
switch (mode) {
- case NNI_TLS_CONFIG_AUTH_MODE_NONE:
- case NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL:
- case NNI_TLS_CONFIG_AUTH_MODE_REQUIRED:
+ case NNG_TLS_AUTH_MODE_NONE:
+ case NNG_TLS_AUTH_MODE_OPTIONAL:
+ case NNG_TLS_AUTH_MODE_REQUIRED:
break;
default:
rv = NNG_EINVAL;
@@ -952,7 +980,7 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz)
return (rv);
}
- if ((rv = nni_tls_config_auth_mode(ep->cfg, mode)) == 0) {
+ if ((rv = nng_tls_config_auth_mode(ep->cfg, mode)) == 0) {
ep->authmode = mode;
}
return (rv);
@@ -998,6 +1026,11 @@ static nni_tran_ep_option nni_tls_ep_options[] = {
.eo_setopt = nni_tls_ep_setopt_linger,
},
{
+ .eo_name = NNG_OPT_TLS_CONFIG,
+ .eo_getopt = tls_getopt_config,
+ .eo_setopt = tls_setopt_config,
+ },
+ {
.eo_name = NNG_OPT_TLS_CA_CERT,
.eo_getopt = NULL,
.eo_setopt = tls_setopt_ca_cert,
diff --git a/src/transport/tls/tls.h b/src/transport/tls/tls.h
index 4317ae55..b36ee774 100644
--- a/src/transport/tls/tls.h
+++ b/src/transport/tls/tls.h
@@ -49,14 +49,12 @@ NNG_DECL int nng_tls_register(void);
// and off on servers/listeners, by default.
#define NNG_OPT_TLS_AUTH_MODE "tls:auth-mode"
-extern int nng_tls_auth_mode_required;
-extern int nng_tls_auth_mode_none;
-extern int nng_tls_auth_mode_optional;
-
// NNG_OPT_TLS_AUTH_VERIFIED is a boolean that can be read on pipes,
// indicating whether the peer certificate is verified.
#define NNG_OPT_TLS_AUTH_VERIFIED "tls:auth-verified"
+#define NNG_OPT_TLS_CONFIG "tls:config"
+
// XXX: TBD: Ciphersuite selection and reporting. Session reuse?
#endif // NNG_TRANSPORT_TLS_TLS_H
diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c
index 4f948fb7..1162338e 100644
--- a/src/transport/ws/websocket.c
+++ b/src/transport/ws/websocket.c
@@ -15,6 +15,7 @@
#include "core/nng_impl.h"
#include "supplemental/http/http.h"
+#include "supplemental/tls/tls.h"
#include "supplemental/websocket/websocket.h"
#include "websocket.h"
@@ -42,6 +43,7 @@ struct ws_ep {
nni_ws_listener *listener;
nni_ws_dialer * dialer;
nni_list headers; // to send, res or req
+ nng_tls_config * tls;
};
struct ws_pipe {
@@ -368,9 +370,6 @@ ws_ep_setopt_headers(ws_ep *ep, const void *v, size_t sz)
ws_hdr * h;
int rv;
- if (nni_strnlen(v, sz) >= sz) {
- return (NNG_EINVAL);
- }
if (ep == NULL) {
return (0);
}
@@ -449,7 +448,11 @@ ws_ep_setopt_reqhdrs(void *arg, const void *v, size_t sz)
{
ws_ep *ep = arg;
- if (ep->mode == NNI_EP_MODE_LISTEN) {
+ if (nni_strnlen(v, sz) >= sz) {
+ return (NNG_EINVAL);
+ }
+
+ if ((ep != NULL) && (ep->mode == NNI_EP_MODE_LISTEN)) {
return (NNG_EREADONLY);
}
return (ws_ep_setopt_headers(ep, v, sz));
@@ -460,7 +463,11 @@ ws_ep_setopt_reshdrs(void *arg, const void *v, size_t sz)
{
ws_ep *ep = arg;
- if (ep->mode == NNI_EP_MODE_DIAL) {
+ if (nni_strnlen(v, sz) >= sz) {
+ return (NNG_EINVAL);
+ }
+
+ if ((ep != NULL) && (ep->mode == NNI_EP_MODE_DIAL)) {
return (NNG_EREADONLY);
}
return (ws_ep_setopt_headers(ep, v, sz));
@@ -594,6 +601,11 @@ ws_ep_fini(void *arg)
nni_strfree(ep->addr);
nni_strfree(ep->protoname);
nni_mtx_fini(&ep->mtx);
+#ifdef NNG_TRANSPORT_WSS
+ if (ep->tls) {
+ nng_tls_config_fini(ep->tls);
+ }
+#endif
NNI_FREE_STRUCT(ep);
}
@@ -689,10 +701,21 @@ ws_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
return (NNG_ENOMEM);
}
-
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->headers, ws_hdr, node);
+#ifdef NNG_TRANSPORT_WSS
+ if (strncmp(url, "wss://", 4) == 0) {
+ rv = nng_tls_config_init(&ep->tls,
+ mode == NNI_EP_MODE_DIAL ? NNG_TLS_MODE_CLIENT
+ : NNG_TLS_MODE_SERVER);
+ if (rv != 0) {
+ NNI_FREE_STRUCT(ep);
+ return (rv);
+ }
+ }
+#endif
+
// List of pipes (server only).
nni_aio_list_init(&ep->aios);
@@ -758,3 +781,100 @@ nng_ws_register(void)
{
return (nni_tran_register(&ws_tran));
}
+
+#ifdef NNG_TRANSPORT_WSS
+
+static int
+wss_ep_getopt_tlsconfig(void *arg, void *v, size_t *szp)
+{
+ ws_ep *ep = arg;
+ return (nni_getopt_ptr(ep->tls, v, szp));
+}
+
+static int
+wss_ep_setopt_tlsconfig(void *arg, const void *v, size_t sz)
+{
+ ws_ep * ep = arg;
+ nng_tls_config *cfg;
+ int rv;
+
+ if (sz != sizeof(cfg)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&cfg, v, sz);
+ if (cfg == NULL) {
+ // NULL is clearly invalid.
+ return (NNG_EINVAL);
+ }
+ if (ep == NULL) {
+ return (0);
+ }
+ nni_mtx_lock(&ep->mtx);
+ if (ep->mode == NNI_EP_MODE_LISTEN) {
+ rv = nni_ws_listener_set_tls(ep->listener, cfg);
+ } else {
+ rv = nni_ws_dialer_set_tls(ep->dialer, cfg);
+ }
+ if (rv == 0) {
+ if (ep->tls != NULL) {
+ nng_tls_config_fini(ep->tls);
+ }
+ nni_tls_config_hold(cfg);
+ ep->tls = cfg;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
+static nni_tran_ep_option wss_ep_options[] = {
+ {
+ .eo_name = NNG_OPT_RECVMAXSZ,
+ .eo_getopt = ws_ep_getopt_recvmaxsz,
+ .eo_setopt = ws_ep_setopt_recvmaxsz,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_REQUEST_HEADERS,
+ .eo_getopt = NULL,
+ .eo_setopt = ws_ep_setopt_reqhdrs,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_RESPONSE_HEADERS,
+ .eo_getopt = NULL,
+ .eo_setopt = ws_ep_setopt_reshdrs,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_TLS_CONFIG,
+ .eo_getopt = wss_ep_getopt_tlsconfig,
+ .eo_setopt = wss_ep_setopt_tlsconfig,
+ },
+
+ // terminate list
+ { NULL, NULL, NULL },
+};
+
+static nni_tran_ep wss_ep_ops = {
+ .ep_init = ws_ep_init,
+ .ep_fini = ws_ep_fini,
+ .ep_connect = ws_ep_connect,
+ .ep_bind = ws_ep_bind,
+ .ep_accept = ws_ep_accept,
+ .ep_close = ws_ep_close,
+ .ep_options = wss_ep_options,
+};
+
+static nni_tran wss_tran = {
+ .tran_version = NNI_TRANSPORT_VERSION,
+ .tran_scheme = "wss",
+ .tran_ep = &wss_ep_ops,
+ .tran_pipe = &ws_pipe_ops,
+ .tran_init = ws_tran_init,
+ .tran_fini = ws_tran_fini,
+};
+
+int
+nng_wss_register(void)
+{
+ return (nni_tran_register(&wss_tran));
+}
+
+#endif // NNG_TRANSPORT_WSS
diff --git a/src/transport/ws/websocket.h b/src/transport/ws/websocket.h
index 2e86aaf0..a0d8a6cc 100644
--- a/src/transport/ws/websocket.h
+++ b/src/transport/ws/websocket.h
@@ -15,12 +15,30 @@
NNG_DECL int nng_ws_register(void);
-// NNG_OPT_TLS_REQUEST_HEADERS is a string containing the
+// NNG_OPT_WS_REQUEST_HEADERS is a string containing the
// request headers, formatted as CRLF terminated lines.
#define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers"
-// NNG_OPT_TLS_RESPONSE_HEADERS is a string containing the
+// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the
// response headers, formatted as CRLF terminated lines.
#define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers"
+// NNG_OPT_WSS_TLS_CONFIG is a pointer to a an nng_tls_config
+// object. This property is only available for wss:// style
+// endpoints. Note that when configuring the object, a hold
+// is placed on the TLS configuration. When retrieving the
+// object, no hold is placed, and so the caller must take care
+// not to use the configuration object after the endpoint it
+// is associated with is removed. Furthermore, as this is a
+// pointer, applications must take care to pass only valid
+// data -- incorrect pointer values will lead to undefined
+// behavior.
+#define NNG_OPT_WSS_TLS_CONFIG "wss:tls-config"
+
+// These aliases are for WSS naming consistency.
+#define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS
+#define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS
+
+NNG_DECL int nng_wss_register(void);
+
#endif // NNG_TRANSPORT_WS_WEBSOCKET_H
diff --git a/src/transport/zerotier/CMakeLists.txt b/src/transport/zerotier/CMakeLists.txt
index c1bb0c35..a4271eb7 100644
--- a/src/transport/zerotier/CMakeLists.txt
+++ b/src/transport/zerotier/CMakeLists.txt
@@ -11,6 +11,7 @@
# ZeroTier protocol
set (NNG_TRANSPORT_ZEROTIER_SOURCE "" CACHE PATH "Location of ZeroTier source tree.")
+mark_as_advanced(NNG_TRANSPORT_ZEROTIER_SOURCE)
if (NNG_TRANSPORT_ZEROTIER)
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index 3cb2871a..f6594eb3 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -8,7 +8,6 @@
// found online at https://opensource.org/licenses/MIT.
//
-#ifdef NNG_HAVE_ZEROTIER
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -2804,5 +2803,3 @@ nng_zt_register(void)
{
return (nni_tran_register(&zt_tran));
}
-
-#endif