30
30
#endif
31
31
32
32
#define NOTE_NGINX_REQUEST_CTX "nginx-ctx"
33
+ #define WAF_DETECTION_MODE 0
34
+ #define WAF_PREVENTION_MODE 1
33
35
34
36
typedef struct {
35
37
ngx_flag_t enable ;
@@ -52,6 +54,8 @@ typedef struct {
52
54
53
55
int thread_running ;
54
56
int status_code ;
57
+ ngx_time_t * start_time ;
58
+ ngx_msec_int_t azwaf_latency ;
55
59
} ngx_http_modsecurity_ctx_t ;
56
60
57
61
#define STATUS_CODE_NOT_SET -1000
@@ -63,7 +67,9 @@ typedef struct {
63
67
/*
64
68
** Module's registred function/handlers.
65
69
*/
66
- static ngx_int_t ngx_http_modsecurity_handler (ngx_http_request_t * r );
70
+ static ngx_int_t ngx_http_modsecurity_handler (ngx_http_request_t * r , ngx_http_modsecurity_loc_conf_t * cf ,
71
+ ngx_http_modsecurity_ctx_t * ctx );
72
+ static ngx_int_t ngx_http_modsecurity_handler_with_timer (ngx_http_request_t * r );
67
73
static ngx_int_t ngx_http_modsecurity_preconfiguration (ngx_conf_t * cf );
68
74
static ngx_int_t ngx_http_modsecurity_init (ngx_conf_t * cf );
69
75
static ngx_int_t ngx_http_modsecurity_init_process (ngx_cycle_t * cycle );
@@ -72,10 +78,28 @@ static char *ngx_http_modsecurity_merge_loc_conf(ngx_conf_t *cf, void *parent, v
72
78
static char * ngx_http_modsecurity_config (ngx_conf_t * cf , ngx_command_t * cmd , void * conf );
73
79
static char * ngx_http_modsecurity_enable (ngx_conf_t * cf , ngx_command_t * cmd , void * conf );
74
80
75
- static ngx_http_modsecurity_ctx_t * ngx_http_modsecurity_create_ctx (ngx_http_request_t * r );
81
+ static ngx_http_modsecurity_ctx_t * ngx_http_modsecurity_create_ctx (ngx_http_request_t * r , ngx_time_t * start_time );
76
82
static int ngx_http_modsecurity_drop_action (request_rec * r );
77
83
static void ngx_http_modsecurity_terminate (ngx_cycle_t * cycle );
78
84
static void ngx_http_modsecurity_cleanup (void * data );
85
+ static ngx_int_t ngx_http_calculate_modsec_latency (ngx_http_request_t * r , ngx_http_modsecurity_ctx_t * ctx );
86
+ static void store_azwaf_latency (ngx_http_modsecurity_ctx_t * ctx , ngx_http_variable_value_t * waf_latency_var );
87
+
88
+ static ngx_int_t ngx_http_modsecurity_set_modsec_latency (ngx_http_request_t * r ,
89
+ ngx_http_variable_value_t * v , ngx_msec_int_t modsec_latency );
90
+ static void ngx_http_modsecurity_set_modsec_mode (ngx_http_request_t * r ,
91
+ ngx_http_variable_value_t * v , ngx_uint_t modsec_mode );
92
+ static ngx_int_t ngx_http_variable_get_modsec_latency (ngx_http_request_t * r ,
93
+ ngx_http_variable_value_t * v , uintptr_t data );
94
+ static ngx_int_t ngx_http_variable_get_modsec_mode (ngx_http_request_t * r ,
95
+ ngx_http_variable_value_t * v , uintptr_t data );
96
+
97
+ static ngx_str_t waf_latency_varname = ngx_string ("waf_latency" );
98
+ static ngx_uint_t waf_latency_index ;
99
+ static ngx_str_t waf_mode_varname = ngx_string ("waf_mode" );
100
+ static ngx_uint_t waf_mode_index ;
101
+ static ngx_str_t modsec_mode_prev = ngx_string ("Prevention" );
102
+ static ngx_str_t modsec_mode_detect = ngx_string ("Detection" );
79
103
80
104
static ngx_str_t thread_pool_name = ngx_string ("default" );
81
105
@@ -160,6 +184,16 @@ ngx_module_t ngx_http_modsecurity = {
160
184
};
161
185
162
186
187
+ static ngx_http_variable_t ngx_http_modsecurity_vars [] = {
188
+ { ngx_string ("waf_latency" ), NULL ,
189
+ ngx_http_variable_get_modsec_latency ,
190
+ 0 , NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_CHANGEABLE , 0 },
191
+ { ngx_string ("waf_mode" ), NULL ,
192
+ ngx_http_variable_get_modsec_mode ,
193
+ 0 , NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_CHANGEABLE , 0 },
194
+ ngx_http_null_variable
195
+ };
196
+
163
197
static ngx_http_upstream_t ngx_http_modsecurity_upstream ;
164
198
165
199
static inline char *
@@ -539,9 +573,29 @@ modsec_pcre_free(void *ptr)
539
573
static server_rec * modsec_server = NULL ;
540
574
static ngx_http_modsecurity_config_cache_t * config_cache = NULL ;
541
575
576
+ static ngx_int_t
577
+ ngx_http_modsecurity_add_variables (ngx_conf_t * cf )
578
+ {
579
+ ngx_http_variable_t * var , * v ;
580
+
581
+ for (v = ngx_http_modsecurity_vars ; v -> name .len ; v ++ ) {
582
+ var = ngx_http_add_variable (cf , & v -> name , v -> flags );
583
+ if (var == NULL ) {
584
+ return NGX_ERROR ;
585
+ }
586
+
587
+ var -> get_handler = v -> get_handler ;
588
+ var -> data = v -> data ;
589
+ }
590
+
591
+ return NGX_OK ;
592
+ }
593
+
542
594
static ngx_int_t
543
595
ngx_http_modsecurity_preconfiguration (ngx_conf_t * cf )
544
596
{
597
+ ngx_http_modsecurity_add_variables (cf );
598
+
545
599
/* XXX: temporary hack, nginx uses pcre as well and hijacks these two */
546
600
pcre_malloc = modsec_pcre_malloc ;
547
601
pcre_free = modsec_pcre_free ;
@@ -601,7 +655,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
601
655
if (h == NULL ) {
602
656
return NGX_ERROR ;
603
657
}
604
- * h = ngx_http_modsecurity_handler ;
658
+ * h = ngx_http_modsecurity_handler_with_timer ;
605
659
606
660
ngx_memzero (& ngx_http_modsecurity_upstream , sizeof (ngx_http_upstream_t ));
607
661
ngx_http_modsecurity_upstream .cacheable = 1 ;
@@ -618,6 +672,9 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
618
672
extern pthread_mutex_t msc_pregcomp_ex_mtx ;
619
673
pthread_mutex_init (& msc_pregcomp_ex_mtx , NULL );
620
674
675
+ waf_latency_index = (ngx_uint_t )ngx_http_get_variable_index (cf , & waf_latency_varname );
676
+ waf_mode_index = (ngx_uint_t )ngx_http_get_variable_index (cf , & waf_mode_varname );
677
+
621
678
#ifdef WAF_JSON_LOGGING_ENABLE
622
679
int result = init_appgw_rules_id_hash ();
623
680
if (result ) {
@@ -848,19 +905,49 @@ ngx_http_modsecurity_body_handler(ngx_http_request_t *r)
848
905
ngx_http_core_run_phases (r );
849
906
}
850
907
908
+ static void
909
+ store_azwaf_latency (ngx_http_modsecurity_ctx_t * ctx , ngx_http_variable_value_t * waf_latency_var )
910
+ {
911
+ int sec , ms ;
912
+ char * token = strtok ((char * )waf_latency_var -> data , "." );
913
+ sec = atoi (token );
914
+ token = strtok (NULL , " " );
915
+ ms = atoi (token );
916
+ ctx -> azwaf_latency = sec * 1000 + ms ;
917
+ }
918
+
919
+ static ngx_int_t
920
+ ngx_http_calculate_modsec_latency (ngx_http_request_t * r , ngx_http_modsecurity_ctx_t * ctx )
921
+ {
922
+ ngx_time_t * end_time ;
923
+ ngx_msec_int_t ms ;
924
+ ngx_time_update ();
925
+ end_time = ngx_timeofday ();
926
+
927
+ ms = (ngx_msec_int_t )
928
+ ((end_time -> sec - ctx -> start_time -> sec ) * 1000 + (end_time -> msec - ctx -> start_time -> msec ));
929
+ ms = ngx_max (ms , 0 );
930
+
931
+ // Add azwaf latency if we are in hybrid mode
932
+ if (ctx -> azwaf_latency != 0 ) {
933
+ ms += ctx -> azwaf_latency ;
934
+ }
935
+ ngx_http_variable_value_t * modsec_latency_var = ngx_http_get_indexed_variable (r , waf_latency_index );
936
+ return ngx_http_modsecurity_set_modsec_latency (r , modsec_latency_var , ms );
937
+ }
851
938
852
939
/*
853
940
** [ENTRY POINT] does : this function called by nginx from the request handler
941
+ * Calculate the modsec latency in this function and invoke the main handler.
854
942
*/
855
943
static ngx_int_t
856
- ngx_http_modsecurity_handler (ngx_http_request_t * r )
944
+ ngx_http_modsecurity_handler_with_timer (ngx_http_request_t * r )
857
945
{
858
946
ngx_http_modsecurity_loc_conf_t * cf ;
859
- ngx_http_modsecurity_ctx_t * ctx ;
860
- ngx_int_t rc ;
947
+ ngx_http_modsecurity_ctx_t * ctx ;
948
+ ngx_int_t ret , modsec_latency_ret ;
861
949
862
950
cf = ngx_http_get_module_loc_conf (r , ngx_http_modsecurity );
863
-
864
951
/* Process only main request */
865
952
if (r != r -> main || !cf -> enable ) {
866
953
return NGX_DECLINED ;
@@ -871,15 +958,61 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
871
958
ngx_http_get_variable (r , & azwaf_processing_result_var , azwaf_processing_result_key );
872
959
if (azwaf_processing_result != NULL && !azwaf_processing_result -> not_found ) {
873
960
if (ngx_strncasecmp (
874
- azwaf_processing_result -> data ,
875
- azwaf_action_allow .data ,
876
- MIN (azwaf_processing_result -> len , azwaf_action_allow .len )) == 0 ) {
961
+ azwaf_processing_result -> data ,
962
+ azwaf_action_allow .data ,
963
+ MIN (azwaf_processing_result -> len , azwaf_action_allow .len )) == 0 ) {
877
964
878
965
ngx_log_error (NGX_LOG_INFO , r -> connection -> log , 0 , "The request is allowed by AzWAF, skip ModSecurity processing" );
879
966
return NGX_DECLINED ;
880
967
}
881
968
}
882
969
970
+ // Get module request context or create if not yet created
971
+ ctx = ngx_http_get_module_ctx (r , ngx_http_modsecurity );
972
+ if (ctx == NULL ) {
973
+ ngx_time_update ();
974
+ ctx = ngx_http_modsecurity_create_ctx (r , ngx_timeofday ());
975
+ if (ctx == NULL ) {
976
+ return NGX_HTTP_INTERNAL_SERVER_ERROR ;
977
+ }
978
+
979
+ ngx_http_set_ctx (r , ctx , ngx_http_modsecurity );
980
+
981
+ ngx_http_variable_value_t * waf_latency_var = ngx_http_get_indexed_variable (r , waf_latency_index );
982
+ ctx -> azwaf_latency = 0 ;
983
+
984
+ // We are in hybrid mode, save the latency from azwaf to add later to the waf_latency.
985
+ if (waf_latency_var -> data != NULL ) {
986
+ store_azwaf_latency (ctx , waf_latency_var );
987
+ }
988
+
989
+ ngx_http_variable_value_t * modsec_mode_var = ngx_http_get_indexed_variable (r , waf_mode_index );
990
+ if (cf -> config -> is_enabled == MODSEC_DETECTION_ONLY ) {
991
+ ngx_http_modsecurity_set_modsec_mode (r , modsec_mode_var , WAF_DETECTION_MODE );
992
+ }
993
+ else {
994
+ ngx_http_modsecurity_set_modsec_mode (r , modsec_mode_var , WAF_PREVENTION_MODE );
995
+ }
996
+ }
997
+
998
+ // Main modsec handler
999
+ ret = ngx_http_modsecurity_handler (r , cf , ctx );
1000
+
1001
+ // We return failure only if memory allocation fails for latency variable in calculating metric
1002
+ modsec_latency_ret = ngx_http_calculate_modsec_latency (r , ctx );
1003
+ if (modsec_latency_ret != NGX_OK ) {
1004
+ ngx_log_error (NGX_LOG_INFO , r -> connection -> log , 0 , "modSecurity: latency metric memory allocation failed" );
1005
+ return modsec_latency_ret ;
1006
+ }
1007
+ return ret ;
1008
+ }
1009
+
1010
+ static ngx_int_t
1011
+ ngx_http_modsecurity_handler (ngx_http_request_t * r , ngx_http_modsecurity_loc_conf_t * cf ,
1012
+ ngx_http_modsecurity_ctx_t * ctx )
1013
+ {
1014
+ ngx_int_t rc ;
1015
+
883
1016
// Read body if not yet read
884
1017
if (!r -> request_body ) {
885
1018
rc = ngx_http_read_client_request_body (r , ngx_http_modsecurity_body_handler );
@@ -893,16 +1026,6 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
893
1026
894
1027
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 , "modSecurity: handler" );
895
1028
896
- // Get module request context or create if not yet created
897
- ctx = ngx_http_get_module_ctx (r , ngx_http_modsecurity );
898
- if (ctx == NULL ) {
899
- ctx = ngx_http_modsecurity_create_ctx (r );
900
- if (ctx == NULL ) {
901
- return NGX_HTTP_INTERNAL_SERVER_ERROR ;
902
- }
903
-
904
- ngx_http_set_ctx (r , ctx , ngx_http_modsecurity );
905
- }
906
1029
907
1030
#ifdef WAF_JSON_LOGGING_ENABLE
908
1031
modsecReopenLogfileIfNeeded (ctx -> req );
@@ -932,7 +1055,7 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
932
1055
#define TXID_SIZE 25
933
1056
934
1057
static ngx_http_modsecurity_ctx_t *
935
- ngx_http_modsecurity_create_ctx (ngx_http_request_t * r )
1058
+ ngx_http_modsecurity_create_ctx (ngx_http_request_t * r , ngx_time_t * start_time )
936
1059
{
937
1060
ngx_http_modsecurity_loc_conf_t * cf ;
938
1061
ngx_pool_cleanup_t * cln ;
@@ -961,6 +1084,7 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
961
1084
cln -> data = ctx ;
962
1085
963
1086
ctx -> r = r ;
1087
+ ctx -> start_time = start_time ;
964
1088
965
1089
if (r -> connection -> requests == 0 || ctx -> connection == NULL ) {
966
1090
@@ -1136,3 +1260,58 @@ ngx_http_modsecurity_drop_action(request_rec *r)
1136
1260
ctx -> r -> connection -> error = 1 ;
1137
1261
return 0 ;
1138
1262
}
1263
+
1264
+ static ngx_int_t
1265
+ ngx_http_variable_get_modsec_latency (ngx_http_request_t * r ,
1266
+ ngx_http_variable_value_t * v , uintptr_t data )
1267
+ {
1268
+ return NGX_OK ;
1269
+ }
1270
+
1271
+ static ngx_int_t
1272
+ ngx_http_variable_get_modsec_mode (ngx_http_request_t * r ,
1273
+ ngx_http_variable_value_t * v , uintptr_t data )
1274
+ {
1275
+ return NGX_OK ;
1276
+ }
1277
+
1278
+ static ngx_int_t
1279
+ ngx_http_modsecurity_set_modsec_latency (ngx_http_request_t * r ,
1280
+ ngx_http_variable_value_t * v , ngx_msec_int_t modsec_latency )
1281
+ {
1282
+ if (v -> data == NULL ) {
1283
+ v -> data = ngx_pnalloc (r -> pool , NGX_TIME_T_LEN + 4 );
1284
+ if (v -> data == NULL ) {
1285
+ return NGX_ERROR ;
1286
+ }
1287
+ }
1288
+
1289
+ v -> len = ngx_sprintf (v -> data , "%T.%03M" , (time_t )(modsec_latency ) / 1000 , modsec_latency % 1000 ) - v -> data ;
1290
+ v -> valid = 1 ;
1291
+ v -> no_cacheable = 0 ;
1292
+ v -> not_found = 0 ;
1293
+
1294
+ return NGX_OK ;
1295
+ }
1296
+
1297
+ static void
1298
+ ngx_http_modsecurity_set_modsec_mode (ngx_http_request_t * r ,
1299
+ ngx_http_variable_value_t * v , ngx_uint_t modsec_mode )
1300
+ {
1301
+ u_char * p ;
1302
+ size_t len ;
1303
+ if (modsec_mode == WAF_DETECTION_MODE ) {
1304
+ len = modsec_mode_detect .len ;
1305
+ p = modsec_mode_detect .data ;
1306
+ }
1307
+ else {
1308
+ len = modsec_mode_prev .len ;
1309
+ p = modsec_mode_prev .data ;
1310
+ }
1311
+
1312
+ v -> len = len ;
1313
+ v -> valid = 1 ;
1314
+ v -> no_cacheable = 0 ;
1315
+ v -> not_found = 0 ;
1316
+ v -> data = p ;
1317
+ }
0 commit comments