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:
committed by
Ondřej Surý
parent
7a96081360
commit
08da09bc76
@@ -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
|
||||
|
@@ -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);
|
||||
/*%<
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user