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 }
 };
 

Reply via email to