Package: libapache2-mod-evasive Version: 1.10.1-3 Severity: wishlist Dear Maintainer,
At present, libapache2-mod-evasive returns HTTP 403 Frobidden when an IP is blocked. This HTTP response code may not always be appropriate, as per RFC 6585, where a client has sent too many requests the HTTP reponse code 429 maybe more accurate. I'v attached a patch that adds a setting to libapache-mod-evasive: DOSHTTPResponseCode, which can be set to any response code between 100 and 599. Regards, Anthony. -- System Information: Debian Release: 9.9 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 4.9.0-9-amd64 (SMP w/8 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE=en_GB.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages libapache2-mod-evasive depends on: ii apache2-bin [apache2-api-20120211] 2.4.25-3+deb9u7 ii bsd-mailx [mailx] 8.1.2-0.20160123cvs-4 ii libc6 2.24-11+deb9u4 libapache2-mod-evasive recommends no packages. libapache2-mod-evasive suggests no packages. -- no debconf information
diff --git a/README b/README index 2d09b62..c740e9b 100644 --- a/README +++ b/README @@ -179,6 +179,7 @@ Optionally you can also add the following directives: DOSEmailNotify y...@yourdomain.com DOSSystemCommand "su - someuser -c '/sbin/... %s ...'" DOSLogDir "/var/lock/mod_evasive" + DOSHTTPResponseCode 429 You will also need to add this line if you are building with dynamic support: @@ -316,6 +317,14 @@ In the event you have nonprivileged shell users, you'll want to create a directory writable only to the user Apache is running as (usually root), then set this in your httpd.conf. +DOSHTTPResponseCode +--------- + +Choose an alternative HTTP response code to be returned when an IP is blocked. + +By default 403 HTTP_FORBIDDEN will be returned. + + WHITELISTING IP ADDRESSES IP addresses of trusted clients can be whitelisted to insure they are never diff --git a/mod_evasive20.c b/mod_evasive20.c index a23ccce..44548dd 100644 --- a/mod_evasive20.c +++ b/mod_evasive20.c @@ -52,6 +52,7 @@ module AP_MODULE_DECLARE_DATA evasive20_module; #define DEFAULT_SITE_INTERVAL 1 // Default 1 Second site interval #define DEFAULT_BLOCKING_PERIOD 10 // Default for Detected IPs; blocked for 10 seconds #define DEFAULT_LOG_DIR "/tmp" // Default temp directory +#define DEFAULT_HTTP_RESPONSE_CODE HTTP_FORBIDDEN /* END DoS Evasive Maneuvers Definitions */ @@ -106,8 +107,8 @@ static char *email_notify = NULL; static char *log_dir = NULL; static char *system_command = NULL; static const char *whitelist(cmd_parms *cmd, void *dconfig, const char *ip); +static int http_response_code = DEFAULT_HTTP_RESPONSE_CODE; int is_whitelisted(const char *ip); - /* END DoS Evasive Maneuvers Globals */ static void * create_hit_list(apr_pool_t *p, server_rec *s) @@ -139,30 +140,30 @@ static int access_checker(request_rec *r) time_t t = time(NULL); /* Check whitelist */ - if (is_whitelisted(r->connection->remote_ip)) + if (is_whitelisted(r->connection->client_ip)) return OK; /* First see if the IP itself is on "hold" */ - n = ntt_find(hit_list, r->connection->remote_ip); + n = ntt_find(hit_list, r->connection->client_ip); if (n != NULL && t-n->timestamp<blocking_period) { - /* If the IP is on "hold", make it wait longer in 403 land */ - ret = HTTP_FORBIDDEN; + /* If the IP is on "hold", make it wait longer on blacklist */ + ret = http_response_code; n->timestamp = time(NULL); /* Not on hold, check hit stats */ } else { /* Has URI been hit too much? */ - snprintf(hash_key, 2048, "%s_%s", r->connection->remote_ip, r->uri); + snprintf(hash_key, 2048, "%s_%s", r->connection->client_ip, r->uri); n = ntt_find(hit_list, hash_key); if (n != NULL) { - /* If URI is being hit too much, add to "hold" list and 403 */ + /* If URI is being hit too much, add to "hold" list */ if (t-n->timestamp<page_interval && n->count>=page_count) { - ret = HTTP_FORBIDDEN; - ntt_insert(hit_list, r->connection->remote_ip, time(NULL)); + ret = http_response_code; + ntt_insert(hit_list, r->connection->client_ip, time(NULL)); } else { /* Reset our hit count list as necessary */ @@ -177,14 +178,14 @@ static int access_checker(request_rec *r) } /* Has site been hit too much? */ - snprintf(hash_key, 2048, "%s_SITE", r->connection->remote_ip); + snprintf(hash_key, 2048, "%s_SITE", r->connection->client_ip); n = ntt_find(hit_list, hash_key); if (n != NULL) { - /* If site is being hit too much, add to "hold" list and 403 */ + /* If site is being hit too much, add to "hold" list */ if (t-n->timestamp<site_interval && n->count>=site_count) { - ret = HTTP_FORBIDDEN; - ntt_insert(hit_list, r->connection->remote_ip, time(NULL)); + ret = http_response_code; + ntt_insert(hit_list, r->connection->client_ip, time(NULL)); } else { /* Reset our hit count list as necessary */ @@ -200,32 +201,32 @@ static int access_checker(request_rec *r) } /* Perform email notification and system functions */ - if (ret == HTTP_FORBIDDEN) { + if (ret == http_response_code) { char filename[1024]; struct stat s; FILE *file; - snprintf(filename, sizeof(filename), "%s/dos-%s", log_dir != NULL ? log_dir : DEFAULT_LOG_DIR, r->connection->remote_ip); + snprintf(filename, sizeof(filename), "%s/dos-%s", log_dir != NULL ? log_dir : DEFAULT_LOG_DIR, r->connection->client_ip); if (stat(filename, &s)) { file = fopen(filename, "w"); if (file != NULL) { fprintf(file, "%ld\n", getpid()); fclose(file); - LOG(LOG_ALERT, "Blacklisting address %s: possible DoS attack.", r->connection->remote_ip); + LOG(LOG_ALERT, "Blacklisting address %s: possible DoS attack.", r->connection->client_ip); if (email_notify != NULL) { snprintf(filename, sizeof(filename), MAILER, email_notify); file = popen(filename, "w"); if (file != NULL) { fprintf(file, "To: %s\n", email_notify); - fprintf(file, "Subject: HTTP BLACKLIST %s\n\n", r->connection->remote_ip); - fprintf(file, "mod_evasive HTTP Blacklisted %s\n", r->connection->remote_ip); + fprintf(file, "Subject: HTTP BLACKLIST %s\n\n", r->connection->client_ip); + fprintf(file, "mod_evasive HTTP Blacklisted %s\n", r->connection->client_ip); pclose(file); } } if (system_command != NULL) { - snprintf(filename, sizeof(filename), system_command, r->connection->remote_ip); + snprintf(filename, sizeof(filename), system_command, r->connection->client_ip); system(filename); } @@ -235,13 +236,13 @@ static int access_checker(request_rec *r) } /* if (temp file does not exist) */ - } /* if (ret == HTTP_FORBIDDEN) */ + } /* if (ret == http_response_code) */ } /* if (r->prev == NULL && r->main == NULL && hit_list != NULL) */ /* END DoS Evasive Maneuvers Code */ - if (ret == HTTP_FORBIDDEN + if (ret == http_response_code && (ap_satisfies(r) != SATISFY_ANY || !ap_some_auth_required(r))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "client denied by server configuration: %s", @@ -642,7 +643,21 @@ get_system_command(cmd_parms *cmd, void *dconfig, const char *value) { } return NULL; -} +} + +static const char * +get_http_response_code(cmd_parms *cmd, void *dconfig, const char *value) { + int n = strtol(value, NULL, 0); + // Allow HTTP response codes between 100 and 599 as per RFC 7231 + if (n>=100 && n<600) { + http_response_code = n; + } else { + http_response_code = DEFAULT_HTTP_RESPONSE_CODE; + } + + return NULL; +} + /* END Configuration Functions */ @@ -678,6 +693,9 @@ static const command_rec access_cmds[] = AP_INIT_ITERATE("DOSWhitelist", whitelist, NULL, RSRC_CONF, "IP-addresses wildcards to whitelist"), + AP_INIT_TAKE1("DOSHTTPResponseCode", get_http_response_code, NULL, RSRC_CONF, + "Set HTTP response code returned when IP is blocked"), + { NULL } };