diff --git a/bin/named/server.c b/bin/named/server.c index e36502863a..a8ba34457a 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -11226,8 +11226,6 @@ listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls, size_t len = 1, i = 0; uint32_t max_clients = named_g_http_listener_clients; uint32_t max_streams = named_g_http_streams_per_conn; - ns_server_t *server = NULL; - isc_quota_t *quota = NULL; REQUIRE(target != NULL && *target == NULL); @@ -11282,24 +11280,13 @@ listenelt_http(const cfg_obj_t *http, const uint16_t family, bool tls, INSIST(i == len); - 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, family, tls, tls_params, - tlsctx_cache, endpoints, len, quota, max_streams, &delt); + tlsctx_cache, endpoints, len, max_clients, max_streams, &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; return (result); @@ -11307,14 +11294,6 @@ 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); } #endif /* HAVE_LIBNGHTTP2 */ diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h index 87d7df9818..ac94c7957a 100644 --- a/lib/ns/include/ns/interfacemgr.h +++ b/lib/ns/include/ns/interfacemgr.h @@ -79,6 +79,7 @@ struct ns_interface { isc_nmsocket_t *tcplistensocket; isc_nmsocket_t *http_listensocket; isc_nmsocket_t *http_secure_listensocket; + isc_quota_t *http_quota; isc_dscp_t dscp; /*%< "listen-on" DSCP value */ isc_refcount_t ntcpaccepting; /*%< Number of clients * ready to accept new diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h index cf433b5028..cbb099c238 100644 --- a/lib/ns/include/ns/listenlist.h +++ b/lib/ns/include/ns/listenlist.h @@ -50,7 +50,7 @@ struct ns_listenelt { isc_tlsctx_cache_t *sslctx_cache; char **http_endpoints; size_t http_endpoints_number; - isc_quota_t *http_quota; + uint32_t http_max_clients; uint32_t max_concurrent_streams; ISC_LINK(ns_listenelt_t) link; }; @@ -98,7 +98,7 @@ ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp, dns_acl_t *acl, const uint16_t family, bool tls, const ns_listen_tls_params_t *tls_params, isc_tlsctx_cache_t *tlsctx_cache, char **endpoints, - size_t nendpoints, isc_quota_t *quota, + size_t nendpoints, const uint32_t max_clients, const uint32_t max_streams, ns_listenelt_t **target); /*%< * Create a listen-on list element for HTTP(S). diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index 1a2135824d..51c2c0a1d5 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -85,6 +85,7 @@ struct ns_server { isc_quota_t tcpquota; isc_quota_t xfroutquota; ISC_LIST(isc_quota_t) http_quotas; + isc_mutex_t http_quotas_lock; /*% Test options and other configurables */ uint32_t options; @@ -183,3 +184,13 @@ ns_server_getoption(ns_server_t *sctx, unsigned int option); * Requires: *\li 'sctx' is valid. */ + +void +ns_server_append_http_quota(ns_server_t *sctx, isc_quota_t *http_quota); +/*%< + * Add a quota to the list of HTTP quotas to destroy it safely later. + * + * Requires: + *\li 'sctx' is valid; + *\li 'http_quota' is not 'NULL'. + */ diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 118b7c0367..a70027a4cd 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -572,12 +572,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, isc_quota_t *quota, + size_t neps, uint32_t max_clients, uint32_t max_concurrent_streams) { #if HAVE_LIBNGHTTP2 isc_result_t result = ISC_R_FAILURE; isc_nmsocket_t *sock = NULL; isc_nm_http_endpoints_t *epset = NULL; + isc_quota_t *quota = NULL; epset = isc_nm_http_endpoints_new(ifp->mgr->mctx); @@ -590,6 +591,8 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps, } if (result == ISC_R_SUCCESS) { + quota = isc_mem_get(ifp->mgr->mctx, sizeof(*quota)); + isc_quota_init(quota, max_clients); result = isc_nm_listenhttp(ifp->mgr->nm, ISC_NM_LISTEN_ALL, &ifp->addr, ifp->mgr->backlog, quota, sslctx, epset, @@ -598,6 +601,16 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps, isc_nm_http_endpoints_detach(&epset); + if (quota != NULL) { + if (result != ISC_R_SUCCESS) { + isc_quota_destroy(quota); + isc_mem_put(ifp->mgr->mctx, quota, sizeof(*quota)); + } else { + ifp->http_quota = quota; + ns_server_append_http_quota(ifp->mgr->sctx, quota); + } + } + if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating %s socket: %s", @@ -630,7 +643,7 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps, UNUSED(sslctx); UNUSED(eps); UNUSED(neps); - UNUSED(quota); + UNUSED(max_clients); UNUSED(max_concurrent_streams); return (ISC_R_NOTIMPLEMENTED); #endif @@ -660,7 +673,7 @@ interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, if (elt->is_http) { result = ns_interface_listenhttp( ifp, elt->sslctx, elt->http_endpoints, - elt->http_endpoints_number, elt->http_quota, + elt->http_endpoints_number, elt->http_max_clients, elt->max_concurrent_streams); if (result != ISC_R_SUCCESS) { goto cleanup_interface; @@ -731,6 +744,7 @@ ns_interface_shutdown(ns_interface_t *ifp) { isc_nm_stoplistening(ifp->http_secure_listensocket); isc_nmsocket_close(&ifp->http_secure_listensocket); } + ifp->http_quota = NULL; } static void diff --git a/lib/ns/listenlist.c b/lib/ns/listenlist.c index f852f06d56..85fc12eb63 100644 --- a/lib/ns/listenlist.c +++ b/lib/ns/listenlist.c @@ -171,7 +171,8 @@ listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp, } elt->http_endpoints = NULL; elt->http_endpoints_number = 0; - elt->http_quota = NULL; + elt->http_max_clients = 0; + elt->max_concurrent_streams = 0; *target = elt; return (ISC_R_SUCCESS); @@ -200,7 +201,7 @@ ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp, dns_acl_t *acl, const uint16_t family, bool tls, const ns_listen_tls_params_t *tls_params, isc_tlsctx_cache_t *tlsctx_cache, char **endpoints, - size_t nendpoints, isc_quota_t *quota, + size_t nendpoints, const uint32_t max_clients, const uint32_t max_streams, ns_listenelt_t **target) { isc_result_t result; @@ -214,7 +215,14 @@ 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; + /* + * 0 sized quota - means unlimited quota. We used to not + * create a quota object in such a case, but we might need to + * update the value of the quota during reconfiguration, so we + * need to have a quota object in place anyway. + */ + (*target)->http_max_clients = max_clients == 0 ? UINT32_MAX + : max_clients; (*target)->max_concurrent_streams = max_streams; } else { size_t i; diff --git a/lib/ns/server.c b/lib/ns/server.c index 57bb753179..4a738118b1 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -55,6 +55,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, isc_quota_init(&sctx->tcpquota, 10); isc_quota_init(&sctx->recursionquota, 100); ISC_LIST_INIT(sctx->http_quotas); + isc_mutex_init(&sctx->http_quotas_lock); CHECKFATAL(dns_tkeyctx_create(mctx, &sctx->tkeyctx)); @@ -150,6 +151,7 @@ ns_server_detach(ns_server_t **sctxp) { sizeof(*http_quota)); http_quota = next; } + isc_mutex_destroy(&sctx->http_quotas_lock); if (sctx->server_id != NULL) { isc_mem_free(sctx->mctx, sctx->server_id); @@ -240,3 +242,14 @@ ns_server_getoption(ns_server_t *sctx, unsigned int option) { return ((sctx->options & option) != 0); } + +void +ns_server_append_http_quota(ns_server_t *sctx, isc_quota_t *http_quota) { + REQUIRE(SCTX_VALID(sctx)); + REQUIRE(http_quota != NULL); + + LOCK(&sctx->http_quotas_lock); + ISC_LINK_INIT(http_quota, link); + ISC_LIST_APPEND(sctx->http_quotas, http_quota, link); + UNLOCK(&sctx->http_quotas_lock); +}