22
22
23
23
#include "ngx_http_modsecurity_common.h"
24
24
25
+ void
26
+ ngx_http_modsecurity_request_read (ngx_http_request_t * r )
27
+ {
28
+ ngx_http_modsecurity_ctx_t * ctx ;
29
+
30
+ ctx = ngx_http_modsecurity_get_module_ctx (r );
31
+
32
+ #if defined(nginx_version ) && nginx_version >= 8011
33
+ r -> main -> count -- ;
34
+ #endif
35
+
36
+ if (ctx -> waiting_more_body )
37
+ {
38
+ ctx -> waiting_more_body = 0 ;
39
+ r -> write_event_handler = ngx_http_core_run_phases ;
40
+ ngx_http_core_run_phases (r );
41
+ }
42
+ }
43
+
44
+
25
45
ngx_int_t
26
- ngx_http_modsecurity_rewrite_handler (ngx_http_request_t * r )
46
+ ngx_http_modsecurity_access_handler (ngx_http_request_t * r )
27
47
{
48
+
28
49
ngx_pool_t * old_pool ;
29
50
ngx_http_modsecurity_ctx_t * ctx ;
30
51
ngx_http_modsecurity_conf_t * mcf ;
@@ -44,7 +65,7 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
44
65
}
45
66
*/
46
67
47
- dd ("catching a new _rewrite_ phase handler" );
68
+ dd ("catching a new _access_ phase handler" );
48
69
49
70
ctx = ngx_http_modsecurity_get_module_ctx (r );
50
71
@@ -264,6 +285,181 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
264
285
}
265
286
}
266
287
288
+ #if 1
289
+
290
+ /*
291
+ * FIXME:
292
+ * In order to perform some tests, let's accept everything.
293
+ *
294
+ if (r->method != NGX_HTTP_GET &&
295
+ r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
296
+ dd("ModSecurity is not ready to deal with anything different from " \
297
+ "POST, GET or HEAD");
298
+ return NGX_DECLINED;
299
+ }
300
+ */
301
+
302
+ ctx = ngx_http_modsecurity_get_module_ctx (r );
303
+
304
+ dd ("recovering ctx: %p" , ctx );
267
305
306
+ if (ctx == NULL )
307
+ {
308
+ dd ("ctx is null; Nothing we can do, returning an error." );
309
+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
310
+ }
311
+
312
+ if (ctx -> request_body_processed ) {
313
+ // should we use r->internal or r->filter_finalize?
314
+ return NGX_DECLINED ;
315
+ }
316
+
317
+ if (ctx -> intervention_triggered ) {
318
+ return NGX_DECLINED ;
319
+ }
320
+
321
+ if (ctx -> waiting_more_body == 1 )
322
+ {
323
+ dd ("waiting for more data before proceed. / count: %d" ,
324
+ r -> main -> count );
325
+
326
+ return NGX_DONE ;
327
+ }
328
+
329
+ if (ctx -> body_requested == 0 )
330
+ {
331
+ ngx_int_t rc = NGX_OK ;
332
+
333
+ ctx -> body_requested = 1 ;
334
+
335
+ dd ("asking for the request body, if any. Count: %d" ,
336
+ r -> main -> count );
337
+ /**
338
+ * TODO: Check if there is any benefit to use request_body_in_single_buf set to 1.
339
+ *
340
+ * saw some module using this request_body_in_single_buf
341
+ * but not sure what exactly it does, same for the others options below.
342
+ *
343
+ * r->request_body_in_single_buf = 1;
344
+ */
345
+ r -> request_body_in_single_buf = 1 ;
346
+ r -> request_body_in_persistent_file = 1 ;
347
+ if (!r -> request_body_in_file_only ) {
348
+ // If the above condition fails, then the flag below will have been
349
+ // set correctly elsewhere. We need to set the flag here for other
350
+ // conditions (client_body_in_file_only not used but
351
+ // client_body_buffer_size is)
352
+ r -> request_body_in_clean_file = 1 ;
353
+ }
354
+
355
+ rc = ngx_http_read_client_request_body (r ,
356
+ ngx_http_modsecurity_request_read );
357
+ if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE ) {
358
+ #if (nginx_version < 1002006 ) || \
359
+ (nginx_version >= 1003000 && nginx_version < 1003009 )
360
+ r -> main -> count -- ;
361
+ #endif
362
+
363
+ return rc ;
364
+ }
365
+ if (rc == NGX_AGAIN )
366
+ {
367
+ dd ("nginx is asking us to wait for more data." );
368
+
369
+ ctx -> waiting_more_body = 1 ;
370
+ return NGX_DONE ;
371
+ }
372
+ }
373
+
374
+ if (ctx -> waiting_more_body == 0 )
375
+ {
376
+ int ret = 0 ;
377
+ int already_inspected = 0 ;
378
+
379
+ dd ("request body is ready to be processed" );
380
+
381
+ r -> write_event_handler = ngx_http_core_run_phases ;
382
+
383
+ ngx_chain_t * chain = r -> request_body -> bufs ;
384
+
385
+ /**
386
+ * TODO: Speed up the analysis by sending chunk while they arrive.
387
+ *
388
+ * Notice that we are waiting for the full request body to
389
+ * start to process it, it may not be necessary. We may send
390
+ * the chunks to ModSecurity while nginx keep calling this
391
+ * function.
392
+ */
393
+
394
+ if (r -> request_body -> temp_file != NULL ) {
395
+ ngx_str_t file_path = r -> request_body -> temp_file -> file .name ;
396
+ const char * file_name = ngx_str_to_char (file_path , r -> pool );
397
+ if (file_name == (char * )-1 ) {
398
+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
399
+ }
400
+ /*
401
+ * Request body was saved to a file, probably we don't have a
402
+ * copy of it in memory.
403
+ */
404
+ dd ("request body inspection: file -- %s" , file_name );
405
+
406
+ msc_request_body_from_file (ctx -> modsec_transaction , file_name );
407
+
408
+ already_inspected = 1 ;
409
+ } else {
410
+ dd ("inspection request body in memory." );
411
+ }
412
+
413
+ while (chain && !already_inspected )
414
+ {
415
+ u_char * data = chain -> buf -> pos ;
416
+
417
+ msc_append_request_body (ctx -> modsec_transaction , data ,
418
+ chain -> buf -> last - data );
419
+
420
+ if (chain -> buf -> last_buf ) {
421
+ break ;
422
+ }
423
+ chain = chain -> next ;
424
+
425
+ /* XXX: chains are processed one-by-one, maybe worth to pass all chains and then call intervention() ? */
426
+
427
+ /**
428
+ * ModSecurity may perform stream inspection on this buffer,
429
+ * it may ask for a intervention in consequence of that.
430
+ *
431
+ */
432
+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 0 );
433
+ if (ret > 0 ) {
434
+ return ret ;
435
+ }
436
+ }
437
+
438
+ /**
439
+ * At this point, all the request body was sent to ModSecurity
440
+ * and we want to make sure that all the request body inspection
441
+ * happened; consequently we have to check if ModSecurity have
442
+ * returned any kind of intervention.
443
+ */
444
+
445
+ /* XXX: once more -- is body can be modified ? content-length need to be adjusted ? */
446
+
447
+ old_pool = ngx_http_modsecurity_pcre_malloc_init (r -> pool );
448
+ msc_process_request_body (ctx -> modsec_transaction );
449
+ ctx -> request_body_processed = 1 ;
450
+ ngx_http_modsecurity_pcre_malloc_done (old_pool );
451
+
452
+ ret = ngx_http_modsecurity_process_intervention (ctx -> modsec_transaction , r , 0 );
453
+ if (r -> error_page ) {
454
+ return NGX_DECLINED ;
455
+ }
456
+ if (ret > 0 ) {
457
+ return ret ;
458
+ }
459
+ }
460
+
461
+ dd ("Nothing to add on the body inspection, reclaiming a NGX_DECLINED" );
462
+ #endif
268
463
return NGX_DECLINED ;
269
464
}
465
+
0 commit comments