Dear NGINX Open Source Community,

I hope this message finds you well.

Recently, I encountered a use case where I needed the deny directive
from the ngx_http_access_module to return a different HTTP status code
than the default 403 (Forbidden). To address this, I developed a small
patch that allows specifying a custom status code directly in the
directive.

This patch adds support for a second parameter to the deny directive,
enabling the user to define the HTTP return code. At the moment, the
patch supports only 403 (NGX_HTTP_FORBIDDEN) and 404
(NGX_HTTP_NOT_FOUND), but it can easily be modified to accept other
status codes as needed.

I believe this enhancement might be useful for others in similar
situations. The patch is attached for your reference, review and
consideration. I would be grateful if you could consider including it
in the official open source project.

Thank you for your time.
Fabiano Furtado
--- nginx-1.29.1/src/http/modules/ngx_http_access_module.c	2025-08-28 17:57:50.834471675 -0300
+++ nginx-1.29.1-patched/src/http/modules/ngx_http_access_module.c	2025-08-28 17:59:06.755196819 -0300
@@ -14,6 +14,7 @@
     in_addr_t         mask;
     in_addr_t         addr;
     ngx_uint_t        deny;      /* unsigned  deny:1; */
+    ngx_uint_t        deny_status_code;
 } ngx_http_access_rule_t;
 
 #if (NGX_HAVE_INET6)
@@ -22,6 +23,7 @@
     struct in6_addr   addr;
     struct in6_addr   mask;
     ngx_uint_t        deny;      /* unsigned  deny:1; */
+    ngx_uint_t        deny_status_code;
 } ngx_http_access_rule6_t;
 
 #endif
@@ -30,6 +32,7 @@
 
 typedef struct {
     ngx_uint_t        deny;      /* unsigned  deny:1; */
+    ngx_uint_t        deny_status_code;
 } ngx_http_access_rule_un_t;
 
 #endif
@@ -56,7 +59,8 @@
 static ngx_int_t ngx_http_access_unix(ngx_http_request_t *r,
     ngx_http_access_loc_conf_t *alcf);
 #endif
-static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
+static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny,
+    ngx_uint_t deny_status_code);
 static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
@@ -77,7 +81,7 @@
 
     { ngx_string("deny"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
-                        |NGX_CONF_TAKE1,
+                        |NGX_CONF_TAKE12,
       ngx_http_access_rule,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -194,7 +198,8 @@
                        addr, rule[i].mask, rule[i].addr);
 
         if ((addr & rule[i].mask) == rule[i].addr) {
-            return ngx_http_access_found(r, rule[i].deny);
+            return ngx_http_access_found(r, rule[i].deny,
+                                            rule[i].deny_status_code);
         }
     }
 
@@ -237,7 +242,8 @@
             }
         }
 
-        return ngx_http_access_found(r, rule6[i].deny);
+        return ngx_http_access_found(r, rule6[i].deny,
+                                        rule6[i].deny_status_code);
 
     next:
         continue;
@@ -262,7 +268,8 @@
 
         /* TODO: check path */
         if (1) {
-            return ngx_http_access_found(r, rule_un[i].deny);
+            return ngx_http_access_found(r, rule_un[i].deny,
+                                            rule_un[i].deny_status_code);
         }
     }
 
@@ -273,7 +280,8 @@
 
 
 static ngx_int_t
-ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
+ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny,
+    ngx_uint_t deny_status_code)
 {
     ngx_http_core_loc_conf_t  *clcf;
 
@@ -282,10 +290,11 @@
 
         if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "access forbidden by rule");
+                          "access forbidden by rule with status %ui",
+                          deny_status_code);
         }
 
-        return NGX_HTTP_FORBIDDEN;
+        return (ngx_int_t)deny_status_code;
     }
 
     return NGX_OK;
@@ -299,6 +308,8 @@
 
     ngx_int_t                   rc;
     ngx_uint_t                  all;
+    ngx_uint_t                  deny;
+    ngx_uint_t                  deny_status_code;
     ngx_str_t                  *value;
     ngx_cidr_t                  cidr;
     ngx_http_access_rule_t     *rule;
@@ -309,11 +320,13 @@
     ngx_http_access_rule_un_t  *rule_un;
 #endif
 
+    value = cf->args->elts;
+
     all = 0;
+    deny = (value[0].data[0] == 'd') ? 1 : 0;
+    deny_status_code = NGX_HTTP_FORBIDDEN;
     ngx_memzero(&cidr, sizeof(ngx_cidr_t));
 
-    value = cf->args->elts;
-
     if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
         all = 1;
 
@@ -337,6 +350,18 @@
         }
     }
 
+    if (deny && cf->args->nelts == 3) {
+        deny_status_code = ngx_atoi(value[2].data, value[2].len);
+        if (deny_status_code == NGX_ERROR || (
+                   deny_status_code != NGX_HTTP_FORBIDDEN &&
+                   deny_status_code != NGX_HTTP_NOT_FOUND)) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                "invalid \"%V\" response status code \"%V\"",
+                &value[0], &value[2]);
+            return NGX_CONF_ERROR;
+        }
+    }
+
     if (cidr.family == AF_INET || all) {
 
         if (alcf->rules == NULL) {
@@ -354,7 +379,8 @@
 
         rule->mask = cidr.u.in.mask;
         rule->addr = cidr.u.in.addr;
-        rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+        rule->deny = deny;
+        rule->deny_status_code = deny_status_code;
     }
 
 #if (NGX_HAVE_INET6)
@@ -375,7 +401,8 @@
 
         rule6->mask = cidr.u.in6.mask;
         rule6->addr = cidr.u.in6.addr;
-        rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
+        rule6->deny = deny;
+        rule6->deny_status_code = deny_status_code;
     }
 #endif
 
@@ -395,7 +422,8 @@
             return NGX_CONF_ERROR;
         }
 
-        rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0;
+        rule_un->deny = deny;
+        rule_un->deny_status_code = deny_status_code;
     }
 #endif
 
_______________________________________________
nginx mailing list
[email protected]
https://mailman.nginx.org/mailman/listinfo/nginx

Reply via email to