Skip to content

Instantly share code, notes, and snippets.

@deferraz
Created November 5, 2012 15:00
Show Gist options
  • Select an option

  • Save deferraz/4017597 to your computer and use it in GitHub Desktop.

Select an option

Save deferraz/4017597 to your computer and use it in GitHub Desktop.
mod_qos withproxy patch
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