From: Graham Leggett Date: Sun, 22 Aug 2021 09:51:33 +0000 (+0000) Subject: Backport: X-Git-Tag: candidate-2.4.49~3^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=21ee1a7dbfc76b1bb8f6ce9dc4f8e49b2bea9a94;p=thirdparty%2Fapache%2Fhttpd.git Backport: *) back port the add of balancer_manage in mod_proxy_balancer. trunk patch: http://svn.apache.org/r1859235 http://svn.apache.org/r1887176 http://svn.apache.org/r1887359 http://svn.apache.org/r1887144 Backport version for 2.4.x of patch: https://people.apache.org/~jfclere/patches/patch.210810.txt +1: jfclere, jim, minfrin git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1892522 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/STATUS b/STATUS index c9022475054..07a493cf1b1 100644 --- a/STATUS +++ b/STATUS @@ -142,20 +142,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) back port the add of balancer_manage in mod_proxy_balancer. - trunk patch: http://svn.apache.org/r1859235 - http://svn.apache.org/r1887176 - http://svn.apache.org/r1887359 - http://svn.apache.org/r1887144 - Backport version for 2.4.x of patch: - https://people.apache.org/~jfclere/patches/patch.210810.txt - +1: jfclere, jim, minfrin - jfclere: The previous proposal was removing the Referer check. - jorton: r1859235 has an "ok2change" param in the newly added - balancer_process_balancer_worker() but this is missing in the - backport patch, maybe include r1887144 for completeness? - jfclere: Fixed: Added in the patch.210810.txt - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index a162b8f90de..799998e9f76 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -574,6 +574,7 @@ * mod_dav.h. * 20120211.112 (2.4.49-dev) Add deliver_report and gather_reports hooks. * 20120211.113 (2.4.49-dev) Add method_precondition hook. + * 20120211.114 (2.4.49-dev) Add optional balancer_manage function. */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -581,7 +582,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 113 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 114 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index bf6bbd0fb33..c307bc9060a 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -1169,6 +1169,16 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec *s, proxy_server_conf *conf); +/** + * Configure and create workers (and balancer) in mod_balancer. + * @param r request + * @param params table with the parameters like b=mycluster etc. + * @return 404 when the worker/balancer doesn't exist, + * 400 if something is invalid + * 200 for success. + */ +APR_DECLARE_OPTIONAL_FN(apr_status_t, balancer_manage, + (request_rec *, apr_table_t *params)); /** * Find the matched alias for this request and setup for proxy handler diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index ece8498b6d9..db469528bfc 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -1120,119 +1120,20 @@ static int safe_referer(request_rec *r, const char *ref) return strcasecmp(uri.hostname, ap_get_server_name(r)) == 0; } -/* Manages the loadfactors and member status - * The balancer, worker and nonce are obtained from - * the request args (?b=...&w=...&nonce=....). - * All other params are pulled from any POST - * data that exists. - * TODO: - * /...//balancer/worker/nonce +/* + * Process the paramters and add or update the worker of the + * balancer. Must only be called if the nonce has been validated to + * match, to avoid XSS attacks. */ -static int balancer_handler(request_rec *r) +static int balancer_process_balancer_worker(request_rec *r, proxy_server_conf *conf, + proxy_balancer *bsel, + proxy_worker *wsel, + apr_table_t *params) + { - void *sconf; - proxy_server_conf *conf; - proxy_balancer *balancer, *bsel = NULL; - proxy_worker *worker, *wsel = NULL; - proxy_worker **workers = NULL; - apr_table_t *params; - int i, n; - int ok2change = 1; - const char *name, *ref; - const char *action; apr_status_t rv; - - /* is this for us? */ - if (strcmp(r->handler, "balancer-manager")) { - return DECLINED; - } - - r->allowed = 0 - | (AP_METHOD_BIT << M_GET) - | (AP_METHOD_BIT << M_POST); - if ((r->method_number != M_GET) && (r->method_number != M_POST)) { - return DECLINED; - } - - sconf = r->server->module_config; - conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - params = apr_table_make(r->pool, 10); - - balancer = (proxy_balancer *)conf->balancers->elts; - for (i = 0; i < conf->balancers->nelts; i++, balancer++) { -#if APR_HAS_THREADS - if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01189) - "%s: Lock failed for balancer_handler", - balancer->s->name); - } -#endif - ap_proxy_sync_balancer(balancer, r->server, conf); -#if APR_HAS_THREADS - if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01190) - "%s: Unlock failed for balancer_handler", - balancer->s->name); - } -#endif - } - - if (r->args && (r->method_number == M_GET)) { - const char *allowed[] = { "w", "b", "nonce", "xml", NULL }; - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01191) "parsing r->args"); - - push2table(r->args, params, allowed, r->pool); - } - if (r->method_number == M_POST) { - apr_bucket_brigade *ib; - apr_size_t len = 1024; - char *buf = apr_pcalloc(r->pool, len+1); - - ib = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); - rv = ap_get_brigade(r->input_filters, ib, AP_MODE_READBYTES, - APR_BLOCK_READ, len); - if (rv != APR_SUCCESS) { - return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); - } - apr_brigade_flatten(ib, buf, &len); - buf[len] = '\0'; - push2table(buf, params, NULL, r->pool); - } - - /* Ignore parameters if this looks like XSRF */ - ref = apr_table_get(r->headers_in, "Referer"); - if (apr_table_elts(params) - && (!ref || !safe_referer(r, ref))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10187) - "ignoring params in balancer-manager cross-site access"); - apr_table_clear(params); - } - - if ((name = apr_table_get(params, "b"))) - bsel = ap_proxy_get_balancer(r->pool, conf, - apr_pstrcat(r->pool, BALANCER_PREFIX, name, NULL), 0); - - if ((name = apr_table_get(params, "w"))) { - wsel = ap_proxy_get_worker(r->pool, bsel, conf, name); - } - - - /* Check that the supplied nonce matches this server's nonce; - * otherwise ignore all parameters, to prevent a CSRF attack. */ - if (!bsel || - (*bsel->s->nonce && - ( - (name = apr_table_get(params, "nonce")) == NULL || - strcmp(bsel->s->nonce, name) != 0 - ) - ) - ) { - apr_table_clear(params); - ok2change = 0; - } - /* First set the params */ - if (wsel && ok2change) { + if (wsel) { const char *val; int was_usable = PROXY_WORKER_IS_USABLE(wsel); @@ -1341,7 +1242,7 @@ static int balancer_handler(request_rec *r) } - if (bsel && ok2change) { + if (bsel) { const char *val; int ival; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01193) @@ -1488,11 +1389,62 @@ static int balancer_handler(request_rec *r) } } + return APR_SUCCESS; +} + +/* + * Process a request for balancer or worker management from another module + */ +static apr_status_t balancer_manage(request_rec *r, apr_table_t *params) +{ + void *sconf; + proxy_server_conf *conf; + proxy_balancer *bsel = NULL; + proxy_worker *wsel = NULL; + const char *name; + sconf = r->server->module_config; + conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); + + /* Process the parameters */ + if ((name = apr_table_get(params, "b"))) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "balancer_manage " + "balancer: %s", name); + bsel = ap_proxy_get_balancer(r->pool, conf, + apr_pstrcat(r->pool, BALANCER_PREFIX, name, NULL), 0); + } + if ((name = apr_table_get(params, "w"))) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "balancer_manage " + "worker: %s", name); + wsel = ap_proxy_get_worker(r->pool, bsel, conf, name); + } + if (bsel) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "balancer_manage " + "balancer: %s", bsel->s->name); + return(balancer_process_balancer_worker(r, conf, bsel, wsel, params)); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "balancer_manage failed: " + "No balancer!"); + return HTTP_BAD_REQUEST; +} + +/* + * builds the page and links to configure via HTLM or XML. + */ +static void balancer_display_page(request_rec *r, proxy_server_conf *conf, + proxy_balancer *bsel, + proxy_worker *wsel, + int usexml) +{ + const char *action; + proxy_balancer *balancer; + proxy_worker *worker; + proxy_worker **workers; + int i, n; action = ap_construct_url(r->pool, r->uri, r); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01204) "genning page"); - if (apr_table_get(params, "xml")) { + if (usexml) { char date[APR_RFC822_DATE_LEN]; ap_set_content_type(r, "text/xml"); ap_rputs("\n", r); @@ -1938,6 +1890,123 @@ static int balancer_handler(request_rec *r) ap_rputs("\n", r); ap_rflush(r); } +} + +/* Manages the loadfactors and member status + * The balancer, worker and nonce are obtained from + * the request args (?b=...&w=...&nonce=....). + * All other params are pulled from any POST + * data that exists. + * TODO: + * /...//balancer/worker/nonce + */ +static int balancer_handler(request_rec *r) +{ + void *sconf; + proxy_server_conf *conf; + proxy_balancer *balancer, *bsel = NULL; + proxy_worker *wsel = NULL; + apr_table_t *params; + int i; + const char *name, *ref; + apr_status_t rv; + + /* is this for us? */ + if (strcmp(r->handler, "balancer-manager")) { + return DECLINED; + } + + r->allowed = 0 + | (AP_METHOD_BIT << M_GET) + | (AP_METHOD_BIT << M_POST); + if ((r->method_number != M_GET) && (r->method_number != M_POST)) { + return DECLINED; + } + + sconf = r->server->module_config; + conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); + params = apr_table_make(r->pool, 10); + + balancer = (proxy_balancer *)conf->balancers->elts; + for (i = 0; i < conf->balancers->nelts; i++, balancer++) { +#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01189) + "%s: Lock failed for balancer_handler", + balancer->s->name); + } +#endif + ap_proxy_sync_balancer(balancer, r->server, conf); +#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01190) + "%s: Unlock failed for balancer_handler", + balancer->s->name); + } +#endif + } + + if (r->args && (r->method_number == M_GET)) { + const char *allowed[] = { "w", "b", "nonce", "xml", NULL }; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01191) "parsing r->args"); + + push2table(r->args, params, allowed, r->pool); + } + if (r->method_number == M_POST) { + apr_bucket_brigade *ib; + apr_size_t len = 1024; + char *buf = apr_pcalloc(r->pool, len+1); + + ib = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); + rv = ap_get_brigade(r->input_filters, ib, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rv != APR_SUCCESS) { + return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + } + apr_brigade_flatten(ib, buf, &len); + buf[len] = '\0'; + push2table(buf, params, NULL, r->pool); + } + + /* Ignore parameters if this looks like XSRF */ + ref = apr_table_get(r->headers_in, "Referer"); + if (apr_table_elts(params) + && (!ref || !safe_referer(r, ref))) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10187) + "ignoring params in balancer-manager cross-site access %s: %s", ref, ap_get_server_name(r)); + apr_table_clear(params); + } + + /* Process the parameters */ + if ((name = apr_table_get(params, "b"))) + bsel = ap_proxy_get_balancer(r->pool, conf, + apr_pstrcat(r->pool, BALANCER_PREFIX, name, NULL), 0); + + if ((name = apr_table_get(params, "w"))) { + wsel = ap_proxy_get_worker(r->pool, bsel, conf, name); + } + + + /* Check that the supplied nonce matches this server's nonce; + * otherwise ignore all parameters, to prevent a CSRF + * attack. */ + if (bsel + && (*bsel->s->nonce + && ((name = apr_table_get(params, "nonce")) != NULL + && strcmp(bsel->s->nonce, name) == 0))) { + /* Process the parameters and add the worker to the balancer */ + rv = balancer_process_balancer_worker(r, conf, bsel, wsel, params); + if (rv != APR_SUCCESS) { + return HTTP_BAD_REQUEST; + } + } + + /* display the HTML or XML page */ + if (apr_table_get(params, "xml")) { + balancer_display_page(r, conf, bsel, wsel, 1); + } else { + balancer_display_page(r, conf, bsel, wsel, 0); + } return DONE; } @@ -1986,6 +2055,7 @@ static void ap_proxy_balancer_register_hook(apr_pool_t *p) static const char *const aszPred[] = { "mpm_winnt.c", "mod_slotmem_shm.c", NULL}; static const char *const aszPred2[] = { "mod_proxy.c", NULL}; /* manager handler */ + APR_REGISTER_OPTIONAL_FN(balancer_manage); ap_hook_post_config(balancer_post_config, aszPred2, NULL, APR_HOOK_MIDDLE); ap_hook_pre_config(balancer_pre_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(balancer_handler, NULL, NULL, APR_HOOK_FIRST);