Skip to content

Commit 1db43b1

Browse files
authored
Move everything into access phase
1 parent cd63e40 commit 1db43b1

File tree

4 files changed

+235
-290
lines changed

4 files changed

+235
-290
lines changed

config

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ else
152152
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
153153
$ngx_addon_dir/src/ngx_http_modsecurity_body_filter.c \
154154
$ngx_addon_dir/src/ngx_http_modsecurity_log.c \
155-
$ngx_addon_dir/src/ngx_http_modsecurity_rewrite.c \
156155
"
157156

158157
NGX_ADDON_DEPS="\

src/ngx_http_modsecurity_access.c

Lines changed: 234 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,248 @@ ngx_http_modsecurity_request_read(ngx_http_request_t *r)
4545
ngx_int_t
4646
ngx_http_modsecurity_access_handler(ngx_http_request_t *r)
4747
{
48-
#if 1
48+
4949
ngx_pool_t *old_pool;
5050
ngx_http_modsecurity_ctx_t *ctx;
5151
ngx_http_modsecurity_conf_t *mcf;
5252

53-
dd("catching a new _access_ phase handler");
54-
5553
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
56-
if (mcf == NULL || mcf->enable != 1)
57-
{
54+
if (mcf == NULL || mcf->enable != 1) {
5855
dd("ModSecurity not enabled... returning");
5956
return NGX_DECLINED;
6057
}
58+
59+
/*
60+
if (r->method != NGX_HTTP_GET &&
61+
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
62+
dd("ModSecurity is not ready to deal with anything different from " \
63+
"POST, GET or HEAD");
64+
return NGX_DECLINED;
65+
}
66+
*/
67+
68+
dd("catching a new _rewrite_ phase handler");
69+
70+
ctx = ngx_http_modsecurity_get_module_ctx(r);
71+
72+
dd("recovering ctx: %p", ctx);
73+
74+
if (ctx == NULL)
75+
{
76+
int ret = 0;
77+
78+
ngx_connection_t *connection = r->connection;
79+
/**
80+
* FIXME: We may want to use struct sockaddr instead of addr_text.
81+
*
82+
*/
83+
ngx_str_t addr_text = connection->addr_text;
84+
85+
ctx = ngx_http_modsecurity_create_ctx(r);
86+
87+
dd("ctx was NULL, creating new context: %p", ctx);
88+
89+
if (ctx == NULL) {
90+
dd("ctx still null; Nothing we can do, returning an error.");
91+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
92+
}
93+
94+
/**
95+
* FIXME: Check if it is possible to hook on nginx on a earlier phase.
96+
*
97+
* At this point we are doing an late connection process. Maybe
98+
* we have to hook into NGX_HTTP_FIND_CONFIG_PHASE, it seems to be the
99+
* erliest phase that nginx allow us to attach those kind of hooks.
100+
*
101+
*/
102+
int client_port = ngx_inet_get_port(connection->sockaddr);
103+
int server_port = ngx_inet_get_port(connection->local_sockaddr);
104+
105+
const char *client_addr = ngx_str_to_char(addr_text, r->pool);
106+
if (client_addr == (char*)-1) {
107+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
108+
}
109+
110+
#if defined(MODSECURITY_CHECK_VERSION)
111+
#if MODSECURITY_VERSION_NUM >= 30130100
112+
ngx_str_t hostname;
113+
hostname.len = 0;
114+
// first check if Nginx received a Host header and it's usable
115+
// (i.e. not empty)
116+
// if yes, we can use that
117+
if (r->headers_in.server.len > 0) {
118+
hostname.len = r->headers_in.server.len;
119+
hostname.data = r->headers_in.server.data;
120+
}
121+
else {
122+
// otherwise we try to use the server config, namely the
123+
// server_name $SERVER_NAME
124+
// directive
125+
// for eg. in default config, server_name is "_"
126+
// possible all requests without a Host header will be
127+
// handled by this server block
128+
ngx_http_core_srv_conf_t *cscf;
129+
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
130+
if (cscf->server_name.len > 0) {
131+
hostname.len = cscf->server_name.len;
132+
hostname.data = cscf->server_name.data;
133+
}
134+
}
135+
if (hostname.len > 0) {
136+
const char *host_name = ngx_str_to_char(hostname, r->pool);
137+
if (host_name == (char*)-1 || host_name == NULL) {
138+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
139+
}
140+
else {
141+
// set the hostname in the transaction
142+
// this function is only available in ModSecurity 3.0.13 and later
143+
msc_set_request_hostname(ctx->modsec_transaction, (const unsigned char *)host_name);
144+
}
145+
}
146+
#endif
147+
#endif
148+
149+
ngx_str_t s;
150+
u_char addr[NGX_SOCKADDR_STRLEN];
151+
s.len = NGX_SOCKADDR_STRLEN;
152+
s.data = addr;
153+
if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
154+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
155+
}
156+
157+
const char *server_addr = ngx_str_to_char(s, r->pool);
158+
if (server_addr == (char*)-1) {
159+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
160+
}
161+
162+
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
163+
ret = msc_process_connection(ctx->modsec_transaction,
164+
client_addr, client_port,
165+
server_addr, server_port);
166+
ngx_http_modsecurity_pcre_malloc_done(old_pool);
167+
if (ret != 1){
168+
dd("Was not able to extract connection information.");
169+
}
170+
/**
171+
*
172+
* FIXME: Check how we can finalize a request without crash nginx.
173+
*
174+
* I don't think nginx is expecting to finalize a request at that
175+
* point as it seems that it clean the ngx_http_request_t information
176+
* and try to use it later.
177+
*
178+
*/
179+
dd("Processing intervention with the connection information filled in");
180+
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
181+
if (ret > 0) {
182+
ctx->intervention_triggered = 1;
183+
return ret;
184+
}
185+
186+
const char *http_version;
187+
switch (r->http_version) {
188+
case NGX_HTTP_VERSION_9 :
189+
http_version = "0.9";
190+
break;
191+
case NGX_HTTP_VERSION_10 :
192+
http_version = "1.0";
193+
break;
194+
case NGX_HTTP_VERSION_11 :
195+
http_version = "1.1";
196+
break;
197+
#if defined(nginx_version) && nginx_version >= 1009005
198+
case NGX_HTTP_VERSION_20 :
199+
http_version = "2.0";
200+
break;
201+
#endif
202+
default :
203+
http_version = ngx_str_to_char(r->http_protocol, r->pool);
204+
if (http_version == (char*)-1) {
205+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
206+
}
207+
if ((http_version != NULL) && (strlen(http_version) > 5) && (!strncmp("HTTP/", http_version, 5))) {
208+
http_version += 5;
209+
} else {
210+
http_version = "1.0";
211+
}
212+
break;
213+
}
214+
215+
const char *n_uri = ngx_str_to_char(r->unparsed_uri, r->pool);
216+
const char *n_method = ngx_str_to_char(r->method_name, r->pool);
217+
if (n_uri == (char*)-1 || n_method == (char*)-1) {
218+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
219+
}
220+
if (n_uri == NULL) {
221+
dd("uri is of length zero");
222+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
223+
}
224+
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
225+
msc_process_uri(ctx->modsec_transaction, n_uri, n_method, http_version);
226+
ngx_http_modsecurity_pcre_malloc_done(old_pool);
227+
228+
dd("Processing intervention with the transaction information filled in (uri, method and version)");
229+
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
230+
if (ret > 0) {
231+
ctx->intervention_triggered = 1;
232+
return ret;
233+
}
234+
235+
/**
236+
* Since incoming request headers are already in place, lets send it to ModSecurity
237+
*
238+
*/
239+
ngx_list_part_t *part = &r->headers_in.headers.part;
240+
ngx_table_elt_t *data = part->elts;
241+
ngx_uint_t i = 0;
242+
for (i = 0 ; /* void */ ; i++) {
243+
if (i >= part->nelts) {
244+
if (part->next == NULL) {
245+
break;
246+
}
247+
248+
part = part->next;
249+
data = part->elts;
250+
i = 0;
251+
}
252+
253+
/**
254+
* By using u_char (utf8_t) I believe nginx is hoping to deal
255+
* with utf8 strings.
256+
* Casting those into to unsigned char * in order to pass
257+
* it to ModSecurity, it will handle with those later.
258+
*
259+
*/
260+
261+
dd("Adding request header: %.*s with value %.*s", (int)data[i].key.len, data[i].key.data, (int) data[i].value.len, data[i].value.data);
262+
msc_add_n_request_header(ctx->modsec_transaction,
263+
(const unsigned char *) data[i].key.data,
264+
data[i].key.len,
265+
(const unsigned char *) data[i].value.data,
266+
data[i].value.len);
267+
}
268+
269+
/**
270+
* Since ModSecurity already knew about all headers, i guess it is safe
271+
* to process this information.
272+
*/
273+
274+
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
275+
msc_process_request_headers(ctx->modsec_transaction);
276+
ngx_http_modsecurity_pcre_malloc_done(old_pool);
277+
dd("Processing intervention with the request headers information filled in");
278+
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
279+
if (r->error_page) {
280+
return NGX_DECLINED;
281+
}
282+
if (ret > 0) {
283+
ctx->intervention_triggered = 1;
284+
return ret;
285+
}
286+
}
287+
288+
#if 1
289+
61290
/*
62291
* FIXME:
63292
* In order to perform some tests, let's accept everything.

src/ngx_http_modsecurity_module.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,6 @@ ngx_module_t ngx_http_modsecurity_module = {
551551
static ngx_int_t
552552
ngx_http_modsecurity_init(ngx_conf_t *cf)
553553
{
554-
ngx_http_handler_pt *h_rewrite;
555554
ngx_http_handler_pt *h_access;
556555
ngx_http_handler_pt *h_log;
557556
ngx_http_core_main_conf_t *cmcf;
@@ -569,21 +568,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
569568
* ngx_http_limit_*_module to run
570569
*
571570
*/
572-
h_rewrite = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
573-
if (h_rewrite == NULL)
574-
{
575-
dd("Not able to create a new NGX_HTTP_ACCESS_PHASE handle");
576-
return NGX_ERROR;
577-
}
578-
*h_rewrite = ngx_http_modsecurity_rewrite_handler;
579571

580-
/**
581-
*
582-
* Processing the request body on the access phase.
583-
*
584-
* TODO: check if hook into separated phases is the best thing to do.
585-
*
586-
*/
587572
h_access = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
588573
if (h_access == NULL)
589574
{
@@ -592,6 +577,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
592577
}
593578
*h_access = ngx_http_modsecurity_access_handler;
594579

580+
595581
/**
596582
* Process the log phase.
597583
*

0 commit comments

Comments
 (0)