Created
November 5, 2012 15:00
-
-
Save deferraz/4017597 to your computer and use it in GitHub Desktop.
mod_qos withproxy patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff -uNr a/apache2/mod_qos.c b/apache2/mod_qos.c | |
| --- a/apache2/mod_qos.c 2012-11-01 19:30:30.000000000 -0200 | |
| +++ b/apache2/mod_qos.c 2012-11-01 20:36:33.000000000 -0200 | |
| @@ -223,6 +223,8 @@ | |
| #define qos_unixd_set_global_mutex_perms unixd_set_global_mutex_perms | |
| #endif | |
| +#define QS_CONN_WITHPROXY(r) apr_table_get(r->headers_in, "X-Forwarded-For") | |
| + | |
| #ifdef QS_MOD_EXT_HOOKS | |
| APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(qos, QOS, apr_status_t, path_decode_hook, | |
| (request_rec *r, char **path, int *len), | |
| @@ -631,6 +633,7 @@ | |
| unsigned long long static_img; | |
| unsigned long long static_other; | |
| unsigned long long static_notmodified; | |
| + int with_proxy; | |
| } qos_srv_config; | |
| /** | |
| @@ -6123,6 +6126,11 @@ | |
| * @return | |
| */ | |
| static int qos_process_connection(conn_rec *c) { | |
| + qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(c->base_server->module_config, | |
| + &qos_module); | |
| + if (sconf->with_proxy == 1) { | |
| + return DECLINED; | |
| + } | |
| qs_conn_ctx *cconf = qos_get_cconf(c); | |
| int vip = 0; | |
| if(cconf == NULL) { | |
| @@ -6132,8 +6140,6 @@ | |
| int current = 0; | |
| qs_ip_entry_t *e = NULL; | |
| char *msg = NULL; | |
| - qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(c->base_server->module_config, | |
| - &qos_module); | |
| qos_user_t *u = qos_get_user_conf(sconf->act->ppool); | |
| cconf = qos_create_cconf(c, sconf); | |
| @@ -6377,6 +6383,202 @@ | |
| return ret; | |
| } | |
| +static int qos_post_read_request_withproxy(request_rec *r) { | |
| + qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(r->connection->base_server->module_config, | |
| + &qos_module); | |
| + if (sconf->with_proxy == 0) { | |
| + return DECLINED; | |
| + } | |
| + else { | |
| + qs_conn_ctx *cconf = qos_get_cconf(r->connection); | |
| + int vip = 0; | |
| + if(cconf == NULL) { | |
| + int client_control = DECLINED; | |
| + int connections = 0; | |
| + int all_connections = 0; | |
| + int current = 0; | |
| + qs_ip_entry_t *e = NULL; | |
| + char *msg = NULL; | |
| + qos_user_t *u = qos_get_user_conf(sconf->act->ppool); | |
| + cconf = qos_create_cconf(r->connection, sconf); | |
| + | |
| + /* control timeout */ | |
| + qos_timeout_pc(r->connection, sconf); | |
| + | |
| + /* packet rate */ | |
| + if(sconf->qos_cc_prefer_limit) { | |
| + qos_pktrate_pc(r->connection, sconf); | |
| + } | |
| + | |
| + /* evaluates client ip */ | |
| + if((sconf->max_conn_per_ip != -1) || | |
| + sconf->has_qos_cc) { | |
| + cconf->ip = qos_inet_addr(QS_CONN_WITHPROXY(r)); | |
| +#ifdef QS_INTERNAL_TEST | |
| + /* use one of the predefined ip addresses */ | |
| + if(cconf->sconf->enable_testip) { | |
| + char *testid = apr_psprintf(r->connection->pool, "%d", rand()%(QS_SIM_IP_LEN-1)); | |
| + const char *testip = apr_table_get(cconf->sconf->testip, testid); | |
| + cconf->ip = qos_inet_addr(testip); | |
| + } | |
| +#endif | |
| + } | |
| + | |
| + /* ------------------------------------------------------------ | |
| + * update data | |
| + */ | |
| + /* client control */ | |
| + client_control = qos_cc_pc_filter(r->connection, cconf, u, &msg); | |
| + /* QS_SrvMaxConn: vhost connections or Geo */ | |
| + if(qos_count_connections(sconf)) { | |
| + apr_global_mutex_lock(cconf->sconf->act->lock); /* @CRT4 */ | |
| + if(cconf->sconf->act->conn) { | |
| + cconf->sconf->act->conn->connections++; | |
| + all_connections = qos_server_connections(sconf); | |
| + connections = cconf->sconf->act->conn->connections; /* @CRT4 */ | |
| + apr_table_set(r->connection->notes, "QS_SrvConn", apr_psprintf(r->connection->pool, "%d", connections)); | |
| + apr_table_set(r->connection->notes, "QS_AllConn", apr_psprintf(r->connection->pool, "%d", all_connections)); | |
| + } | |
| + apr_global_mutex_unlock(cconf->sconf->act->lock); | |
| + } | |
| + | |
| + /* single source ip */ | |
| + if(sconf->max_conn_per_ip != -1) { | |
| + current = qos_inc_ip(cconf, &e); | |
| + } | |
| + /* Check for vip (by ip) */ | |
| + if(apr_table_elts(sconf->exclude_ip)->nelts > 0) { | |
| + int i; | |
| + apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(sconf->exclude_ip)->elts; | |
| + for(i = 0; i < apr_table_elts(sconf->exclude_ip)->nelts; i++) { | |
| + if(entry[i].val[0] == 'r') { | |
| + if(strncmp(entry[i].key, QS_CONN_REMOTEIP(cconf->c), strlen(entry[i].key)) == 0) { | |
| + vip = 1; | |
| + /* propagate vip to connection */ | |
| + cconf->is_vip = vip; | |
| + if(!cconf->evmsg || !strstr(cconf->evmsg, "S;")) { | |
| + cconf->evmsg = apr_pstrcat(r->connection->pool, "S;", cconf->evmsg, NULL); | |
| + } | |
| + } | |
| + } else { | |
| + if(strcmp(entry[i].key, QS_CONN_REMOTEIP(cconf->c)) == 0) { | |
| + vip = 1; | |
| + /* propagate vip to connection */ | |
| + cconf->is_vip = vip; | |
| + if(!cconf->evmsg || !strstr(cconf->evmsg, "S;")) { | |
| + cconf->evmsg = apr_pstrcat(r->connection->pool, "S;", cconf->evmsg, NULL); | |
| + } | |
| + } | |
| + } | |
| + } | |
| + } | |
| + | |
| + /* ------------------------------------------------------------ | |
| + * enforce rules | |
| + */ | |
| + /* client control */ | |
| + if((client_control != DECLINED) && !vip) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + "%s", | |
| + msg == NULL ? "-" : msg); | |
| + if(!sconf->log_only) { | |
| + r->connection->keepalive = AP_CONN_CLOSE; | |
| + return qos_return_error(r->connection); | |
| + } | |
| + } | |
| + /* Geo */ | |
| + if(sconf->geodb) { | |
| + unsigned long ip = qos_geo_str2long(r->connection->pool, QS_CONN_WITHPROXY(r)); | |
| + qos_geo_t *pB = bsearch(&ip, | |
| + sconf->geodb, | |
| + sconf->geodb_size, | |
| + sizeof(qos_geo_t), | |
| + qos_geo_comp); | |
| + if(pB) { | |
| + apr_table_set(r->connection->notes, QS_COUNTRY, pB->country); | |
| + } | |
| + if(sconf->geo_limit != -1) { | |
| + if(all_connections >= sconf->geo_limit) { | |
| + if(pB == NULL || apr_table_get(sconf->geo_priv, pB->country) == NULL) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + QOS_LOG_PFX(101)"access denied, QS_ClientGeoCountryPriv rule: max=%d," | |
| + " concurrent connections=%d," | |
| + " c=%s" | |
| + " country=%s", | |
| + sconf->geo_limit, | |
| + all_connections, | |
| + QS_CONN_WITHPROXY(r), | |
| + pB != NULL ? pB->country : "--"); | |
| + if(!sconf->log_only) { | |
| + r->connection->keepalive = AP_CONN_CLOSE; | |
| + return qos_return_error(r->connection); | |
| + } | |
| + } | |
| + } | |
| + } | |
| + } | |
| + /* QS_SrvMaxConn: vhost connections */ | |
| + if((sconf->max_conn != -1) && !vip) { | |
| + if(connections > sconf->max_conn) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + QOS_LOG_PFX(030)"access denied, QS_SrvMaxConn rule: max=%d," | |
| + " concurrent connections=%d," | |
| + " c=%s", | |
| + sconf->max_conn, connections, | |
| + QS_CONN_WITHPROXY(r) == NULL ? "-" : QS_CONN_WITHPROXY(r)); | |
| + if(!sconf->log_only) { | |
| + r->connection->keepalive = AP_CONN_CLOSE; | |
| + return qos_return_error(r->connection); | |
| + } | |
| + } | |
| + } | |
| + /* single source ip */ | |
| + if((sconf->max_conn_per_ip != -1) && !vip) { | |
| + if(current > sconf->max_conn_per_ip) { | |
| + e->error++; | |
| + /* only print the first 20 messages for this client */ | |
| + if(e->error <= QS_LOG_REPEAT) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + QOS_LOG_PFX(031)"access denied, QS_SrvMaxConnPerIP rule: max=%d," | |
| + " concurrent connections=%d," | |
| + " c=%s", | |
| + sconf->max_conn_per_ip, current, | |
| + QS_CONN_WITHPROXY(r) == NULL ? "-" : QS_CONN_WITHPROXY(r)); | |
| + } else { | |
| + if((e->error % QS_LOG_REPEAT) == 0) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + QOS_LOG_PFX(031)"access denied, QS_SrvMaxConnPerIP rule: max=%d," | |
| + " concurrent connections=%d," | |
| + " message repeated %d times," | |
| + " c=%s", | |
| + sconf->max_conn_per_ip, current, | |
| + QS_LOG_REPEAT, | |
| + QS_CONN_WITHPROXY(r) == NULL ? "-" : QS_CONN_WITHPROXY(r)); | |
| + } | |
| + } | |
| + if(!sconf->log_only) { | |
| + r->connection->keepalive = AP_CONN_CLOSE; | |
| + return qos_return_error(r->connection); | |
| + } | |
| + } else { | |
| + if(e->error > 0) { | |
| + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server, | |
| + QOS_LOG_PFX(031)"access denied, QS_SrvMaxConnPerIP rule: max=%d," | |
| + " concurrent connections=%d," | |
| + " message repeated %d times," | |
| + " c=%s", | |
| + sconf->max_conn_per_ip, current, | |
| + e->error % QS_LOG_REPEAT, | |
| + QS_CONN_WITHPROXY(r) == NULL ? "-" : QS_CONN_WITHPROXY(r)); | |
| + } | |
| + e->error = 0; | |
| + } | |
| + } | |
| + } | |
| + } | |
| + return DECLINED; | |
| +} | |
| + | |
| /** | |
| * Process user tracking cookie | |
| * | |
| @@ -8852,6 +9054,19 @@ | |
| return NULL; | |
| } | |
| +const char *qos_withproxy_cmd(cmd_parms *cmd, void *dcfg, int flag) { | |
| + qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config, | |
| + &qos_module); | |
| + | |
| + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); | |
| + if (err != NULL) { | |
| + return err; | |
| + } | |
| + sconf->with_proxy = flag; | |
| + | |
| + return NULL; | |
| +} | |
| + | |
| const char *qos_mfile_cmd(cmd_parms *cmd, void *dcfg, const char *path) { | |
| qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config, | |
| &qos_module); | |
| @@ -10475,6 +10690,10 @@ | |
| RSRC_CONF, | |
| "QS_LogOnly 'on'|'off', enabled log only mode where no limitations are" | |
| " enforced. Default is off."), | |
| + AP_INIT_FLAG("QS_WithProxy", qos_withproxy_cmd, NULL, | |
| + RSRC_CONF, | |
| + "QS_WithProxy 'on'|'off', turn this on if this Apache instance is behind" | |
| + "a Proxy Server. Default is off."), | |
| AP_INIT_TAKE1("QS_SemMemFile", qos_mfile_cmd, NULL, | |
| RSRC_CONF, | |
| "QS_SemMemFile <path>, optional path to a directory or file" | |
| @@ -11030,6 +11249,7 @@ | |
| ap_hook_child_init(qos_child_init, NULL, NULL, APR_HOOK_MIDDLE); | |
| ap_hook_pre_connection(qos_pre_connection, NULL, pressl, APR_HOOK_FIRST); | |
| ap_hook_process_connection(qos_process_connection, NULL, NULL, APR_HOOK_MIDDLE); | |
| + ap_hook_post_read_request(qos_post_read_request_withproxy, NULL, pre, APR_HOOK_FIRST); | |
| ap_hook_post_read_request(qos_post_read_request, NULL, post, APR_HOOK_MIDDLE); | |
| ap_hook_post_read_request(qos_post_read_request_later, pre, NULL, APR_HOOK_MIDDLE); | |
| ap_hook_header_parser(qos_header_parser0, NULL, post, APR_HOOK_FIRST); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment