mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-03 13:59:27 -04:00
Add (http-)listener-clients option (DoH quota mechanism)
This commit adds support for http-listener-clients global options as
well as ability to override the default in an HTTP server description,
like:
http local-http-server {
...
listener-clients 100;
...
};
This way we have ability to specify per-listener active connections
quota globally and then override it when required. This is exactly
what AT&T requested us: they wanted a functionality to specify quota
globally and then override it for specific IPs. This change
functionality makes such a configuration possible.
It makes sense: for example, one could have different quotas for
internal and external clients. Or, for example, one could use BIND's
internal ability to serve encrypted DoH with some sane quota value for
internal clients, while having un-encrypted DoH listener without quota
to put BIND behind a load balancer doing TLS offloading for external
clients.
Moreover, the code no more shares the quota with TCP, which makes
little sense anyway (see tcp-clients option), because of the nature of
interaction of DoH clients: they tend to keep idle opened connections
for longer periods of time, preventing the TCP and TLS client from
being served. Thus, the need to have a separate, generally larger,
quota for them.
Also, the change makes any option within "http <name> { ... };"
statement optional, making it easier to override only required default
options.
By default, the DoH connections are limited to 300 per listener. I
hope that it is a good initial guesstimate.
This commit is contained in:
parent
0aac2d094a
commit
03a557a9bb
14 changed files with 128 additions and 29 deletions
|
|
@ -93,6 +93,7 @@ options {\n\
|
|||
#if HAVE_LIBNGHTTP2
|
||||
"http-port 80;\n"
|
||||
"https-port 443;\n"
|
||||
"http-listener-clients 300;\n"
|
||||
#endif
|
||||
"\
|
||||
prefetch 2 9;\n\
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ EXTERN in_port_t named_g_httpsport INIT(0);
|
|||
EXTERN in_port_t named_g_httpport INIT(0);
|
||||
EXTERN isc_dscp_t named_g_dscp INIT(-1);
|
||||
|
||||
EXTERN in_port_t named_g_http_listener_clients INIT(0);
|
||||
|
||||
EXTERN named_server_t *named_g_server INIT(NULL);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -8629,6 +8629,11 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
result = named_config_get(maps, "https-port", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "http-listener-clients", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
named_g_http_listener_clients = cfg_obj_asuint32(obj);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -11326,6 +11331,9 @@ listenelt_http(const cfg_obj_t *http, bool tls, const char *key,
|
|||
const cfg_obj_t *eplist = NULL;
|
||||
const cfg_listelt_t *elt = NULL;
|
||||
size_t len = 1, i = 0;
|
||||
uint32_t max_clients = named_g_http_listener_clients;
|
||||
ns_server_t *server = NULL;
|
||||
isc_quota_t *quota = NULL;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
REQUIRE((key == NULL) == (cert == NULL));
|
||||
|
|
@ -11339,13 +11347,22 @@ listenelt_http(const cfg_obj_t *http, bool tls, const char *key,
|
|||
* of "/dns-query".
|
||||
*/
|
||||
if (http != NULL) {
|
||||
CHECK(cfg_map_get(http, "endpoints", &eplist));
|
||||
len = cfg_list_length(eplist, false);
|
||||
const cfg_obj_t *cfg_max_clients = NULL;
|
||||
if (cfg_map_get(http, "endpoints", &eplist) == ISC_R_SUCCESS) {
|
||||
INSIST(eplist != NULL);
|
||||
len = cfg_list_length(eplist, false);
|
||||
}
|
||||
|
||||
if (cfg_map_get(http, "listener-clients", &cfg_max_clients) ==
|
||||
ISC_R_SUCCESS) {
|
||||
INSIST(cfg_max_clients != NULL);
|
||||
max_clients = cfg_obj_asuint32(cfg_max_clients);
|
||||
}
|
||||
}
|
||||
|
||||
endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
|
||||
|
||||
if (http != NULL) {
|
||||
if (http != NULL && eplist != NULL) {
|
||||
for (elt = cfg_list_first(eplist); elt != NULL;
|
||||
elt = cfg_list_next(elt)) {
|
||||
const cfg_obj_t *ep = cfg_listelt_value(elt);
|
||||
|
|
@ -11358,18 +11375,39 @@ listenelt_http(const cfg_obj_t *http, bool tls, const char *key,
|
|||
|
||||
INSIST(i == len);
|
||||
|
||||
result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls,
|
||||
key, cert, endpoints, len, &delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (delt != NULL) {
|
||||
ns_listenelt_destroy(delt);
|
||||
}
|
||||
return (result);
|
||||
INSIST(named_g_server != NULL);
|
||||
ns_server_attach(named_g_server->sctx, &server);
|
||||
if (max_clients > 0) {
|
||||
quota = isc_mem_get(mctx, sizeof(isc_quota_t));
|
||||
isc_quota_init(quota, max_clients);
|
||||
}
|
||||
result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls,
|
||||
key, cert, endpoints, len, quota,
|
||||
&delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (quota != NULL) {
|
||||
ISC_LIST_APPEND(server->http_quotas, quota, link);
|
||||
}
|
||||
ns_server_detach(&server);
|
||||
|
||||
*target = delt;
|
||||
|
||||
cleanup:
|
||||
return (result);
|
||||
error:
|
||||
if (delt != NULL) {
|
||||
ns_listenelt_destroy(delt);
|
||||
}
|
||||
if (quota != NULL) {
|
||||
isc_quota_destroy(quota);
|
||||
isc_mem_put(mctx, quota, sizeof(*quota));
|
||||
}
|
||||
|
||||
if (server != NULL) {
|
||||
ns_server_detach(&server);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@ tls local-tls {
|
|||
|
||||
http local-http-server {
|
||||
endpoints { "/dns-query"; };
|
||||
listener-clients 100;
|
||||
};
|
||||
|
||||
options {
|
||||
listen-on { 10.53.0.1; };
|
||||
http-port 80;
|
||||
https-port 443;
|
||||
http-listener-clients 100;
|
||||
listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; };
|
||||
listen-on port 8080 tls none http local-http-server { 10.53.0.1; };
|
||||
};
|
||||
|
|
|
|||
29
bin/tests/system/checkconf/good-doh-4.conf
Normal file
29
bin/tests/system/checkconf/good-doh-4.conf
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
tls local-tls {
|
||||
key-file "key.pem";
|
||||
cert-file "cert.pem";
|
||||
};
|
||||
|
||||
# Use the default values only - just to make sure that we could
|
||||
# override only values which we need and there is no required ones.
|
||||
http empty-http-server {
|
||||
};
|
||||
|
||||
options {
|
||||
listen-on { 10.53.0.1; };
|
||||
http-port 80;
|
||||
https-port 443;
|
||||
http-listener-clients 100;
|
||||
listen-on port 443 tls local-tls http empty-http-server { 10.53.0.1; };
|
||||
listen-on port 8080 tls none http empty-http-server { 10.53.0.1; };
|
||||
};
|
||||
|
|
@ -1986,17 +1986,19 @@ bind9_check_httpserver(const cfg_obj_t *http, isc_log_t *logctx,
|
|||
|
||||
/* Check endpoints are valid */
|
||||
tresult = cfg_map_get(http, "endpoints", &eps);
|
||||
RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
|
||||
for (elt = cfg_list_first(eps); elt != NULL; elt = cfg_list_next(elt)) {
|
||||
const cfg_obj_t *ep = cfg_listelt_value(elt);
|
||||
const char *path = cfg_obj_asstring(ep);
|
||||
if (!isc_nm_http_path_isvalid(path)) {
|
||||
cfg_obj_log(eps, logctx, ISC_LOG_ERROR,
|
||||
"endpoint '%s' is not a "
|
||||
"valid absolute HTTP path",
|
||||
path);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ISC_R_FAILURE;
|
||||
if (tresult == ISC_R_SUCCESS) {
|
||||
for (elt = cfg_list_first(eps); elt != NULL;
|
||||
elt = cfg_list_next(elt)) {
|
||||
const cfg_obj_t *ep = cfg_listelt_value(elt);
|
||||
const char *path = cfg_obj_asstring(ep);
|
||||
if (!isc_nm_http_path_isvalid(path)) {
|
||||
cfg_obj_log(eps, logctx, ISC_LOG_ERROR,
|
||||
"endpoint '%s' is not a "
|
||||
"valid absolute HTTP path",
|
||||
path);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ struct isc_quota {
|
|||
atomic_uint_fast32_t waiting;
|
||||
isc_mutex_t cblock;
|
||||
ISC_LIST(isc_quota_cb_t) cbs;
|
||||
ISC_LINK(isc_quota_t) link;
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ isc_quota_init(isc_quota_t *quota, unsigned int max) {
|
|||
atomic_init("a->waiting, 0);
|
||||
ISC_LIST_INIT(quota->cbs);
|
||||
isc_mutex_init("a->cblock);
|
||||
ISC_LINK_INIT(quota, link);
|
||||
quota->magic = QUOTA_MAGIC;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1251,9 +1251,12 @@ static cfg_clausedef_t options_clauses[] = {
|
|||
{ "tls-port", &cfg_type_uint32, 0 },
|
||||
#if HAVE_LIBNGHTTP2
|
||||
{ "http-port", &cfg_type_uint32, 0 },
|
||||
{ "http-listener-clients", &cfg_type_uint32, 0 },
|
||||
{ "https-port", &cfg_type_uint32, 0 },
|
||||
#else
|
||||
{ "http-port", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTCONFIGURED },
|
||||
{ "http-listener-clients", &cfg_type_uint32,
|
||||
CFG_CLAUSEFLAG_NOTCONFIGURED },
|
||||
{ "https-port", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTCONFIGURED },
|
||||
#endif
|
||||
{ "querylog", &cfg_type_boolean, 0 },
|
||||
|
|
@ -3902,6 +3905,8 @@ static cfg_type_t cfg_type_bracketed_http_endpoint_list = {
|
|||
|
||||
static cfg_clausedef_t cfg_http_description_clauses[] = {
|
||||
{ "endpoints", &cfg_type_bracketed_http_endpoint_list, 0 },
|
||||
{ "listener-clients", &cfg_type_uint32, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cfg_clausedef_t *http_description_clausesets[] = {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ struct ns_listenelt {
|
|||
isc_tlsctx_t *sslctx;
|
||||
char ** http_endpoints;
|
||||
size_t http_endpoints_number;
|
||||
isc_quota_t * http_quota;
|
||||
ISC_LINK(ns_listenelt_t) link;
|
||||
};
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ isc_result_t
|
|||
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, bool tls, const char *key,
|
||||
const char *cert, char **endpoints, size_t nendpoints,
|
||||
ns_listenelt_t **target);
|
||||
isc_quota_t *quota, ns_listenelt_t **target);
|
||||
/*%<
|
||||
* Create a listen-on list element for HTTP(S).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ struct ns_server {
|
|||
isc_quota_t recursionquota;
|
||||
isc_quota_t tcpquota;
|
||||
isc_quota_t xfroutquota;
|
||||
ISC_LIST(isc_quota_t) http_quotas;
|
||||
|
||||
/*% Test options and other configurables */
|
||||
uint32_t options;
|
||||
|
|
|
|||
|
|
@ -539,13 +539,13 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
|
|||
|
||||
static isc_result_t
|
||||
ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
|
||||
size_t neps) {
|
||||
size_t neps, isc_quota_t *quota) {
|
||||
#if HAVE_LIBNGHTTP2
|
||||
isc_result_t result;
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
result = isc_nm_listenhttp(ifp->mgr->nm, &ifp->addr, ifp->mgr->backlog,
|
||||
&ifp->mgr->sctx->tcpquota, sslctx, &sock);
|
||||
quota, sslctx, &sock);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
for (size_t i = 0; i < neps; i++) {
|
||||
|
|
@ -609,9 +609,9 @@ 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);
|
||||
result = ns_interface_listenhttp(
|
||||
ifp, elt->sslctx, elt->http_endpoints,
|
||||
elt->http_endpoints_number, elt->http_quota);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_interface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
elt->sslctx = sslctx;
|
||||
elt->http_endpoints = NULL;
|
||||
elt->http_endpoints_number = 0;
|
||||
elt->http_quota = NULL;
|
||||
|
||||
*target = elt;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
@ -60,7 +61,7 @@ isc_result_t
|
|||
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, bool tls, const char *key,
|
||||
const char *cert, char **endpoints, size_t nendpoints,
|
||||
ns_listenelt_t **target) {
|
||||
isc_quota_t *quota, ns_listenelt_t **target) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
|
|
@ -73,6 +74,7 @@ ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
|
|||
(*target)->is_http = true;
|
||||
(*target)->http_endpoints = endpoints;
|
||||
(*target)->http_endpoints_number = nendpoints;
|
||||
(*target)->http_quota = quota;
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < nendpoints; i++) {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
|
|||
isc_quota_init(&sctx->xfroutquota, 10);
|
||||
isc_quota_init(&sctx->tcpquota, 10);
|
||||
isc_quota_init(&sctx->recursionquota, 100);
|
||||
ISC_LIST_INIT(sctx->http_quotas);
|
||||
|
||||
CHECKFATAL(dns_tkeyctx_create(mctx, &sctx->tkeyctx));
|
||||
|
||||
|
|
@ -125,6 +126,7 @@ ns_server_detach(ns_server_t **sctxp) {
|
|||
|
||||
if (isc_refcount_decrement(&sctx->references) == 1) {
|
||||
ns_altsecret_t *altsecret;
|
||||
isc_quota_t *http_quota;
|
||||
|
||||
while ((altsecret = ISC_LIST_HEAD(sctx->altsecrets)) != NULL) {
|
||||
ISC_LIST_UNLINK(sctx->altsecrets, altsecret, link);
|
||||
|
|
@ -135,6 +137,18 @@ ns_server_detach(ns_server_t **sctxp) {
|
|||
isc_quota_destroy(&sctx->tcpquota);
|
||||
isc_quota_destroy(&sctx->xfroutquota);
|
||||
|
||||
http_quota = ISC_LIST_HEAD(sctx->http_quotas);
|
||||
while (http_quota != NULL) {
|
||||
isc_quota_t *next = NULL;
|
||||
|
||||
next = ISC_LIST_NEXT(http_quota, link);
|
||||
ISC_LIST_DEQUEUE(sctx->http_quotas, http_quota, link);
|
||||
isc_quota_destroy(http_quota);
|
||||
isc_mem_put(sctx->mctx, http_quota,
|
||||
sizeof(*http_quota));
|
||||
http_quota = next;
|
||||
}
|
||||
|
||||
if (sctx->server_id != NULL) {
|
||||
isc_mem_free(sctx->mctx, sctx->server_id);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue