On Fri, 2009-10-16 at 08:00 +1100, Bojan Smojver wrote: > I wrote the attached craziness.
Slightly more sophisticated craziness attached. -- Bojan
--- httpd-2.2.14/server/mpm/prefork/prefork.c 2009-02-01 07:54:55.000000000 +1100 +++ httpd-2.2.14-p/server/mpm/prefork/prefork.c 2009-10-16 12:19:49.929566854 +1100 @@ -803,6 +803,7 @@ int free_slots[MAX_SPAWN_RATE]; int last_non_dead; int total_non_dead; + static apr_time_t maxed_out = 0; /* initialize the free_list */ free_length = 0; @@ -856,12 +857,14 @@ */ ap_mpm_pod_signal(pod); idle_spawn_rate = 1; + maxed_out = 0; } else if (idle_count < ap_daemons_min_free) { /* terminate the free list */ if (free_length == 0) { /* only report this condition once */ static int reported = 0; + apr_time_t now = apr_time_now(), diff; if (!reported) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, @@ -870,6 +873,36 @@ reported = 1; } idle_spawn_rate = 1; + + /* Flooded by intentionally slow requests (e.g. slowloris)? + * Give the legitimate clients one maintenance interval to + * finish with request reads, then cull if we are still + * maxed out. Crude, but seems to clear things out. + */ + diff = now - maxed_out; + + if (diff >= SCOREBOARD_MAINTENANCE_INTERVAL && + diff <= SCOREBOARD_MAINTENANCE_INTERVAL * 2) { + + pid_t reader; + + for (i = 0; i < ap_daemons_limit; ++i) { + + ws = &ap_scoreboard_image->servers[i][0]; + + if (ws->status == SERVER_BUSY_READ || + ws->status == SERVER_BUSY_KEEPALIVE) { + + reader = ap_scoreboard_image->parent[i].pid; + + ap_mpm_safe_kill(reader, SIGTERM); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, + "Killed reader: %" APR_PID_T_FMT, reader); + } + } + } + + maxed_out = now; } else { if (idle_spawn_rate >= 8) { @@ -902,10 +934,13 @@ else if (idle_spawn_rate < MAX_SPAWN_RATE) { idle_spawn_rate *= 2; } + + maxed_out = 0; } } else { idle_spawn_rate = 1; + maxed_out = 0; } }