2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-05 09:05:40 +00:00

Initial support for DNS-over-HTTP(S)

This commit completes the support for DNS-over-HTTP(S) built on top of
nghttp2 and plugs it into the BIND. Support for both GET and POST
requests is present, as required by RFC8484.

Both encrypted (via TLS) and unencrypted HTTP/2 connections are
supported. The latter are mostly there for debugging/troubleshooting
purposes and for the means of encryption offloading to third-party
software (as might be desirable in some environments to simplify TLS
certificates management).
This commit is contained in:
Artem Boldariev
2020-12-07 14:19:10 +02:00
committed by Ondřej Surý
parent 7a96081360
commit 08da09bc76
25 changed files with 4734 additions and 428 deletions

View File

@@ -80,6 +80,8 @@ struct ns_interface {
isc_socket_t * tcpsocket; /*%< TCP socket. */
isc_nmsocket_t *udplistensocket;
isc_nmsocket_t *tcplistensocket;
isc_nmsocket_t *http_listensocket;
isc_nmsocket_t *http_secure_listensocket;
isc_dscp_t dscp; /*%< "listen-on" DSCP value */
isc_refcount_t ntcpaccepting; /*%< Number of clients
* ready to accept new

View File

@@ -42,9 +42,12 @@ typedef struct ns_listenlist ns_listenlist_t;
struct ns_listenelt {
isc_mem_t * mctx;
in_port_t port;
bool is_http;
isc_dscp_t dscp; /* -1 = not set, 0..63 */
dns_acl_t * acl;
isc_tlsctx_t *sslctx;
char ** http_endpoints;
size_t http_endpoints_number;
ISC_LINK(ns_listenelt_t) link;
};
@@ -66,6 +69,15 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
* Create a listen-on list element.
*/
isc_result_t
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
dns_acl_t *acl, const char *key, const char *cert,
char **endpoints, size_t nendpoints,
ns_listenelt_t **target);
/*%<
* Create a listen-on list element for HTTP(S).
*/
void
ns_listenelt_destroy(ns_listenelt_t *elt);
/*%<

View File

@@ -437,6 +437,10 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
goto failure;
}
ifp->tcplistensocket = NULL;
ifp->http_listensocket = NULL;
ifp->http_secure_listensocket = NULL;
*ifpret = ifp;
return (ISC_R_SUCCESS);
@@ -539,6 +543,54 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
return (result);
}
static isc_result_t
ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
size_t neps) {
isc_result_t result;
isc_nmsocket_t *sock = NULL;
size_t i = 0;
result = isc_nm_listenhttp(ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr,
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota,
sslctx, &sock);
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,
sizeof(ns_client_t));
}
}
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"creating %s socket: %s",
sslctx ? "HTTPS" : "HTTP",
isc_result_totext(result));
return (result);
}
if (sslctx) {
ifp->http_secure_listensocket = sock;
} else {
ifp->http_listensocket = sock;
}
/*
* We call this now to update the tcp-highwater statistic:
* this is necessary because we are adding to the TCP quota just
* by listening.
*/
result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"updating TCP stats: %s",
isc_result_totext(result));
}
return (result);
}
static isc_result_t
ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
const char *name, ns_interface_t **ifpret, bool accept_tcp,
@@ -555,6 +607,17 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
ifp->dscp = elt->dscp;
if (elt->is_http) {
result = ns_interface_listenhttp(ifp, elt->sslctx,
elt->http_endpoints,
elt->http_endpoints_number);
if (result != ISC_R_SUCCESS) {
goto cleanup_interface;
}
*ifpret = ifp;
return (result);
}
if (elt->sslctx != NULL) {
result = ns_interface_listentls(ifp, elt->sslctx);
if (result != ISC_R_SUCCESS) {
@@ -611,6 +674,14 @@ ns_interface_shutdown(ns_interface_t *ifp) {
isc_nm_stoplistening(ifp->tcplistensocket);
isc_nmsocket_close(&ifp->tcplistensocket);
}
if (ifp->http_listensocket != NULL) {
isc_nm_stoplistening(ifp->http_listensocket);
isc_nmsocket_close(&ifp->http_listensocket);
}
if (ifp->http_secure_listensocket != NULL) {
isc_nm_stoplistening(ifp->http_secure_listensocket);
isc_nmsocket_close(&ifp->http_secure_listensocket);
}
if (ifp->clientmgr != NULL) {
ns_clientmgr_destroy(&ifp->clientmgr);
}

View File

@@ -30,24 +30,59 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
ns_listenelt_t **target) {
ns_listenelt_t *elt = NULL;
isc_result_t result = ISC_R_SUCCESS;
isc_tlsctx_t *sslctx = NULL;
REQUIRE(target != NULL && *target == NULL);
elt = isc_mem_get(mctx, sizeof(*elt));
elt->mctx = mctx;
ISC_LINK_INIT(elt, link);
elt->port = port;
elt->dscp = dscp;
elt->acl = acl;
elt->sslctx = NULL;
if (tls) {
result = isc_tlsctx_createserver(key, cert, &elt->sslctx);
result = isc_tlsctx_createserver(key, cert, &sslctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
elt = isc_mem_get(mctx, sizeof(*elt));
elt->mctx = mctx;
ISC_LINK_INIT(elt, link);
elt->port = port;
elt->is_http = false;
elt->dscp = dscp;
elt->acl = acl;
elt->sslctx = sslctx;
elt->http_endpoints = NULL;
elt->http_endpoints_number = 0;
*target = elt;
return (ISC_R_SUCCESS);
}
isc_result_t
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
dns_acl_t *acl, const char *key, const char *cert,
char **endpoints, size_t nendpoints,
ns_listenelt_t **target) {
isc_result_t result;
REQUIRE(target != NULL && *target == NULL);
REQUIRE(endpoints != NULL && *endpoints != NULL);
REQUIRE(nendpoints > 0);
result = ns_listenelt_create(mctx, http_port, dscp, acl, key != NULL,
key, cert, target);
if (result == ISC_R_SUCCESS) {
(*target)->is_http = true;
(*target)->http_endpoints = endpoints;
(*target)->http_endpoints_number = nendpoints;
} else {
size_t i;
for (i = 0; i < nendpoints; i++) {
isc_mem_free(mctx, endpoints[i]);
}
isc_mem_free(mctx, endpoints);
}
return (result);
}
void
ns_listenelt_destroy(ns_listenelt_t *elt) {
if (elt->acl != NULL) {
@@ -56,6 +91,14 @@ ns_listenelt_destroy(ns_listenelt_t *elt) {
if (elt->sslctx != NULL) {
isc_tlsctx_free(&elt->sslctx);
}
if (elt->http_endpoints != NULL) {
size_t i;
INSIST(elt->http_endpoints_number > 0);
for (i = 0; i < elt->http_endpoints_number; i++) {
isc_mem_free(elt->mctx, elt->http_endpoints[i]);
}
isc_mem_free(elt->mctx, elt->http_endpoints);
}
isc_mem_put(elt->mctx, elt, sizeof(*elt));
}

View File

@@ -66,6 +66,7 @@ ns_interfacemgr_shutdown
ns_lib_init
ns_lib_shutdown
ns_listenelt_create
ns_listenelt_create_http
ns_listenelt_destroy
ns_listenlist_attach
ns_listenlist_create