2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 23:55:27 +00:00

refactor outgoing HTTP connection support

- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
  into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
  function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
  and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
  in isc_nm_httpconnect(); this eliminates the need to parse the URI
  and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
  for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
  isc_tlsctx_createclient(), we now have a function
  isc_tlsctx_enable_http2client_alpn() that can be run from
  isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
  isc_nm_send() or isc_nm_read() is called on an http socket, it will
  be stored until a corresponding isc_nm_read() or _send() arrives; when
  we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
  internal helper function by the DoH unit test. (eventually doh_test
  should be rewritten to use read and send, and this function should
  be removed.)
- added implementations of isc__nm_tls_settimeout() and
  isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
  help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
  currently we try to bypass HTTP caching proxies, but ideally we should
  interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
This commit is contained in:
Evan Hunt
2021-02-03 16:59:49 -08:00
committed by Artem Boldariev
parent 9c8b7a5c45
commit 88752b1121
17 changed files with 1794 additions and 1630 deletions

View File

@@ -64,7 +64,7 @@ add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
create_name(dohid, &dohname);
transport = dns_transport_new(&dohname, DNS_TRANSPORT_DOH,
transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
list);
parse_transport_option(doh, transport, "key-file",

View File

@@ -18,14 +18,14 @@ typedef enum {
DNS_TRANSPORT_UDP = 1,
DNS_TRANSPORT_TCP = 2,
DNS_TRANSPORT_TLS = 3,
DNS_TRANSPORT_DOH = 4,
DNS_TRANSPORT_HTTP = 4,
DNS_TRANSPORT_COUNT = 5,
} dns_transport_type_t;
typedef enum {
DNS_DOH_GET = 0,
DNS_DOH_POST = 1,
} dns_doh_mode_t;
DNS_HTTP_GET = 0,
DNS_HTTP_POST = 1,
} dns_http_mode_t;
typedef struct dns_transport dns_transport_t;
typedef struct dns_transport_list dns_transport_list_t;
@@ -50,11 +50,11 @@ char *
dns_transport_get_hostname(dns_transport_t *transport);
char *
dns_transport_get_endpoint(dns_transport_t *transport);
dns_doh_mode_t
dns_http_mode_t
dns_transport_get_mode(dns_transport_t *transport);
/*%<
* Getter functions: return the type, cert file, key file, CA file,
* hostname, DoH endpoint, or DoH mode (GET or POST) for 'transport'.
* hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
*/
void
@@ -68,16 +68,16 @@ dns_transport_set_hostname(dns_transport_t *transport, const char *hostname);
void
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint);
void
dns_transport_set_mode(dns_transport_t *transport, dns_doh_mode_t mode);
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode);
/*%<
* Setter functions: set the type, cert file, key file, CA file,
* hostname, DoH endpoint, or DoH mode (GET or POST) for 'transport'.
* hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
*
* Requires:
*\li 'transport' is valid.
*\li 'transport' is of type DNS_TRANSPORT_TLS or DNS_TRANSPORT_DOH
*\li 'transport' is of type DNS_TRANSPORT_TLS or DNS_TRANSPORT_HTTP
* (for certfile, keyfile, cafile, or hostname).
*\li 'transport' is of type DNS_TRANSPORT_DOH (for endpoint or mode).
*\li 'transport' is of type DNS_TRANSPORT_HTTP (for endpoint or mode).
*/
void

View File

@@ -50,7 +50,7 @@ struct dns_transport {
} tls;
struct {
char *endpoint;
dns_doh_mode_t mode;
dns_http_mode_t mode;
} doh;
};
@@ -124,7 +124,7 @@ dns_transport_get_endpoint(dns_transport_t *transport) {
return (transport->doh.endpoint);
}
dns_doh_mode_t
dns_http_mode_t
dns_transport_get_mode(dns_transport_t *transport) {
REQUIRE(VALID_TRANSPORT(transport));
@@ -150,7 +150,7 @@ void
dns_transport_set_certfile(dns_transport_t *transport, const char *certfile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (certfile != NULL) {
transport->tls.certfile = isc_mem_strdup(transport->mctx,
@@ -162,7 +162,7 @@ void
dns_transport_set_keyfile(dns_transport_t *transport, const char *keyfile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (keyfile != NULL) {
transport->tls.keyfile = isc_mem_strdup(transport->mctx,
@@ -174,7 +174,7 @@ void
dns_transport_set_cafile(dns_transport_t *transport, const char *cafile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (cafile != NULL) {
transport->tls.cafile = isc_mem_strdup(transport->mctx, cafile);
@@ -185,7 +185,7 @@ void
dns_transport_set_hostname(dns_transport_t *transport, const char *hostname) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (hostname != NULL) {
transport->tls.hostname = isc_mem_strdup(transport->mctx,
@@ -196,7 +196,7 @@ dns_transport_set_hostname(dns_transport_t *transport, const char *hostname) {
void
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_DOH);
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
if (endpoint != NULL) {
transport->doh.endpoint = isc_mem_strdup(transport->mctx,
@@ -205,9 +205,9 @@ dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
}
void
dns_transport_set_mode(dns_transport_t *transport, dns_doh_mode_t mode) {
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_DOH);
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
transport->doh.mode = mode;
}

View File

@@ -506,45 +506,17 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
* 'cb'.
*/
typedef void (*isc_nm_http_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *data, void *cbarg);
/*%<
* Callback function to be used when receiving an HTTP request.
*
* 'handle' the handle that can be used to send back the answer.
* 'eresult' the result of the event.
* 'data' contains the received data, if any. It will be freed
* after return by caller.
* 'cbarg' the callback argument passed to listen function.
*/
isc_result_t
isc_nm_http_connect_send_request(isc_nm_t *mgr, const char *uri, bool POST,
isc_region_t *message, isc_nm_recv_cb_t cb,
void *cbarg, isc_tlsctx_t *ctx,
unsigned int timeout);
isc_result_t
isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
isc_tlsctx_t *ctx, unsigned int timeout,
size_t extrahandlesize);
isc_result_t
isc_nm_httprequest(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_recv_cb_t reply_cb, void *cbarg);
isc_result_t
isc_nm_listenhttp(isc_nm_t *mgr, isc_nmiface_t *iface, int backlog,
isc_quota_t *quota, isc_tlsctx_t *ctx,
isc_nmsocket_t **sockp);
isc_result_t
isc_nm_http_add_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_http_cb_t cb, void *cbarg,
size_t extrahandlesize);
isc_result_t
isc_nm_http_add_doh_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_recv_cb_t cb, void *cbarg,
size_t extrahandlesize);
isc_nm_http_endpoint(isc_nmsocket_t *sock, const char *uri, isc_nm_recv_cb_t cb,
void *cbarg, size_t extrahandlesize);

View File

@@ -89,9 +89,10 @@
#define ISC_R_DEFAULT 68 /*%< default */
#define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */
#define ISC_R_TLSERROR 70 /*%< TLS error */
#define ISC_R_HTTP2ALPNERROR 71 /*%< ALPN for HTTP/2 failed */
/*% Not a result code: the number of results. */
#define ISC_R_NRESULTS 71
#define ISC_R_NRESULTS 72
ISC_LANG_BEGINDECLS

View File

@@ -14,35 +14,72 @@
#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tls.h>
#include <isc/types.h>
typedef struct ssl_ctx_st isc_tlsctx_t;
typedef struct ssl_st isc_tls_t;
void
isc_tlsctx_free(isc_tlsctx_t **ctpx);
/*%
* Free the TLS client/server context.
/*%<
* Free a TLS client or server context.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' != NULL.
*/
isc_result_t
isc_tlsctx_createserver(const char *keyfile, const char *certfile,
isc_tlsctx_t **ctxp);
/*%
* Set up TLS server context.
/*%<
* Set up a TLS server context, using the key and certificate specified in
* 'keyfile' and 'certfile', or a self-generated ephemeral key and
* certificdate if both 'keyfile' and 'certfile' are NULL.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*\li 'keyfile' and 'certfile' are either both NULL or both non-NULL.
*/
isc_result_t
isc_tlsctx_createclient(isc_tlsctx_t **ctxp);
/*%
* Set up TLS client context.
/*%<
* Set up a TLS client context.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*/
isc_tls_t *
isc_tls_create(isc_tlsctx_t *ctx);
/*%<
* Set up the structure to hold data for a new TLS connection.
*
* Requires:
*\li 'ctx' != NULL.
*/
void
isc_tls_free(isc_tls_t **tlsp);
/*%<
* Free a TLS structure.
*
* Requires:
*\li 'tlsp' != NULL and '*tlsp' != NULL.
*/
void
isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx);
void
isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *ctx);
/*%<
*
* Enable HTTP/2 Application Layer Protocol Negotation for 'ctx'.
*
* Requires:
*\li 'ctx' is not NULL.
*/
void
isc_tls_get_http2_alpn(isc_tls_t *tls, const unsigned char **alpn,
unsigned int *alpnlen);

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,7 @@
#include <isc/sockaddr.h>
#include <isc/stats.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "uv-compat.h"
@@ -156,8 +157,6 @@ isc__nm_dump_active(isc_nm_t *nm);
#define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock)
#endif
typedef struct isc_nm_http2_session isc_nm_http2_session_t;
/*
* Single network event loop worker.
*/
@@ -195,6 +194,7 @@ typedef struct isc__networker {
atomic_load(&(t)->references) > 0)
typedef void (*isc__nm_closecb)(isc_nmhandle_t *);
typedef struct isc_nm_http_session isc_nm_http_session_t;
struct isc_nmhandle {
int magic;
@@ -210,7 +210,7 @@ struct isc_nmhandle {
isc_nmsocket_t *sock;
size_t ah_pos; /* Position in the socket's 'active handles' array */
isc_nm_http2_session_t *httpsession;
isc_nm_http_session_t *httpsession;
isc_sockaddr_t peer;
isc_sockaddr_t local;
@@ -302,20 +302,18 @@ typedef enum isc__netievent_type {
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_http_cb_t http;
isc_nm_cb_t send;
isc_nm_cb_t connect;
isc_nm_accept_cb_t accept;
} isc__nm_cb_t;
typedef struct isc_nm_http2_server_handler isc_nm_http2_server_handler_t;
struct isc_nm_http2_server_handler {
typedef struct isc_nm_httphandler isc_nm_httphandler_t;
struct isc_nm_httphandler {
char *path;
isc_nm_http_cb_t cb;
isc_nm_recv_cb_t cb;
void *cbarg;
size_t extrahandlesize;
LINK(isc_nm_http2_server_handler_t) link;
LINK(isc_nm_httphandler_t) link;
};
/*
@@ -674,7 +672,7 @@ typedef enum isc_nmsocket_type {
isc_nm_tlsdnslistener,
isc_nm_tlsdnssocket,
isc_nm_httplistener,
isc_nm_httpstream
isc_nm_httpsocket
} isc_nmsocket_type;
/*%
@@ -704,25 +702,29 @@ enum {
typedef struct isc_nmsocket_tls_send_req {
isc_nmsocket_t *tlssock;
isc_region_t data;
isc_nm_cb_t cb;
void *cbarg;
isc_nmhandle_t *handle;
bool finish;
} isc_nmsocket_tls_send_req_t;
typedef enum isc_doh_request_type {
typedef enum isc_http_request_type {
ISC_HTTP_REQ_GET,
ISC_HTTP_REQ_POST,
ISC_HTTP_REQ_UNSUPPORTED
} isc_http2_request_type_t;
} isc_http_request_type_t;
typedef enum isc_http2_scheme_type {
typedef enum isc_http_scheme_type {
ISC_HTTP_SCHEME_HTTP,
ISC_HTTP_SCHEME_HTTP_SECURE,
ISC_HTTP_SCHEME_UNSUPPORTED
} isc_http2_scheme_type_t;
} isc_http_scheme_type_t;
typedef struct isc_nm_http_doh_cbarg {
typedef struct isc_nm_httpcbarg {
isc_nm_recv_cb_t cb;
void *cbarg;
LINK(struct isc_nm_http_doh_cbarg) link;
} isc_nm_http_doh_cbarg_t;
LINK(struct isc_nm_httpcbarg) link;
} isc_nm_httpcbarg_t;
typedef struct isc_nmsocket_h2 {
isc_nmsocket_t *psock; /* owner of the structure */
@@ -730,38 +732,43 @@ typedef struct isc_nmsocket_h2 {
char *query_data;
size_t query_data_len;
bool query_too_large;
isc_nm_http2_server_handler_t *handler;
isc_nm_httphandler_t *handler;
uint8_t *buf;
size_t bufsize;
size_t bufpos;
int32_t stream_id;
isc_nm_http2_session_t *session;
isc_nm_http_session_t *session;
isc_nmsocket_t *httpserver;
isc_http2_request_type_t request_type;
isc_http2_scheme_type_t request_scheme;
isc_http_request_type_t request_type;
isc_http_scheme_type_t request_scheme;
size_t content_length;
char clenbuf[128];
bool content_type_verified;
bool accept_type_verified;
isc_nm_http_cb_t handler_cb;
void *handler_cbarg;
isc_nm_recv_cb_t cb;
void *cbarg;
LINK(struct isc_nmsocket_h2) link;
ISC_LIST(isc_nm_http2_server_handler_t) handlers;
ISC_LIST(isc_nm_http_doh_cbarg_t) handlers_cbargs;
isc_rwlock_t handlers_lock;
ISC_LIST(isc_nm_httphandler_t) handlers;
ISC_LIST(isc_nm_httpcbarg_t) handler_cbargs;
isc_rwlock_t lock;
char response_content_length_str[128];
struct isc_nmsocket_h2_connect_data {
struct {
char *uri;
bool post;
isc_tlsctx_t *tlsctx;
isc_nmiface_t local_interface;
void *cstream;
} connect;
} isc_nmsocket_h2_t;
struct isc_nmsocket {
/*% Unlocked, RO */
int magic;
@@ -778,8 +785,8 @@ struct isc_nmsocket {
/*% TLS stuff */
struct tls {
SSL *ssl;
SSL_CTX *ctx;
isc_tls_t *tls;
isc_tlsctx_t *ctx;
BIO *app_rbio;
BIO *app_wbio;
BIO *ssl_rbio;
@@ -802,21 +809,22 @@ struct isc_nmsocket {
struct tlsstream {
bool server;
BIO *app_bio;
SSL *ssl;
SSL_CTX *ctx;
isc_tls_t *tls;
isc_tlsctx_t *ctx;
BIO *ssl_bio;
isc_nmsocket_t *tlslistener;
isc_nmiface_t server_iface;
isc_nmiface_t local_iface;
bool connect_from_networker;
atomic_bool result_updated;
enum {
TLS_INIT,
TLS_HANDSHAKE,
TLS_IO,
TLS_ERROR,
TLS_CLOSING,
TLS_CLOSED
} state;
} state; /*%< The order of these is significant */
size_t nsending;
/* List of active send requests. */
ISC_LIST(isc__nm_uvreq_t) sends;
} tlsstream;
isc_nmsocket_h2_t h2;
@@ -1149,11 +1157,15 @@ isc__nmsocket_clearcb(isc_nmsocket_t *sock);
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Issue a connect callback on the socket, used to call the callback
*/
void
@@ -1518,19 +1530,42 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock);
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_tls_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TCP socket it wraps
* around.
*/
void
isc__nm_http_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_http_clear_handlers(isc_nmsocket_t *sock);
isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TLS/TCP socket it wraps
* around.
*/
void
isc__nm_http_clear_session(isc_nmsocket_t *sock);
isc__nm_http_initsocket(isc_nmsocket_t *sock);
void
isc__nm_http_cleanup_data(isc_nmsocket_t *sock);
isc_result_t
isc__nm_http_request(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_recv_cb_t reply_cb, void *cbarg);
void
isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_http_close(isc_nmsocket_t *sock);
@@ -1544,7 +1579,7 @@ void
isc__nm_async_httpclose(isc__networker_t *worker, isc__netievent_t *ev0);
bool
isc__nm_parse_doh_query_string(const char *query_string, const char **start,
isc__nm_parse_httpquery(const char *query_string, const char **start,
size_t *len);
char *
@@ -1555,6 +1590,12 @@ char *
isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64,
const size_t base64_len, size_t *res_len);
void
isc__nm_httpsession_attach(isc_nm_http_session_t *source,
isc_nm_http_session_t **targetp);
void
isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp);
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
isc_result_t

View File

@@ -1004,33 +1004,7 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
isc_condition_destroy(&sock->cond);
isc_condition_destroy(&sock->scond);
isc__nm_tls_cleanup_data(sock);
if (sock->type == isc_nm_httplistener) {
isc__nm_http_clear_handlers(sock);
isc_rwlock_destroy(&sock->h2.handlers_lock);
}
if (sock->h2.request_path != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.request_path);
sock->h2.request_path = NULL;
}
if (sock->h2.query_data != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.query_data);
sock->h2.query_data = NULL;
}
if (sock->h2.connect.uri != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.connect.uri);
sock->h2.query_data = NULL;
}
if (sock->h2.buf != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.buf);
sock->h2.buf = NULL;
}
isc__nm_http_clear_session(sock);
isc__nm_http_cleanup_data(sock);
#ifdef NETMGR_TRACE
LOCK(&sock->mgr->lock);
ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link);
@@ -1145,7 +1119,7 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_close(sock);
return;
case isc_nm_httpstream:
case isc_nm_httpsocket:
isc__nm_http_close(sock);
return;
default:
@@ -1255,7 +1229,7 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
case isc_nm_tcpdnslistener:
case isc_nm_tlsdnssocket:
case isc_nm_tlsdnslistener:
case isc_nm_httpstream:
case isc_nm_httpsocket:
case isc_nm_httplistener:
if (family == AF_INET) {
sock->statsindex = tcp4statsindex;
@@ -1274,7 +1248,6 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
isc_refcount_init(&sock->references, 1);
memset(&sock->tlsstream, 0, sizeof(sock->tlsstream));
ISC_LIST_INIT(sock->tlsstream.sends);
NETMGR_TRACE_LOG("isc__nmsocket_init():%p->references = %lu\n", sock,
isc_refcount_current(&sock->references));
@@ -1286,27 +1259,7 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
atomic_store(&sock->active_child_connections, 0);
if (type == isc_nm_httplistener) {
ISC_LIST_INIT(sock->h2.handlers);
ISC_LIST_INIT(sock->h2.handlers_cbargs);
isc_rwlock_init(&sock->h2.handlers_lock, 0, 1);
}
sock->h2.session = NULL;
sock->h2.httpserver = NULL;
sock->h2.query_data = NULL;
sock->h2.query_data_len = 0;
sock->h2.query_too_large = false;
sock->h2.request_path = NULL;
sock->h2.request_type = ISC_HTTP_REQ_UNSUPPORTED;
sock->h2.request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED;
sock->h2.content_length = 0;
sock->h2.content_type_verified = false;
sock->h2.accept_type_verified = false;
sock->h2.handler_cb = NULL;
sock->h2.handler_cbarg = NULL;
sock->h2.connect.uri = NULL;
sock->h2.buf = NULL;
isc__nm_http_initsocket(sock);
sock->magic = NMSOCK_MAGIC;
}
@@ -1449,8 +1402,9 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
sock->statichandle = handle;
}
if (sock->type == isc_nm_httpstream) {
handle->httpsession = sock->h2.session;
if (sock->type == isc_nm_httpsocket && sock->h2.session) {
isc__nm_httpsession_attach(sock->h2.session,
&handle->httpsession);
}
return (handle);
@@ -1582,6 +1536,10 @@ nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG) {
handle->doreset(handle->opaque);
}
if (sock->type == isc_nm_httpsocket && handle->httpsession != NULL) {
isc__nm_httpsession_detach(&handle->httpsession);
}
nmhandle_deactivate(sock, handle);
/*
@@ -1642,6 +1600,12 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_settimeout(handle, timeout);
break;
case isc_nm_tlssocket:
isc__nm_tls_settimeout(handle, timeout);
break;
case isc_nm_httpsocket:
isc__nm_http_settimeout(handle, timeout);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@@ -1758,7 +1722,7 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_send(handle, region, cb, cbarg);
break;
case isc_nm_httpstream:
case isc_nm_httpsocket:
isc__nm_http_send(handle, region, cb, cbarg);
break;
default:
@@ -1794,6 +1758,9 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_read(handle, cb, cbarg);
break;
case isc_nm_httpsocket:
isc__nm_http_read(handle, cb, cbarg);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@@ -1893,27 +1860,38 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
}
}
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
static void
nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc_result_t eresult,
bool force_async) {
isc__netievent_connectcb_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(uvreq));
REQUIRE(VALID_NMHANDLE(uvreq->handle));
if (eresult == ISC_R_SUCCESS) {
isc__netievent_connectcb_t ievent = { .sock = sock,
.req = uvreq,
.result = eresult };
isc__nm_async_connectcb(NULL, (isc__netievent_t *)&ievent);
} else {
isc__netievent_connectcb_t *ievent =
isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
ievent = isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
eresult);
if (force_async) {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
} else {
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, false);
}
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, true);
}
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_connectcb_t *ievent = (isc__netievent_connectcb_t *)ev0;
@@ -2460,8 +2438,8 @@ nmsocket_type_totext(isc_nmsocket_type type) {
return ("isc_nm_tlsdnssocket");
case isc_nm_httplistener:
return ("isc_nm_httplistener");
case isc_nm_httpstream:
return ("isc_nm_httpstream");
case isc_nm_httpsocket:
return ("isc_nm_httpsocket");
default:
INSIST(0);
ISC_UNREACHABLE();

View File

@@ -167,23 +167,6 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
result = isc__nm_socket(req->peer.type.sa.sa_family, SOCK_STREAM, 0,
&sock->fd);
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->closed, true);
isc__nm_uvreq_t *cbreq = NULL;
cbreq = isc__nm_uvreq_get(sock->mgr, sock);
cbreq->cb.connect = req->cb.connect;
cbreq->cbarg = req->cbarg;
isc_nmhandle_attach(req->handle, &cbreq->handle);
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, cbreq, result);
goto error;
}
result = isc__nm_socket_connectiontimeout(sock->fd,
sock->connect_timeout);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -231,7 +214,7 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
done:
result = isc__nm_uverr2result(r);
error:
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
@@ -260,7 +243,6 @@ isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->parent == NULL);
REQUIRE(sock->tid == isc_nm_tid());
sock->fd = (uv_os_sock_t)(-1);
result = tcp_connect_direct(sock, req);
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->active, false);
@@ -333,17 +315,31 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nmsocket_t *sock = NULL;
isc__netievent_tcpconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
REQUIRE(peer != NULL);
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(*sock));
isc__nmsocket_init(sock, mgr, isc_nm_tcpsocket, local);
sock->extrahandlesize = extrahandlesize;
sock->connect_timeout = timeout;
sock->result = ISC_R_DEFAULT;
sock->fd = fd;
atomic_init(&sock->client, true);
req = isc__nm_uvreq_get(mgr, sock);

View File

@@ -338,8 +338,8 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
}
sock->tls.state = TLS_STATE_NONE;
sock->tls.ssl = SSL_new(sock->tls.ctx);
RUNTIME_CHECK(sock->tls.ssl != NULL);
sock->tls.tls = isc_tls_create(sock->tls.ctx);
RUNTIME_CHECK(sock->tls.tls != NULL);
/*
*
@@ -359,13 +359,13 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
*/
SSL_set0_rbio(sock->tls.ssl, sock->tls.ssl_rbio);
SSL_set0_wbio(sock->tls.ssl, sock->tls.ssl_wbio);
SSL_set0_rbio(sock->tls.tls, sock->tls.ssl_rbio);
SSL_set0_wbio(sock->tls.tls, sock->tls.ssl_wbio);
#else
SSL_set_bio(sock->tls.ssl, sock->tls.ssl_rbio, sock->tls.ssl_wbio);
SSL_set_bio(sock->tls.tls, sock->tls.ssl_rbio, sock->tls.ssl_wbio);
#endif
SSL_set_connect_state(sock->tls.ssl);
SSL_set_connect_state(sock->tls.tls);
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -782,7 +782,7 @@ isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0) {
return;
}
rv = SSL_shutdown(sock->tls.ssl);
rv = SSL_shutdown(sock->tls.tls);
if (rv == 1) {
sock->tls.state = TLS_STATE_NONE;
@@ -802,7 +802,7 @@ isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0) {
return;
}
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
switch (err) {
case SSL_ERROR_WANT_READ:
@@ -1167,9 +1167,9 @@ tls_cycle_input(isc_nmsocket_t *sock) {
size_t len;
for (;;) {
(void)SSL_peek(sock->tls.ssl, &(char){ '\0' }, 0);
(void)SSL_peek(sock->tls.tls, &(char){ '\0' }, 0);
int pending = SSL_pending(sock->tls.ssl);
int pending = SSL_pending(sock->tls.tls);
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
@@ -1179,7 +1179,7 @@ tls_cycle_input(isc_nmsocket_t *sock) {
}
len = 0;
rv = SSL_read_ex(sock->tls.ssl,
rv = SSL_read_ex(sock->tls.tls,
sock->buf + sock->buf_len,
sock->buf_size - sock->buf_len, &len);
if (rv != 1) {
@@ -1196,11 +1196,11 @@ tls_cycle_input(isc_nmsocket_t *sock) {
process_sock_buffer(sock);
}
} else if (!SSL_is_init_finished(sock->tls.ssl)) {
if (SSL_is_server(sock->tls.ssl)) {
rv = SSL_accept(sock->tls.ssl);
} else if (!SSL_is_init_finished(sock->tls.tls)) {
if (SSL_is_server(sock->tls.tls)) {
rv = SSL_accept(sock->tls.tls);
} else {
rv = SSL_connect(sock->tls.ssl);
rv = SSL_connect(sock->tls.tls);
}
} else {
@@ -1208,13 +1208,13 @@ tls_cycle_input(isc_nmsocket_t *sock) {
}
if (rv <= 0) {
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
}
switch (err) {
case SSL_ERROR_WANT_READ:
if (sock->tls.state == TLS_STATE_NONE &&
!SSL_is_init_finished(sock->tls.ssl)) {
!SSL_is_init_finished(sock->tls.tls)) {
sock->tls.state = TLS_STATE_HANDSHAKE;
start_reading(sock);
}
@@ -1237,11 +1237,11 @@ tls_cycle_input(isc_nmsocket_t *sock) {
/* Stop state after handshake */
if (sock->tls.state == TLS_STATE_HANDSHAKE &&
SSL_is_init_finished(sock->tls.ssl))
SSL_is_init_finished(sock->tls.tls))
{
sock->tls.state = TLS_STATE_IO;
if (SSL_is_server(sock->tls.ssl)) {
if (SSL_is_server(sock->tls.tls)) {
REQUIRE(sock->recv_handle != NULL);
result = sock->accept_cb(sock->recv_handle,
ISC_R_SUCCESS,
@@ -1656,18 +1656,8 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
csock->tls.state = TLS_STATE_NONE;
csock->tls.ssl = SSL_new(ssock->tls.ctx);
if (csock->tls.ssl == NULL) {
char errbuf[256];
unsigned long err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
fprintf(stderr, "%s:SSL_new(%p) -> %s\n", __func__,
ssock->tls.ctx, errbuf);
}
RUNTIME_CHECK(csock->tls.ssl != NULL);
csock->tls.tls = isc_tls_create(ssock->tls.ctx);
RUNTIME_CHECK(csock->tls.tls != NULL);
r = BIO_new_bio_pair(&csock->tls.ssl_wbio, TLS_BUF_SIZE,
&csock->tls.app_rbio, TLS_BUF_SIZE);
@@ -1684,13 +1674,13 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
*/
SSL_set0_rbio(csock->tls.ssl, csock->tls.ssl_rbio);
SSL_set0_wbio(csock->tls.ssl, csock->tls.ssl_wbio);
SSL_set0_rbio(csock->tls.tls, csock->tls.ssl_rbio);
SSL_set0_wbio(csock->tls.tls, csock->tls.ssl_wbio);
#else
SSL_set_bio(csock->tls.ssl, csock->tls.ssl_rbio, csock->tls.ssl_wbio);
SSL_set_bio(csock->tls.tls, csock->tls.ssl_rbio, csock->tls.ssl_wbio);
#endif
SSL_set_accept_state(csock->tls.ssl);
SSL_set_accept_state(csock->tls.tls);
/* FIXME: Set SSL_MODE_RELEASE_BUFFERS */
@@ -1823,7 +1813,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
/* Writes won't succeed until handshake end */
if (!SSL_is_init_finished(sock->tls.ssl)) {
if (!SSL_is_init_finished(sock->tls.tls)) {
goto requeue;
}
@@ -1837,7 +1827,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
memmove(worker->sendbuf + sizeof(uint16_t), req->uvbuf.base,
req->uvbuf.len);
rv = SSL_write_ex(sock->tls.ssl, worker->sendbuf, sendlen, &bytes);
rv = SSL_write_ex(sock->tls.tls, worker->sendbuf, sendlen, &bytes);
if (rv > 0) {
/* SSL_write_ex() doesn't do partial writes */
INSIST(sendlen == bytes);
@@ -1848,7 +1838,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
/* Nothing was written, maybe enqueue? */
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
switch (err) {
case SSL_ERROR_WANT_WRITE:
@@ -1921,9 +1911,8 @@ tlsdns_close_cb(uv_handle_t *handle) {
atomic_store(&sock->connected, false);
if (sock->tls.ssl) {
SSL_free(sock->tls.ssl);
sock->tls.ssl = NULL;
if (sock->tls.tls != NULL) {
isc_tls_free(&sock->tls.tls);
}
BIO_free_all(sock->tls.app_rbio);

View File

@@ -44,13 +44,15 @@ tls_error_to_result(int tls_err) {
switch (tls_err) {
case SSL_ERROR_ZERO_RETURN:
return (ISC_R_EOF);
case SSL_ERROR_SSL:
return (ISC_R_TLSERROR);
default:
return (ISC_R_UNEXPECTED);
}
}
static void
tls_do_bio(isc_nmsocket_t *sock);
tls_do_bio(isc_nmsocket_t *sock, isc__nm_uvreq_t *send_data, bool finish);
static void
tls_close_direct(isc_nmsocket_t *sock);
@@ -67,6 +69,8 @@ static bool
inactive(isc_nmsocket_t *sock) {
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
sock->outerhandle == NULL ||
!isc__nmsocket_active(sock->outerhandle->sock) ||
atomic_load(&sock->outerhandle->sock->closing) ||
(sock->listener != NULL &&
!isc__nmsocket_active(sock->listener)) ||
atomic_load(&sock->mgr->closing));
@@ -74,17 +78,31 @@ inactive(isc_nmsocket_t *sock) {
static void
update_result(isc_nmsocket_t *sock, const isc_result_t result) {
if (!sock->tlsstream.server) {
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
if (!atomic_load(&sock->active)) {
while (!atomic_load(&sock->active)) {
WAIT(&sock->scond, &sock->lock);
}
UNLOCK(&sock->lock);
if (sock->parent) {
LOCK(&sock->parent->lock);
sock->parent->result = result;
UNLOCK(&sock->parent->lock);
} else {
LOCK(&sock->lock);
sock->result = result;
UNLOCK(&sock->lock);
}
}
static void
tls_call_connect_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
const isc_result_t result) {
if (sock->connect_cb == NULL) {
return;
}
sock->connect_cb(handle, result, sock->connect_cbarg);
update_result(sock, result);
if (result != ISC_R_SUCCESS) {
isc__nmsocket_clearcb(handle->sock);
}
}
@@ -92,26 +110,38 @@ static void
tls_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nmsocket_tls_send_req_t *send_req =
(isc_nmsocket_tls_send_req_t *)cbarg;
isc_nmsocket_t *sock = send_req->tlssock;
isc_nmsocket_t *tlssock = NULL;
bool finish = send_req->finish;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_NMSOCK(send_req->tlssock));
/* XXXWPK TODO */
UNUSED(eresult);
tlssock = send_req->tlssock;
send_req->tlssock = NULL;
if (send_req->cb != NULL) {
send_req->cb(send_req->handle, eresult, send_req->cbarg);
isc_nmhandle_detach(&send_req->handle);
}
isc_mem_put(handle->sock->mgr->mctx, send_req->data.base,
send_req->data.length);
isc_mem_put(handle->sock->mgr->mctx, send_req, sizeof(*send_req));
tlssock->tlsstream.nsending--;
sock->tlsstream.nsending--;
async_tls_do_bio(sock);
isc__nmsocket_detach(&sock);
if (finish && eresult == ISC_R_SUCCESS) {
isc_nm_cancelread(handle);
} else if (eresult == ISC_R_SUCCESS) {
tls_do_bio(tlssock, NULL, false);
}
isc__nmsocket_detach(&tlssock);
}
static void
tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
const isc_result_t result, const bool close) {
const isc_result_t result) {
REQUIRE(VALID_NMSOCK(sock));
if (!sock->tlsstream.server &&
@@ -121,9 +151,7 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
{
INSIST(handle == NULL);
handle = isc__nmhandle_get(sock, NULL, NULL);
sock->connect_cb(handle, result, sock->connect_cbarg);
update_result(sock, result);
isc__nmsocket_clearcb(sock);
tls_call_connect_cb(sock, handle, result);
isc_nmhandle_detach(&handle);
} else if (sock->recv_cb != NULL) {
isc__nm_uvreq_t *req = NULL;
@@ -131,7 +159,7 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
req->cb.recv = sock->recv_cb;
req->cbarg = sock->recv_cbarg;
req->handle = NULL;
if (handle) {
if (handle != NULL) {
REQUIRE(VALID_NMHANDLE(handle));
isc_nmhandle_attach(handle, &req->handle);
} else {
@@ -140,11 +168,9 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
isc__nmsocket_clearcb(sock);
isc__nm_readcb(sock, req, result);
}
sock->tlsstream.state = TLS_ERROR;
if (close) {
isc__nmsocket_prep_destroy(sock);
}
isc__nmsocket_detach(&sock);
}
static void
@@ -155,12 +181,70 @@ async_tls_do_bio(isc_nmsocket_t *sock) {
(isc__netievent_t *)ievent);
}
static int
tls_send_outgoing(isc_nmsocket_t *sock, bool finish, isc_nmhandle_t *tlshandle,
isc_nm_cb_t cb, void *cbarg) {
isc_nmsocket_tls_send_req_t *send_req = NULL;
int pending;
int rv;
if (inactive(sock)) {
if (cb != NULL) {
INSIST(VALID_NMHANDLE(tlshandle));
cb(tlshandle, ISC_R_CANCELED, cbarg);
}
return (0);
}
if (finish && (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_SENT_SHUTDOWN) != SSL_SENT_SHUTDOWN)
{
(void)SSL_shutdown(sock->tlsstream.tls);
}
pending = BIO_pending(sock->tlsstream.app_bio);
if (pending <= 0) {
return (pending);
}
/* TODO Should we keep track of these requests in a list? */
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
send_req = isc_mem_get(sock->mgr->mctx, sizeof(*send_req));
*send_req = (isc_nmsocket_tls_send_req_t){
.finish = finish,
.data.base = isc_mem_get(sock->mgr->mctx, pending),
.data.length = pending
};
isc__nmsocket_attach(sock, &send_req->tlssock);
if (cb != NULL) {
send_req->cb = cb;
send_req->cbarg = cbarg;
isc_nmhandle_attach(tlshandle, &send_req->handle);
}
rv = BIO_read(sock->tlsstream.app_bio, send_req->data.base, pending);
/* There's something pending, read must succeed */
RUNTIME_CHECK(rv == pending);
INSIST(VALID_NMHANDLE(sock->outerhandle));
sock->tlsstream.nsending++;
isc_nm_send(sock->outerhandle, &send_req->data, tls_senddone, send_req);
return (pending);
}
static void
tls_do_bio(isc_nmsocket_t *sock) {
tls_do_bio(isc_nmsocket_t *sock, isc__nm_uvreq_t *send_data, bool finish) {
isc_result_t result = ISC_R_SUCCESS;
int pending, tls_err = 0;
int rv;
isc__nm_uvreq_t *req;
char buf[1];
bool sent_shutdown, received_shutdown;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
@@ -172,79 +256,91 @@ tls_do_bio(isc_nmsocket_t *sock) {
}
if (sock->tlsstream.state == TLS_INIT) {
(void)SSL_do_handshake(sock->tlsstream.ssl);
(void)SSL_do_handshake(sock->tlsstream.tls);
sock->tlsstream.state = TLS_HANDSHAKE;
} else if (sock->tlsstream.state == TLS_ERROR) {
result = ISC_R_FAILURE;
goto low_level_error;
} else if (sock->tlsstream.state == TLS_CLOSED) {
return;
}
received_shutdown = (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_RECEIVED_SHUTDOWN) == SSL_RECEIVED_SHUTDOWN;
/* Data from TLS to client */
char buf[1];
if (sock->tlsstream.state == TLS_IO && sock->recv_cb != NULL &&
if (sock->tlsstream.state >= TLS_IO && sock->recv_cb != NULL &&
!atomic_load(&sock->readpaused))
{
(void)SSL_peek(sock->tlsstream.ssl, buf, 1);
while ((pending = SSL_pending(sock->tlsstream.ssl)) > 0) {
(void)SSL_peek(sock->tlsstream.tls, buf, 1);
while ((pending = SSL_pending(sock->tlsstream.tls)) > 0) {
uint8_t recv_buf[TLS_BUF_SIZE];
isc_region_t region, dregion;
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
isc_region_t region = {
isc_mem_get(sock->mgr->mctx, pending), pending
};
isc_region_t dregion;
memset(region.base, 0, region.length);
rv = SSL_read(sock->tlsstream.ssl, region.base,
region = (isc_region_t){ .base = &recv_buf[0],
.length = pending };
rv = SSL_read(sock->tlsstream.tls, region.base,
region.length);
/* Pending succeded, so should read */
RUNTIME_CHECK(rv == pending);
dregion = (isc_region_t){ region.base, rv };
sock->recv_cb(sock->statichandle, ISC_R_SUCCESS,
&dregion, sock->recv_cbarg);
isc_mem_put(sock->mgr->mctx, region.base,
region.length);
}
}
if (send_data != NULL) {
INSIST(sock->tlsstream.state > TLS_HANDSHAKE);
rv = SSL_write(sock->tlsstream.tls, send_data->uvbuf.base,
send_data->uvbuf.len);
if (rv != (int)send_data->uvbuf.len) {
result = received_shutdown ? ISC_R_CANCELED
: ISC_R_TLSERROR;
send_data->cb.send(send_data->handle, result,
send_data->cbarg);
send_data = NULL;
if (!received_shutdown) {
isc__nmsocket_detach(&sock);
return;
}
}
}
sent_shutdown = (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
/* Peek to move the session forward */
(void)SSL_peek(sock->tlsstream.ssl, buf, 1);
(void)SSL_peek(sock->tlsstream.tls, buf, 1);
/* Data from TLS to network */
pending = BIO_pending(sock->tlsstream.app_bio);
if (pending > 0) {
/*TODO Should we keep the track of these requests in a list? */
isc_nmsocket_tls_send_req_t *send_req = NULL;
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
if (send_data != NULL) {
pending = tls_send_outgoing(sock, finish, send_data->handle,
send_data->cb.send,
send_data->cbarg);
} else {
if (received_shutdown && !sent_shutdown) {
finish = true;
(void)SSL_shutdown(sock->tlsstream.tls);
}
send_req = isc_mem_get(sock->mgr->mctx, sizeof(*send_req));
send_req->data.base = isc_mem_get(sock->mgr->mctx, pending);
send_req->data.length = pending;
send_req->tlssock = NULL;
isc__nmsocket_attach(sock, &send_req->tlssock);
rv = BIO_read(sock->tlsstream.app_bio, send_req->data.base,
pending);
/* There's something pending, read must succeed */
RUNTIME_CHECK(rv == pending);
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nm_send(sock->outerhandle, &send_req->data, tls_senddone,
send_req);
pending = tls_send_outgoing(sock, finish, NULL, NULL, NULL);
}
if (pending > 0) {
/* We'll continue in tls_senddone */
return;
}
/* Get the potential error code */
rv = SSL_peek(sock->tlsstream.ssl, buf, 1);
rv = SSL_peek(sock->tlsstream.tls, buf, 1);
if (rv < 0) {
tls_err = SSL_get_error(sock->tlsstream.ssl, rv);
tls_err = SSL_get_error(sock->tlsstream.tls, rv);
}
/* Only after doing the IO we can check if SSL handshake is done */
if (sock->tlsstream.state == TLS_HANDSHAKE &&
SSL_is_init_finished(sock->tlsstream.ssl) == 1)
SSL_is_init_finished(sock->tlsstream.tls) == 1)
{
isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL);
if (sock->tlsstream.server) {
@@ -252,9 +348,7 @@ tls_do_bio(isc_nmsocket_t *sock) {
ISC_R_SUCCESS,
sock->listener->accept_cbarg);
} else {
sock->connect_cb(tlshandle, ISC_R_SUCCESS,
sock->connect_cbarg);
update_result(tlshandle->sock, ISC_R_SUCCESS);
tls_call_connect_cb(sock, tlshandle, ISC_R_SUCCESS);
}
isc_nmhandle_detach(&tlshandle);
sock->tlsstream.state = TLS_IO;
@@ -263,8 +357,14 @@ tls_do_bio(isc_nmsocket_t *sock) {
}
switch (tls_err) {
case 0:
case SSL_ERROR_NONE:
if (sent_shutdown && received_shutdown) {
/* clean shutdown */
isc_nm_cancelread(sock->outerhandle);
isc__nm_tls_close(sock);
};
return;
break;
case SSL_ERROR_WANT_WRITE:
if (sock->tlsstream.nsending == 0) {
/*
@@ -272,83 +372,30 @@ tls_do_bio(isc_nmsocket_t *sock) {
* already the send callback will call it.
*/
async_tls_do_bio(sock);
return;
} else {
return;
}
break;
case SSL_ERROR_WANT_READ:
if (sock->outerhandle != NULL) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nm_resumeread(sock->outerhandle);
}
return;
break;
default:
result = tls_error_to_result(tls_err);
goto error;
}
while ((req = ISC_LIST_HEAD(sock->tlsstream.sends)) != NULL) {
INSIST(VALID_UVREQ(req));
rv = SSL_write(sock->tlsstream.ssl, req->uvbuf.base,
req->uvbuf.len);
if (rv < 0) {
if (sock->tlsstream.nsending == 0) {
async_tls_do_bio(sock);
}
return;
}
if (rv != (int)req->uvbuf.len) {
if (!sock->tlsstream.server &&
(sock->tlsstream.state == TLS_HANDSHAKE ||
TLS_INIT))
{
isc_nmhandle_t *tlshandle =
isc__nmhandle_get(sock, NULL, NULL);
sock->connect_cb(tlshandle, result,
sock->connect_cbarg);
update_result(tlshandle->sock, result);
isc_nmhandle_detach(&tlshandle);
}
sock->tlsstream.state = TLS_ERROR;
async_tls_do_bio(sock);
return;
}
ISC_LIST_UNLINK(sock->tlsstream.sends, req, link);
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
isc__nm_uvreq_put(&req, sock);
}
return;
error:
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "SSL error in BIO: %d %s", tls_err,
isc_result_totext(result));
low_level_error:
if (sock->tlsstream.state == TLS_HANDSHAKE) {
isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL);
if (!sock->tlsstream.server) {
sock->connect_cb(tlshandle, result,
sock->connect_cbarg);
update_result(tlshandle->sock, result);
}
isc_nmhandle_detach(&tlshandle);
} else if (sock->tlsstream.state == TLS_IO) {
if (ISC_LIST_HEAD(sock->tlsstream.sends) != NULL) {
while ((req = ISC_LIST_HEAD(sock->tlsstream.sends)) !=
NULL) {
req->cb.send(sock->statichandle, result,
req->cbarg);
ISC_LIST_UNLINK(sock->tlsstream.sends, req,
link);
isc__nm_uvreq_put(&req, sock);
}
} else if (sock->recv_cb != NULL) {
tls_failed_read_cb(sock, sock->statichandle, result,
false);
} else {
tls_close_direct(sock);
}
}
sock->tlsstream.state = TLS_ERROR;
tls_failed_read_cb(sock, sock->statichandle, result);
}
static void
@@ -361,18 +408,18 @@ tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(tlssock->tid == isc_nm_tid());
if (result != ISC_R_SUCCESS) {
tls_failed_read_cb(tlssock, tlssock->statichandle, result,
true);
tls_failed_read_cb(tlssock, tlssock->statichandle, result);
return;
}
rv = BIO_write(tlssock->tlsstream.app_bio, region->base,
region->length);
if (rv != (int)region->length) {
/* XXXWPK log it? */
tlssock->tlsstream.state = TLS_ERROR;
tls_failed_read_cb(tlssock, tlssock->statichandle,
ISC_R_TLSERROR);
return;
}
tls_do_bio(tlssock);
tls_do_bio(tlssock, NULL, false);
}
static isc_result_t
@@ -382,20 +429,20 @@ initialize_tls(isc_nmsocket_t *sock, bool server) {
if (BIO_new_bio_pair(&(sock->tlsstream.ssl_bio), TLS_BUF_SIZE,
&(sock->tlsstream.app_bio), TLS_BUF_SIZE) != 1)
{
SSL_free(sock->tlsstream.ssl);
isc_tls_free(&sock->tlsstream.tls);
return (ISC_R_TLSERROR);
}
SSL_set_bio(sock->tlsstream.ssl, sock->tlsstream.ssl_bio,
SSL_set_bio(sock->tlsstream.tls, sock->tlsstream.ssl_bio,
sock->tlsstream.ssl_bio);
if (server) {
SSL_set_accept_state(sock->tlsstream.ssl);
SSL_set_accept_state(sock->tlsstream.tls);
} else {
SSL_set_connect_state(sock->tlsstream.ssl);
SSL_set_connect_state(sock->tlsstream.tls);
}
sock->tlsstream.nsending = 0;
isc_nm_read(sock->outerhandle, tls_readcb, sock);
tls_do_bio(sock);
tls_do_bio(sock, NULL, false);
return (ISC_R_SUCCESS);
}
@@ -403,7 +450,6 @@ static isc_result_t
tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *tlssock = NULL;
int r;
/* If accept() was unsuccessful we can't do anything */
if (result != ISC_R_SUCCESS) {
@@ -420,14 +466,12 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
*/
tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock));
isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket,
handle->sock->iface);
&tlslistensock->tlsstream.server_iface);
/* We need to initialize SSL now to reference SSL_CTX properly */
tlssock->tlsstream.ctx = tlslistensock->tlsstream.ctx;
tlssock->tlsstream.ssl = SSL_new(tlssock->tlsstream.ctx);
ISC_LIST_INIT(tlssock->tlsstream.sends);
if (tlssock->tlsstream.ssl == NULL) {
update_result(tlssock, ISC_R_TLSERROR);
tlssock->tlsstream.tls = isc_tls_create(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.tls == NULL) {
atomic_store(&tlssock->closed, true);
isc__nmsocket_detach(&tlssock);
return (ISC_R_TLSERROR);
@@ -442,12 +486,6 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
tlssock->tlsstream.server = true;
tlssock->tlsstream.state = TLS_INIT;
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
tlssock->timer.data = tlssock;
tlssock->timer_initialized = true;
tlssock->tlsstream.ctx = tlslistensock->tlsstream.ctx;
result = initialize_tls(tlssock, true);
@@ -469,12 +507,15 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
REQUIRE(VALID_NM(mgr));
isc__nmsocket_init(tlssock, mgr, isc_nm_tlslistener, iface);
tlssock->tlsstream.server_iface = *iface;
ISC_LINK_INIT(&tlssock->tlsstream.server_iface.addr, link);
tlssock->iface = &tlssock->tlsstream.server_iface;
tlssock->result = ISC_R_DEFAULT;
tlssock->accept_cb = accept_cb;
tlssock->accept_cbarg = accept_cbarg;
tlssock->extrahandlesize = extrahandlesize;
tlssock->tlsstream.ctx = sslctx;
tlssock->tlsstream.ssl = NULL;
tlssock->tlsstream.tls = NULL;
/*
* tlssock will be a TLS 'wrapper' around an unencrypted stream.
@@ -515,46 +556,25 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
void
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0) {
int rv;
isc__netievent_tlssend_t *ievent = (isc__netievent_tlssend_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc__nm_uvreq_t *req = ievent->req;
ievent->req = NULL;
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
ievent->req = NULL;
if (inactive(sock)) {
req->cb.send(req->handle, ISC_R_CANCELED, req->cbarg);
isc__nm_uvreq_put(&req, sock);
return;
}
if (!ISC_LIST_EMPTY(sock->tlsstream.sends)) {
/* We're not the first */
ISC_LIST_APPEND(sock->tlsstream.sends, req, link);
tls_do_bio(sock);
return;
}
rv = SSL_write(sock->tlsstream.ssl, req->uvbuf.base, req->uvbuf.len);
if (rv < 0) {
/*
* We might need to read, we might need to write, or the
* TLS socket might be dead - in any case, we need to
* enqueue the uvreq and let the TLS BIO layer do the rest.
*/
ISC_LIST_APPEND(sock->tlsstream.sends, req, link);
tls_do_bio(sock);
return;
}
if (rv != (int)req->uvbuf.len) {
sock->tlsstream.state = TLS_ERROR;
async_tls_do_bio(sock);
return;
}
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
tls_do_bio(sock, req, false);
isc__nm_uvreq_put(&req, sock);
tls_do_bio(sock);
return;
}
@@ -600,20 +620,24 @@ isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tls_do_bio(sock);
tls_do_bio(sock, NULL, false);
}
void
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->statichandle == handle);
REQUIRE(handle->sock->tid == isc_nm_tid());
isc__netievent_tlsstartread_t *ievent = NULL;
isc_nmsocket_t *sock = handle->sock;
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->statichandle == handle);
REQUIRE(sock->tid == isc_nm_tid());
if (inactive(sock)) {
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
@@ -632,56 +656,26 @@ void
isc__nm_tls_pauseread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
atomic_store(&sock->readpaused, true);
atomic_store(&handle->sock->readpaused, true);
if (handle->sock->outerhandle != NULL) {
isc_nm_pauseread(handle->sock->outerhandle);
}
}
void
isc__nm_tls_resumeread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
atomic_store(&sock->readpaused, false);
async_tls_do_bio(sock);
}
static void
timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
tls_close_direct(sock);
atomic_store(&handle->sock->readpaused, false);
async_tls_do_bio(handle->sock);
}
static void
tls_close_direct(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
/* if (!sock->tlsstream.server) { */
/* INSIST(sock->tlsstream.state != TLS_HANDSHAKE && */
/* sock->tlsstream.state != TLS_INIT); */
/* } */
sock->tlsstream.state = TLS_CLOSING;
if (sock->timer_running) {
uv_timer_stop(&sock->timer);
sock->timer_running = false;
}
/* We don't need atomics here, it's all in single network thread
*/
if (sock->timer_initialized) {
/*
* We need to fire the timer callback to clean it up,
* it will then call us again (via detach) so that we
* can finally close the socket.
*/
sock->timer_initialized = false;
uv_timer_stop(&sock->timer);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
} else {
/*
* At this point we're certain that there are no
* external references, we can close everything.
@@ -690,28 +684,21 @@ tls_close_direct(isc_nmsocket_t *sock) {
isc_nm_pauseread(sock->outerhandle);
isc_nmhandle_detach(&sock->outerhandle);
}
if (sock->listener != NULL) {
isc__nmsocket_detach(&sock->listener);
}
if (sock->tlsstream.ssl != NULL) {
SSL_free(sock->tlsstream.ssl);
sock->tlsstream.ssl = NULL;
/* These are destroyed when we free SSL* */
sock->tlsstream.ctx = NULL;
sock->tlsstream.ssl_bio = NULL;
}
if (sock->tlsstream.app_bio != NULL) {
BIO_free(sock->tlsstream.app_bio);
sock->tlsstream.app_bio = NULL;
}
sock->tlsstream.state = TLS_CLOSED;
/* further cleanup performed in isc__nm_tls_cleanup_data() */
atomic_store(&sock->active, false);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
}
sock->tlsstream.state = TLS_CLOSED;
}
void
isc__nm_tls_close(isc_nmsocket_t *sock) {
isc__netievent_tlsclose_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tlssocket);
@@ -720,24 +707,21 @@ isc__nm_tls_close(isc_nmsocket_t *sock) {
return;
}
if (sock->tid == isc_nm_tid()) {
tls_close_direct(sock);
} else {
isc__netievent_tlsclose_t *ievent =
isc__nm_get_netievent_tlsclose(sock->mgr, sock);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
ievent = isc__nm_get_netievent_tlsclose(sock->mgr, sock);
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tlsclose_t *ievent = (isc__netievent_tlsclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(ievent->sock->tid == isc_nm_tid());
UNUSED(worker);
tls_close_direct(ievent->sock);
tls_close_direct(sock);
}
void
@@ -749,9 +733,8 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
atomic_store(&sock->closed, true);
sock->recv_cb = NULL;
sock->recv_cbarg = NULL;
if (sock->tlsstream.ssl != NULL) {
SSL_free(sock->tlsstream.ssl);
sock->tlsstream.ssl = NULL;
if (sock->tlsstream.tls != NULL) {
isc_tls_free(&sock->tlsstream.tls);
sock->tlsstream.ctx = NULL;
}
@@ -773,6 +756,9 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local);
nsock->tlsstream.local_iface = *local;
ISC_LINK_INIT(&nsock->tlsstream.local_iface.addr, link);
nsock->iface = &nsock->tlsstream.local_iface;
nsock->extrahandlesize = extrahandlesize;
nsock->result = ISC_R_DEFAULT;
nsock->connect_cb = cb;
@@ -815,29 +801,31 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
}
static void
tls_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
isc_nmhandle_t *tlshandle = NULL;
REQUIRE(VALID_NMSOCK(tlssock));
REQUIRE(VALID_NMHANDLE(handle));
if (result != ISC_R_SUCCESS) {
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
update_result(tlssock, result);
tls_close_direct(tlssock);
return;
goto error;
}
INSIST(VALID_NMHANDLE(handle));
tlssock->peer = isc_nmhandle_peeraddr(handle);
isc_nmhandle_attach(handle, &tlssock->outerhandle);
result = initialize_tls(tlssock, false);
if (result != ISC_R_SUCCESS) {
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
update_result(tlssock, result);
tls_close_direct(tlssock);
return;
goto error;
}
return;
error:
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
atomic_store(&tlssock->closed, true);
tls_call_connect_cb(tlssock, tlshandle, result);
isc_nmhandle_detach(&tlshandle);
isc__nmsocket_detach(&tlssock);
}
void
@@ -846,7 +834,6 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
(isc__netievent_tlsconnect_t *)ev0;
isc_nmsocket_t *tlssock = ievent->sock;
isc_result_t result;
int r;
isc_nmhandle_t *tlshandle = NULL;
UNUSED(worker);
@@ -854,36 +841,36 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
/*
* We need to initialize SSL now to reference SSL_CTX properly.
*/
tlssock->tlsstream.ssl = SSL_new(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.ssl == NULL) {
tlssock->tlsstream.tls = isc_tls_create(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.tls == NULL) {
result = ISC_R_TLSERROR;
update_result(tlssock, result);
goto error;
}
tlssock->tid = isc_nm_tid();
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
tlssock->timer.data = tlssock;
tlssock->timer_initialized = true;
tlssock->tlsstream.state = TLS_INIT;
result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
(isc_nmiface_t *)&ievent->peer,
tls_connect_cb, tlssock,
tlssock->connect_timeout, 0);
if (result != ISC_R_SUCCESS) {
goto error;
}
(void)isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
(isc_nmiface_t *)&ievent->peer, tcp_connected,
tlssock, tlssock->connect_timeout, 0);
return;
error:
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
atomic_store(&tlssock->closed, true);
tlssock->connect_cb(tlshandle, result, tlssock->connect_cbarg);
tls_call_connect_cb(tlssock, tlshandle, result);
isc_nmhandle_detach(&tlshandle);
update_result(tlssock, result);
tls_close_direct(tlssock);
isc__nmsocket_detach(&tlssock);
}
static void
tls_cancelread(isc_nmsocket_t *sock) {
if (!inactive(sock) && sock->tlsstream.state == TLS_IO) {
tls_do_bio(sock, NULL, true);
} else if (sock->outerhandle != NULL) {
isc_nm_cancelread(sock->outerhandle);
}
}
void
@@ -897,40 +884,69 @@ isc__nm_tls_cancelread(isc_nmhandle_t *handle) {
REQUIRE(sock->type == isc_nm_tlssocket);
ievent = isc__nm_get_netievent_tlscancel(sock->mgr, sock, handle);
if (sock->tid == isc_nm_tid()) {
tls_cancelread(sock);
} else {
ievent = isc__nm_get_netievent_tlscancel(sock->mgr, sock,
handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_async_tlscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tlscancel_t *ievent = (isc__netievent_tlscancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = ievent->handle;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tls_failed_read_cb(sock, handle, ISC_R_EOF, false);
if (sock->outerhandle) {
isc__nm_tcp_cancelread(sock->outerhandle);
}
tls_cancelread(sock);
}
void
isc__nm_async_tlsdobio(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
isc__netievent_tlsdobio_t *ievent = (isc__netievent_tlsdobio_t *)ev0;
tls_do_bio(ievent->sock);
UNUSED(worker);
tls_do_bio(ievent->sock, NULL, false);
}
void
isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
if (sock->tlsstream.tlslistener) {
if (sock->type == isc_nm_tcplistener &&
sock->tlsstream.tlslistener != NULL) {
REQUIRE(VALID_NMSOCK(sock->tlsstream.tlslistener));
isc__nmsocket_detach(&sock->tlsstream.tlslistener);
} else if (sock->type == isc_nm_tlssocket) {
if (sock->tlsstream.tls != NULL) {
isc_tls_free(&sock->tlsstream.tls);
/* These are destroyed when we free SSL */
sock->tlsstream.ctx = NULL;
sock->tlsstream.ssl_bio = NULL;
}
if (sock->tlsstream.app_bio != NULL) {
BIO_free(sock->tlsstream.app_bio);
sock->tlsstream.app_bio = NULL;
}
}
}
void
isc__nm_tls_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type == isc_nm_tlssocket);
sock = handle->sock;
if (sock->outerhandle != NULL) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nmhandle_settimeout(sock->outerhandle, timeout);
}
}

View File

@@ -102,10 +102,10 @@ static const char *description[ISC_R_NRESULTS] = {
"default", /*%< 68 */
"IPv4 prefix", /*%< 69 */
"TLS error", /*%< 70 */
"ALPN for HTTP/2 failed" /*%< 71 */
};
static const char *identifier[ISC_R_NRESULTS] = {
"ISC_R_SUCCESS",
static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_SUCCESS",
"ISC_R_NOMEMORY",
"ISC_R_TIMEDOUT",
"ISC_R_NOTHREADS",
@@ -176,7 +176,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
"ISC_R_DEFAULT",
"ISC_R_IPV4PREFIX",
"ISC_R_TLSERROR",
};
"ISC_R_HTTP2ALPNERROR" };
#define ISC_RESULT_RESULTSET 2
#define ISC_RESULT_UNAVAILABLESET 3

View File

@@ -72,7 +72,8 @@ static bool reuse_supported = true;
static atomic_bool POST = ATOMIC_VAR_INIT(true);
static atomic_bool use_TLS = ATOMIC_VAR_INIT(false);
static SSL_CTX *server_ssl_ctx = NULL;
static isc_tlsctx_t *server_tlsctx = NULL;
static isc_tlsctx_t *client_tlsctx = NULL;
#define NSENDS 100
#define NWRITES 10
@@ -101,6 +102,63 @@ static SSL_CTX *server_ssl_ctx = NULL;
#define X(v)
#endif
typedef struct csdata {
isc_nm_recv_cb_t reply_cb;
void *cb_arg;
isc_region_t region;
} csdata_t;
static void
connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
csdata_t data;
REQUIRE(VALID_NMHANDLE(handle));
memmove(&data, arg, sizeof(data));
isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data));
if (result != ISC_R_SUCCESS) {
goto error;
}
result = isc__nm_http_request(handle, &data.region, data.reply_cb,
data.cb_arg);
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_mem_put(handle->sock->mgr->mctx, data.region.base,
data.region.length);
return;
error:
data.reply_cb(handle, result, NULL, data.cb_arg);
isc_mem_put(handle->sock->mgr->mctx, data.region.base,
data.region.length);
}
static isc_result_t
connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg,
bool tls, unsigned int timeout) {
isc_result_t result;
isc_region_t copy;
csdata_t *data = NULL;
isc_tlsctx_t *ctx = NULL;
copy = (isc_region_t){ .base = isc_mem_get(mgr->mctx, region->length),
.length = region->length };
memmove(copy.base, region->base, region->length);
data = isc_mem_get(mgr->mctx, sizeof(*data));
*data = (csdata_t){ .reply_cb = cb, .cb_arg = cbarg, .region = copy };
if (tls) {
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri, post,
connect_send_cb, data, ctx, timeout, 0);
return (result);
}
static int
setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
isc_result_t result;
@@ -171,7 +229,7 @@ static int
_setup(void **state) {
UNUSED(state);
/*workers = isc_os_ncpus();*/
workers = isc_os_ncpus();
if (isc_test_begin(NULL, false, workers) != ISC_R_SUCCESS) {
return (-1);
@@ -243,8 +301,11 @@ nm_setup(void **state) {
assert_non_null(nm[i]);
}
server_ssl_ctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &server_ssl_ctx);
server_tlsctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &server_tlsctx);
client_tlsctx = NULL;
isc_tlsctx_createclient(&client_tlsctx);
isc_tlsctx_enable_http2client_alpn(client_tlsctx);
*state = nm;
@@ -261,8 +322,11 @@ nm_teardown(void **state) {
}
isc_mem_put(test_mctx, nm, MAX_NM * sizeof(nm[0]));
if (server_ssl_ctx) {
isc_tlsctx_free(&server_ssl_ctx);
if (server_tlsctx != NULL) {
isc_tlsctx_free(&server_tlsctx);
}
if (client_tlsctx != NULL) {
isc_tlsctx_free(&client_tlsctx);
}
return (0);
@@ -276,6 +340,7 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
uint16_t port;
char saddr[INET6_ADDRSTRLEN] = { 0 };
int family;
if (sa == NULL || outbuf == NULL || outbuf_len == 0) {
return;
}
@@ -321,8 +386,6 @@ doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
}
}
atomic_store(&was_error, true);
/* Send failed, we need to stop reading too */
isc_nm_cancelread(handle);
}
}
@@ -382,10 +445,6 @@ mock_doh_uv_tcp_bind(void **state) {
isc_nm_t *listen_nm = nm[0];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
WILL_RETURN(uv_tcp_bind, UV_EADDRINUSE);
@@ -404,17 +463,13 @@ doh_noop(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(listen_nm, (isc_nmiface_t *)&tcp_listen_addr,
0, NULL, NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
noop_read_cb, NULL, 0);
result = isc_nm_http_endpoint(listen_sock, DOH_PATH, noop_read_cb, NULL,
0);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@@ -422,11 +477,11 @@ doh_noop(void **state) {
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, NULL, 30000);
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_closedown(connect_nm);
@@ -455,27 +510,23 @@ doh_noresponse(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(listen_nm, (isc_nmiface_t *)&tcp_listen_addr,
0, NULL, NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
noop_read_cb, NULL, 0);
result = isc_nm_http_endpoint(listen_sock, DOH_PATH, noop_read_cb, NULL,
0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, NULL, 30000);
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@@ -509,7 +560,7 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
size_t i;
atomic_fetch_sub(&nsends, 1);
for (i = 0; i < NWRITES / 2; i++) {
eresult = isc_nm_httprequest(
eresult = isc__nm_http_request(
handle,
&(isc_region_t){
.base = (uint8_t *)send_msg.base,
@@ -535,20 +586,18 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
static isc_threadresult_t
doh_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
while (atomic_load(&nsends) > 0) {
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_send_reply_cb, NULL, NULL, 5000);
doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS),
30000);
}
return ((isc_threadresult_t)0);
@@ -561,33 +610,26 @@ doh_recv_one(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 1);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
result = isc_nm_http_connect_send_request(
result = connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_reply_cb, NULL, NULL, 5000);
doh_receive_reply_cb, NULL, atomic_load(&use_TLS), 30000);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -657,7 +699,7 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
goto error;
}
result = isc_nm_httprequest(
result = isc__nm_http_request(
handle,
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
@@ -666,7 +708,7 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
goto error;
}
result = isc_nm_httprequest(
result = isc__nm_http_request(
handle,
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
@@ -674,8 +716,6 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_nm_resumeread(handle);
return;
error:
atomic_store(&was_error, true);
@@ -688,31 +728,31 @@ doh_recv_two(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
isc_tlsctx_t *ctx = NULL;
atomic_store(&nsends, 2);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
if (atomic_load(&use_TLS)) {
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
connect_nm, NULL, NULL, req_url, atomic_load(&POST),
doh_connect_send_two_requests_cb, NULL, NULL, 5000, 0);
connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr, req_url,
atomic_load(&POST), doh_connect_send_two_requests_cb, NULL, ctx,
5000, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -783,20 +823,13 @@ doh_recv_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -859,20 +892,13 @@ doh_recv_half_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -940,20 +966,13 @@ doh_half_recv_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -1021,20 +1040,13 @@ doh_half_recv_half_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -1105,7 +1117,7 @@ doh_parse_GET_query_string(void **state) {
"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1122,7 +1134,7 @@ doh_parse_GET_query_string(void **state) {
"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1136,7 +1148,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123&dns=567";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1150,7 +1162,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?name1=123&dns=567&name2=123&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1167,7 +1179,7 @@ doh_parse_GET_query_string(void **state) {
"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
"D0%BD%D0%BD%D1%8F&dns=123&veaction=edit&section=0";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1184,7 +1196,7 @@ doh_parse_GET_query_string(void **state) {
"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
"D0%BD%D0%BD%D1%8F&veaction=edit&section=0";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1196,7 +1208,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1208,7 +1220,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1220,7 +1232,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1232,7 +1244,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1244,7 +1256,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123&&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1256,7 +1268,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%12&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1270,7 +1282,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%ZZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1282,7 +1294,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%%&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1294,7 +1306,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%AZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@@ -1306,7 +1318,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%0AZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@@ -1593,66 +1605,6 @@ doh_base64_to_base64url(void **state) {
}
}
/*
static char wikipedia_org_A[] = { 0xae, 0x35, 0x01, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x77,
0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69,
0x61, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
0x01, 0x00, 0x01 };
static void
doh_print_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
assert_non_null(handle);
UNUSED(cbarg);
UNUSED(region);
puts("Cloudflare DNS query result:");
if (eresult == ISC_R_SUCCESS) {
puts("success!");
printf("Response size: %lu\n", region->length);
atomic_fetch_add(&creads, 1);
isc_nm_resumeread(handle);
} else {
puts("failure!");
atomic_store(&was_error, true);
isc_nm_cancelread(handle);
}
}
static void
doh_cloudflare(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_result_t result = ISC_R_SUCCESS;
result = isc_nm_http_connect_send_request(
nm[0], "https://cloudflare-dns.com/dns-query",
atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)wikipedia_org_A,
.length = sizeof(wikipedia_org_A) },
doh_print_reply_cb, NULL, NULL, 5000);
assert_int_equal(result, ISC_R_SUCCESS);
while (atomic_load(&creads) != 1 && atomic_load(&was_error) == false) {
isc_thread_yield();
}
isc_nm_closedown(nm[0]);
}
static void
doh_cloudflare_POST(void **state) {
atomic_store(&POST, true);
doh_cloudflare(state);
}
static void
doh_cloudflare_GET(void **state) {
atomic_store(&POST, false);
doh_cloudflare(state);
}
*/
int
main(void) {
const struct CMUnitTest tests_short[] = {
@@ -1745,17 +1697,21 @@ main(void) {
cmocka_unit_test_setup_teardown(doh_cloudflare_POST, nm_setup,
nm_teardown)*/
};
int result = 0;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
UNUSED(tests_long);
return (cmocka_run_group_tests(tests_short, _setup, _teardown));
result = (cmocka_run_group_tests(tests_short, _setup, _teardown));
#else
if (getenv("CI") != NULL || !reuse_supported) {
return (cmocka_run_group_tests(tests_short, _setup, _teardown));
result = (cmocka_run_group_tests(tests_short, _setup,
_teardown));
} else {
return (cmocka_run_group_tests(tests_long, _setup, _teardown));
result =
(cmocka_run_group_tests(tests_long, _setup, _teardown));
}
#endif
return result;
}
#else /* HAVE_CMOCKA */

View File

@@ -9,6 +9,9 @@
* information regarding copyright ownership.
*/
#include <inttypes.h>
#include <nghttp2/nghttp2.h>
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
@@ -220,14 +223,7 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile,
const SSL_METHOD *method = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
if (ephemeral) {
INSIST(keyfile == NULL);
INSIST(certfile == NULL);
} else {
INSIST(keyfile != NULL);
INSIST(certfile != NULL);
}
REQUIRE((keyfile == NULL) == (certfile == NULL));
method = TLS_server_method();
if (method == NULL) {
@@ -355,3 +351,123 @@ ssl_error:
return (ISC_R_TLSERROR);
}
isc_tls_t *
isc_tls_create(isc_tlsctx_t *ctx) {
isc_tls_t *newctx = NULL;
REQUIRE(ctx != NULL);
newctx = SSL_new(ctx);
if (newctx == NULL) {
char errbuf[256];
unsigned long err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
fprintf(stderr, "%s:SSL_new(%p) -> %s\n", __func__, ctx,
errbuf);
}
return (newctx);
}
void
isc_tls_free(isc_tls_t **tlsp) {
REQUIRE(tlsp != NULL && *tlsp != NULL);
SSL_free(*tlsp);
*tlsp = NULL;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
/*
* NPN TLS extension client callback.
*/
static int
select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) {
UNUSED(ssl);
UNUSED(arg);
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
return (SSL_TLSEXT_ERR_NOACK);
}
return (SSL_TLSEXT_ERR_OK);
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
void
isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx) {
REQUIRE(ctx != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)NGHTTP2_PROTO_ALPN,
NGHTTP2_PROTO_ALPN_LEN);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
#ifndef OPENSSL_NO_NEXTPROTONEG
static int
next_proto_cb(isc_tls_t *ssl, const unsigned char **data, unsigned int *len,
void *arg) {
UNUSED(ssl);
UNUSED(arg);
*data = (const unsigned char *)NGHTTP2_PROTO_ALPN;
*len = (unsigned int)NGHTTP2_PROTO_ALPN_LEN;
return (SSL_TLSEXT_ERR_OK);
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int
alpn_select_proto_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) {
int ret;
UNUSED(ssl);
UNUSED(arg);
ret = nghttp2_select_next_protocol((unsigned char **)(uintptr_t)out,
outlen, in, inlen);
if (ret != 1) {
return (SSL_TLSEXT_ERR_NOACK);
}
return (SSL_TLSEXT_ERR_OK);
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
void
isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *tls) {
REQUIRE(tls != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb(tls, next_proto_cb, NULL);
#endif // OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_select_cb(tls, alpn_select_proto_cb, NULL);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
}
void
isc_tls_get_http2_alpn(isc_tls_t *tls, const unsigned char **alpn,
unsigned int *alpnlen) {
REQUIRE(tls != NULL);
REQUIRE(alpn != NULL);
REQUIRE(alpnlen != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(tls, alpn, alpnlen);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (*alpn == NULL) {
SSL_get0_alpn_selected(tls, alpn, alpnlen);
}
#endif
}

View File

@@ -452,11 +452,8 @@ isc_nm_cancelread
isc_nm_closedown
isc_nm_destroy
isc_nm_detach
isc_nm_http_add_doh_endpoint
isc_nm_http_add_endpoint
isc_nm_http_connect_send_request
isc_nm_http_endpoint
isc_nm_httpconnect
isc_nm_httprequest
isc_nm_listenhttp
isc_nm_listentcpdns
isc_nm_listentls
@@ -710,17 +707,20 @@ isc_timermgr_create
isc_timermgr_createinctx
isc_timermgr_destroy
isc_timermgr_poke
isc__tls_initialize
isc__tls_shutdown
isc_tls_get_http2_alpn
isc_tls_create
isc_tls_free
isc_tlsctx_createclient
isc_tlsctx_createserver
isc_tlsctx_free
isc_tlsctx_enable_http2client_alpn
isc_tlsctx_enable_http2server_alpn
isc_tm_timegm
isc_tm_strptime
isc__trampoline_initialize
isc__trampoline_shutdown
isc__trampoline_get
isc__trampoline_run
isc_tm_timegm
isc_tm_strptime
isc_url_parse
isc_utf8_bom
isc_utf8_valid

View File

@@ -556,8 +556,8 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
if (result == ISC_R_SUCCESS) {
for (i = 0; i < neps; i++) {
result = isc_nm_http_add_doh_endpoint(
sock, eps[i], ns__client_request, ifp,
result = isc_nm_http_endpoint(sock, eps[i],
ns__client_request, ifp,
sizeof(ns_client_t));
}
}