Add isc_nm_streamdnssocket (aka Stream DNS)

This commit adds an initial implementation of isc_nm_streamdnssocket
transport: a unified transport for DNS over stream protocols messages,
which is capable of replacing both TCP DNS and TLS DNS
transports. Currently, the interface it provides is a unified set of
interfaces provided by both of the transports it attempts to replace.

The transport is built around "isc_dnsbuffer_t" and
"isc_dnsstream_assembler_t" objects and attempts to minimise both the
number of memory allocations during network transfers as well as
memory usage.
This commit is contained in:
Artem Boldariev
2022-06-20 20:30:12 +03:00
parent ae63471e50
commit f395cd4b3e
6 changed files with 1388 additions and 2 deletions

View File

@@ -115,6 +115,7 @@ libisc_la_SOURCES = \
netmgr/netmgr-int.h \
netmgr/netmgr.c \
netmgr/socket.c \
netmgr/streamdns.c \
netmgr/tcp.c \
netmgr/tcpdns.c \
netmgr/timer.c \

View File

@@ -410,6 +410,13 @@ isc_nm_listentlsdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
* Same as isc_nm_listentcpdns but for an SSL (DoT) socket.
*/
isc_result_t
isc_nm_listenstreamdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
int backlog, isc_quota_t *quota, isc_tlsctx_t *sslctx,
isc_nmsocket_t **sockp);
void
isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
uint32_t keepalive, uint32_t advertised);
@@ -496,6 +503,11 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
isc_tlsctx_t *sslctx,
isc_tlsctx_client_session_cache_t *client_sess_cache);
void
isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local,
isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg,
unsigned int timeout, isc_tlsctx_t *sslctx,
isc_tlsctx_client_session_cache_t *client_sess_cache);
/*%<
* Establish a DNS client connection via a TCP or TLS connection, bound to
* the address 'local' and connected to the address 'peer'.

View File

@@ -110,6 +110,7 @@ typedef enum isc_nmsocket_type {
isc_nm_tlssocket = 1 << 4,
isc_nm_tlsdnssocket = 1 << 5,
isc_nm_httpsocket = 1 << 6,
isc_nm_streamdnssocket = 1 << 7,
isc_nm_maxsocket,
isc_nm_udplistener, /* Aggregate of nm_udpsocks */
@@ -117,7 +118,8 @@ typedef enum isc_nmsocket_type {
isc_nm_tlslistener,
isc_nm_tcpdnslistener,
isc_nm_tlsdnslistener,
isc_nm_httplistener
isc_nm_httplistener,
isc_nm_streamdnslistener
} isc_nmsocket_type;
typedef isc_nmsocket_type isc_nmsocket_type_t;

View File

@@ -23,6 +23,7 @@
#include <isc/barrier.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/dnsstream.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
@@ -281,6 +282,11 @@ typedef enum isc__netievent_type {
netievent_httpsend,
netievent_httpendpoints,
netievent_streamdnsclose,
netievent_streamdnssend,
netievent_streamdnsread,
netievent_streamdnscancel,
netievent_connectcb,
netievent_readcb,
netievent_sendcb,
@@ -922,6 +928,17 @@ struct isc_nmsocket {
isc_nmsocket_h2_t h2;
#endif /* HAVE_LIBNGHTTP2 */
struct {
isc_dnsstream_assembler_t *input;
bool reading;
isc_nmsocket_t *listener;
isc_nmsocket_t *sock;
size_t nsending;
void *send_req;
bool dot_alpn_negotiated;
const char *tls_verify_error;
} streamdns;
/*%
* quota is the TCP client, attached when a TCP connection
* is established. pquota is a non-attached pointer to the
@@ -1702,6 +1719,79 @@ isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
#endif
void
isc__nm_async_streamdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_streamdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
void *cbarg);
void
isc__nm_async_streamdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_streamdns_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_async_streamdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_streamdns_close(isc_nmsocket_t *sock);
void
isc__nm_streamdns_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_streamdns_cleanup_data(isc_nmsocket_t *sock);
void
isc__nm_async_streamdnscancel(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_streamdns_cancelread(isc_nmhandle_t *handle);
void
isc__nmhandle_streamdns_cleartimeout(isc_nmhandle_t *handle);
void
isc__nmhandle_streamdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
void
isc__nmhandle_streamdns_keepalive(isc_nmhandle_t *handle, bool value);
void
isc__nmhandle_streamdns_setwritetimeout(isc_nmhandle_t *handle,
uint32_t timeout);
bool
isc__nm_streamdns_has_encryption(const isc_nmhandle_t *handle);
const char *
isc__nm_streamdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle);
void
isc__nm_streamdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx);
bool
isc__nm_streamdns_xfr_allowed(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_reset(isc_nmsocket_t *sock);
bool
isc__nmsocket_streamdns_timer_running(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_timer_stop(isc_nmsocket_t *sock);
void
isc__nmsocket_streamdns_timer_restart(isc_nmsocket_t *sock);
void
isc__nm_streamdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
void
isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0);
@@ -1865,6 +1955,11 @@ NETIEVENT_SOCKET_HANDLE_TYPE(udpcancel);
NETIEVENT_SOCKET_QUOTA_TYPE(tcpaccept);
NETIEVENT_SOCKET_TYPE(streamdnsclose);
NETIEVENT_SOCKET_REQ_TYPE(streamdnssend);
NETIEVENT_SOCKET_TYPE(streamdnsread);
NETIEVENT_SOCKET_HANDLE_TYPE(streamdnscancel);
NETIEVENT_SOCKET_TLSCTX_TYPE(settlsctx);
NETIEVENT_SOCKET_TYPE(sockstop);
@@ -1915,6 +2010,11 @@ NETIEVENT_SOCKET_DECL(detach);
NETIEVENT_SOCKET_QUOTA_DECL(tcpaccept);
NETIEVENT_SOCKET_DECL(streamdnsclose);
NETIEVENT_SOCKET_REQ_DECL(streamdnssend);
NETIEVENT_SOCKET_DECL(streamdnsread);
NETIEVENT_SOCKET_HANDLE_DECL(streamdnscancel);
NETIEVENT_SOCKET_TLSCTX_DECL(settlsctx);
NETIEVENT_SOCKET_DECL(sockstop);

View File

@@ -354,6 +354,9 @@ isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) {
isc__nmhandle_tls_setwritetimeout(handle, write_timeout);
break;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_setwritetimeout(handle, write_timeout);
break;
default:
UNREACHABLE();
break;
@@ -480,6 +483,11 @@ process_netievent(void *arg) {
NETIEVENT_CASE(httpclose);
NETIEVENT_CASE(httpendpoints);
#endif
NETIEVENT_CASE(streamdnsread);
NETIEVENT_CASE(streamdnssend);
NETIEVENT_CASE(streamdnsclose);
NETIEVENT_CASE(streamdnscancel);
NETIEVENT_CASE(settlsctx);
NETIEVENT_CASE(sockstop);
@@ -556,6 +564,11 @@ NETIEVENT_SOCKET_DEF(detach);
NETIEVENT_SOCKET_QUOTA_DEF(tcpaccept);
NETIEVENT_SOCKET_DEF(streamdnsclose);
NETIEVENT_SOCKET_REQ_DEF(streamdnssend);
NETIEVENT_SOCKET_DEF(streamdnsread);
NETIEVENT_SOCKET_HANDLE_DEF(streamdnscancel);
NETIEVENT_SOCKET_TLSCTX_DEF(settlsctx);
NETIEVENT_SOCKET_DEF(sockstop);
@@ -715,6 +728,7 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
isc__nm_tls_cleanup_data(sock);
isc__nm_http_cleanup_data(sock);
#endif
isc__nm_streamdns_cleanup_data(sock);
if (sock->barrier_initialised) {
isc_barrier_destroy(&sock->barrier);
@@ -844,6 +858,9 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_close(sock);
return;
case isc_nm_streamdnssocket:
isc__nm_streamdns_close(sock);
return;
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
isc__nm_tls_close(sock);
@@ -896,6 +913,7 @@ isc_nmsocket_close(isc_nmsocket_t **sockp) {
(*sockp)->type == isc_nm_tcplistener ||
(*sockp)->type == isc_nm_tcpdnslistener ||
(*sockp)->type == isc_nm_tlsdnslistener ||
(*sockp)->type == isc_nm_streamdnslistener ||
(*sockp)->type == isc_nm_tlslistener ||
(*sockp)->type == isc_nm_httplistener);
@@ -1159,7 +1177,8 @@ isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
handle->sock->type == isc_nm_tcpdnssocket ||
handle->sock->type == isc_nm_tlssocket ||
handle->sock->type == isc_nm_tlsdnssocket ||
handle->sock->type == isc_nm_httpsocket);
handle->sock->type == isc_nm_httpsocket ||
handle->sock->type == isc_nm_streamdnssocket);
}
static void
@@ -1406,6 +1425,9 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) {
isc__nm_tls_failed_read_cb(sock, result, async);
return;
#endif
case isc_nm_streamdnssocket:
isc__nm_streamdns_failed_read_cb(sock, result, async);
return;
default:
UNREACHABLE();
}
@@ -1517,6 +1539,9 @@ isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
isc__nmsocket_tls_timer_restart(sock);
return;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_timer_restart(sock);
return;
default:
break;
}
@@ -1560,6 +1585,8 @@ isc__nmsocket_timer_running(isc_nmsocket_t *sock) {
case isc_nm_tlssocket:
return (isc__nmsocket_tls_timer_running(sock));
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
return (isc__nmsocket_streamdns_timer_running(sock));
default:
break;
}
@@ -1590,6 +1617,9 @@ isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
isc__nmsocket_tls_timer_stop(sock);
return;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_timer_stop(sock);
return;
default:
break;
}
@@ -1613,6 +1643,9 @@ isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) {
case isc_nm_tlssocket:
isc_nmhandle_attach(sock->statichandle, &req->handle);
break;
case isc_nm_streamdnssocket:
isc_nmhandle_attach(sock->recv_handle, &req->handle);
break;
default:
if (atomic_load(&sock->client) && sock->statichandle != NULL) {
isc_nmhandle_attach(sock->statichandle, &req->handle);
@@ -1842,6 +1875,9 @@ isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) {
isc__nm_tls_cleartimeout(handle);
return;
#endif
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_cleartimeout(handle);
return;
default:
handle->sock->read_timeout = 0;
@@ -1865,6 +1901,9 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
isc__nm_tls_settimeout(handle, timeout);
return;
#endif
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_settimeout(handle, timeout);
return;
default:
handle->sock->read_timeout = timeout;
isc__nmsocket_timer_restart(handle->sock);
@@ -1892,6 +1931,9 @@ isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) {
sock->write_timeout = value ? atomic_load(&netmgr->keepalive)
: atomic_load(&netmgr->idle);
break;
case isc_nm_streamdnssocket:
isc__nmhandle_streamdns_keepalive(handle, value);
break;
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
isc__nmhandle_tls_keepalive(handle, value);
@@ -2025,6 +2067,9 @@ 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_streamdnssocket:
isc__nm_streamdns_send(handle, region, cb, cbarg);
break;
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
isc__nm_tls_send(handle, region, cb, cbarg);
@@ -2055,6 +2100,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_streamdnssocket:
isc__nm_streamdns_read(handle, cb, cbarg);
break;
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
isc__nm_tls_read(handle, cb, cbarg);
@@ -2082,6 +2130,9 @@ isc_nm_cancelread(isc_nmhandle_t *handle) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_cancelread(handle);
break;
case isc_nm_streamdnssocket:
isc__nm_streamdns_cancelread(handle);
break;
default:
UNREACHABLE();
}
@@ -2124,6 +2175,9 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
case isc_nm_tlsdnslistener:
isc__nm_tlsdns_stoplistening(sock);
break;
case isc_nm_streamdnslistener:
isc__nm_streamdns_stoplistening(sock);
break;
#if HAVE_LIBNGHTTP2
case isc_nm_tlslistener:
isc__nm_tls_stoplistening(sock);
@@ -2364,6 +2418,9 @@ isc__nmsocket_reset(isc_nmsocket_t *sock) {
isc__nmsocket_tls_reset(sock);
return;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
isc__nmsocket_streamdns_reset(sock);
return;
default:
UNREACHABLE();
break;
@@ -2583,6 +2640,7 @@ isc_nm_bad_request(isc_nmhandle_t *handle) {
case isc_nm_tcpdnssocket:
case isc_nm_tlsdnssocket:
case isc_nm_tcpsocket:
case isc_nm_streamdnssocket:
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:
#endif /* HAVE_LIBNGHTTP2 */
@@ -2614,6 +2672,8 @@ isc_nm_xfr_allowed(isc_nmhandle_t *handle) {
return (true);
case isc_nm_tlsdnssocket:
return (isc__nm_tlsdns_xfr_allowed(sock));
case isc_nm_streamdnssocket:
return (isc__nm_streamdns_xfr_allowed(sock));
default:
return (false);
}
@@ -2653,6 +2713,7 @@ isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) {
case isc_nm_udpsocket:
case isc_nm_tcpdnssocket:
case isc_nm_tlsdnssocket:
case isc_nm_streamdnssocket:
return;
break;
@@ -2689,6 +2750,8 @@ isc_nm_has_encryption(const isc_nmhandle_t *handle) {
case isc_nm_httpsocket:
return (isc__nm_http_has_encryption(handle));
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
return (isc__nm_streamdns_has_encryption(handle));
default:
return (false);
};
@@ -2716,6 +2779,10 @@ isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
return (isc__nm_http_verify_tls_peer_result_string(handle));
break;
#endif /* HAVE_LIBNGHTTP2 */
case isc_nm_streamdnssocket:
return (isc__nm_streamdns_verify_tls_peer_result_string(
handle));
break;
default:
break;
}
@@ -2785,6 +2852,9 @@ isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
case isc_nm_tlsdnslistener:
set_tlsctx_workers(listener, tlsctx);
break;
case isc_nm_streamdnslistener:
isc__nm_streamdns_set_tlsctx(listener, tlsctx);
break;
default:
UNREACHABLE();
break;
@@ -2976,6 +3046,10 @@ nmsocket_type_totext(isc_nmsocket_type type) {
return ("isc_nm_httplistener");
case isc_nm_httpsocket:
return ("isc_nm_httpsocket");
case isc_nm_streamdnslistener:
return ("isc_nm_streamdnslistener");
case isc_nm_streamdnssocket:
return ("isc_nm_streamdnssocket");
default:
UNREACHABLE();
}

1197
lib/isc/netmgr/streamdns.c Normal file

File diff suppressed because it is too large Load Diff