@@ -520,6 +520,26 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) {
520
520
}
521
521
522
522
#ifdef WITH_JSON_LOGGING
523
+ /**
524
+ * Write detailed information about performance metrics into a JSON generator
525
+ */
526
+ static void format_performance_variables_json (modsec_rec * msr , yajl_gen g ) {
527
+ yajl_string (g , "stopwatch" );
528
+ yajl_gen_map_open (g );
529
+
530
+ yajl_kv_int (g , "p1" , msr -> time_phase1 );
531
+ yajl_kv_int (g , "p2" , msr -> time_phase2 );
532
+ yajl_kv_int (g , "p3" , msr -> time_phase3 );
533
+ yajl_kv_int (g , "p4" , msr -> time_phase4 );
534
+ yajl_kv_int (g , "p5" , msr -> time_phase5 );
535
+ yajl_kv_int (g , "sr" , msr -> time_storage_read );
536
+ yajl_kv_int (g , "sw" , msr -> time_storage_write );
537
+ yajl_kv_int (g , "l" , msr -> time_logging );
538
+ yajl_kv_int (g , "gc" , msr -> time_gc );
539
+
540
+ yajl_gen_map_close (g );
541
+ }
542
+
523
543
/**
524
544
* Write detailed information about a rule and its actionset into a JSON generator
525
545
*/
@@ -558,6 +578,9 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g)
558
578
yajl_kv_int (g , "phase" , rule -> actionset -> phase );
559
579
}
560
580
yajl_kv_bool (g , "is_chained" , rule -> actionset -> is_chained );
581
+ if (rule -> actionset -> is_chained && (rule -> chain_starter == NULL )) {
582
+ yajl_kv_bool (g , "chain_starter" , 1 );
583
+ }
561
584
yajl_gen_map_close (g );
562
585
563
586
yajl_string (g , "operator" );
@@ -602,6 +625,7 @@ void sec_audit_logger(modsec_rec *msr) {
602
625
int arg_min , arg_max , sanitize_matched ;
603
626
#ifdef WITH_JSON_LOGGING
604
627
yajl_gen g ;
628
+ int been_opened = 0 ; // helper flag for conditionally opening maps
605
629
#endif
606
630
607
631
#ifndef WITH_JSON_LOGGING
@@ -704,7 +728,7 @@ void sec_audit_logger(modsec_rec *msr) {
704
728
g = yajl_gen_alloc (NULL );
705
729
706
730
/**
707
- * don't pretty print JSON by default
731
+ * don't pretty print JSON
708
732
* this is harder to eyeball but much easier to parse programmatically
709
733
*/
710
734
yajl_gen_config (g , yajl_gen_beautify , 0 );
@@ -771,16 +795,14 @@ void sec_audit_logger(modsec_rec *msr) {
771
795
for (i = 0 ; i < arr -> nelts ; i ++ ) {
772
796
sanitized_partial = 0 ;
773
797
sanitize_matched = 0 ;
774
- #ifndef WITH_JSON_LOGGING
775
798
text = apr_psprintf (msr -> mp , "%s: %s\n" , te [i ].key , te [i ].val );
776
- #else
799
+ #ifdef WITH_JSON_LOGGING
777
800
// write the key no matter what
778
801
// since sanitization only occurs on the value
779
802
yajl_string (g , te [i ].key );
780
803
#endif
781
804
if (apr_table_get (msr -> request_headers_to_sanitize , te [i ].key ) != NULL ) {
782
805
buf = apr_psprintf (msr -> mp , "%s" ,text + strlen (te [i ].key )+ 2 );
783
-
784
806
for ( k = 0 ; k < tarr_pattern -> nelts ; k ++ ) {
785
807
if (strncmp (telts_pattern [k ].key ,te [i ].key ,strlen (te [i ].key )) == 0 ) {
786
808
mparm = (msc_parm * )telts_pattern [k ].val ;
@@ -818,7 +840,8 @@ void sec_audit_logger(modsec_rec *msr) {
818
840
#ifndef WITH_JSON_LOGGING
819
841
memset (text + strlen (te [i ].key ) + 2 , '*' , strlen (te [i ].val ));
820
842
#else
821
- yajl_string (g , "****" ); // fix this later
843
+ memset (buf , '*' , strlen (buf )); // strlen also includes the appended newline on the header
844
+ yajl_string (g , buf );
822
845
#endif
823
846
}
824
847
}
@@ -827,7 +850,9 @@ void sec_audit_logger(modsec_rec *msr) {
827
850
#else
828
851
// we diverge from the original logic a bit because we always print the key
829
852
// at this no point sanitization had occured, so we just print the value
830
- yajl_string (g , te [i ].val );
853
+ else {
854
+ yajl_string (g , te [i ].val );
855
+ }
831
856
#endif
832
857
}
833
858
#ifdef WITH_JSON_LOGGING
@@ -1025,7 +1050,6 @@ void sec_audit_logger(modsec_rec *msr) {
1025
1050
sec_auditlog_write (msr , text , strlen (text ));
1026
1051
sec_auditlog_write (msr , buffer , strlen (buffer ));
1027
1052
#else
1028
- // this is a key instead 'request', doesn't need an array or map since it's one value
1029
1053
yajl_kv_string (g , "fake_body" , buffer );
1030
1054
#endif
1031
1055
}
@@ -1055,7 +1079,8 @@ void sec_audit_logger(modsec_rec *msr) {
1055
1079
msr -> status_line );
1056
1080
#else
1057
1081
yajl_kv_string (g , "protocol" , msr -> response_protocol );
1058
- yajl_kv_string (g , "status" , msr -> status_line );
1082
+ // as an integer, response status is easier to parse than status_line
1083
+ yajl_kv_int (g , "status" , (int )msr -> response_status );
1059
1084
#endif
1060
1085
} else {
1061
1086
#ifndef WITH_JSON_LOGGING
@@ -1084,9 +1109,8 @@ void sec_audit_logger(modsec_rec *msr) {
1084
1109
for (i = 0 ; i < arr -> nelts ; i ++ ) {
1085
1110
sanitized_partial = 0 ;
1086
1111
sanitize_matched = 0 ;
1087
- #ifndef WITH_JSON_LOGGING
1088
1112
text = apr_psprintf (msr -> mp , "%s: %s\n" , te [i ].key , te [i ].val );
1089
- #else
1113
+ #ifdef WITH_JSON_LOGGING
1090
1114
// write the key no matter what
1091
1115
// since sanitization only occurs on the value
1092
1116
yajl_string (g , te [i ].key );
@@ -1131,7 +1155,8 @@ void sec_audit_logger(modsec_rec *msr) {
1131
1155
#ifndef WITH_JSON_LOGGING
1132
1156
memset (text + strlen (te [i ].key ) + 2 , '*' , strlen (te [i ].val ));
1133
1157
#else
1134
- yajl_string (g , "****" ); // fix this later
1158
+ memset (buf , '*' , strlen (buf ));
1159
+ yajl_string (g , buf );
1135
1160
#endif
1136
1161
}
1137
1162
}
@@ -1140,7 +1165,9 @@ void sec_audit_logger(modsec_rec *msr) {
1140
1165
#else
1141
1166
// we diverge from the original logic a bit because we always print the key
1142
1167
// at this point no sanitization had occured, so we just print the value
1143
- yajl_string (g , te [i ].val );
1168
+ else {
1169
+ yajl_string (g , te [i ].val );
1170
+ }
1144
1171
#endif
1145
1172
}
1146
1173
#ifdef WITH_JSON_LOGGING
@@ -1169,8 +1196,8 @@ void sec_audit_logger(modsec_rec *msr) {
1169
1196
#ifdef WITH_JSON_LOGGING
1170
1197
yajl_gen_map_close (g ); // response top-level key is finished
1171
1198
1172
- yajl_string (g , "data " );
1173
- yajl_gen_map_open (g ); // data top-level key
1199
+ yajl_string (g , "audit_data " );
1200
+ yajl_gen_map_open (g ); // audit_data top-level key
1174
1201
#endif
1175
1202
1176
1203
/* AUDITLOG_PART_TRAILER */
@@ -1184,8 +1211,12 @@ void sec_audit_logger(modsec_rec *msr) {
1184
1211
1185
1212
/* Messages */
1186
1213
#ifdef WITH_JSON_LOGGING
1187
- yajl_string (g , "messages" );
1188
- yajl_gen_array_open (g );
1214
+ been_opened = 0 ;
1215
+ if (msr -> alerts -> nelts > 0 ) {
1216
+ yajl_string (g , "messages" );
1217
+ yajl_gen_array_open (g );
1218
+ been_opened = 1 ;
1219
+ }
1189
1220
#endif
1190
1221
for (i = 0 ; i < msr -> alerts -> nelts ; i ++ ) {
1191
1222
#ifndef WITH_JSON_LOGGING
@@ -1196,13 +1227,19 @@ void sec_audit_logger(modsec_rec *msr) {
1196
1227
#endif
1197
1228
}
1198
1229
#ifdef WITH_JSON_LOGGING
1199
- yajl_gen_array_close (g );
1230
+ if (been_opened == 1 ) {
1231
+ yajl_gen_array_close (g );
1232
+ }
1200
1233
#endif
1201
1234
1202
1235
/* Apache error messages */
1203
1236
#ifdef WITH_JSON_LOGGING
1204
- yajl_string (g , "error_messages" );
1205
- yajl_gen_array_open (g );
1237
+ been_opened = 0 ;
1238
+ if (msr -> error_messages -> nelts > 0 ) {
1239
+ yajl_string (g , "error_messages" );
1240
+ yajl_gen_array_open (g );
1241
+ been_opened = 1 ;
1242
+ }
1206
1243
#endif
1207
1244
for (i = 0 ; i < msr -> error_messages -> nelts ; i ++ ) {
1208
1245
error_message_t * em = (((error_message_t * * )msr -> error_messages -> elts )[i ]);
@@ -1215,7 +1252,9 @@ void sec_audit_logger(modsec_rec *msr) {
1215
1252
#endif
1216
1253
}
1217
1254
#ifdef WITH_JSON_LOGGING
1218
- yajl_gen_array_close (g );
1255
+ if (been_opened == 1 ) {
1256
+ yajl_gen_array_close (g );
1257
+ }
1219
1258
#endif
1220
1259
1221
1260
/* Action */
@@ -1228,6 +1267,7 @@ void sec_audit_logger(modsec_rec *msr) {
1228
1267
yajl_gen_map_open (g );
1229
1268
yajl_kv_bool (g , "intercepted" , 1 );
1230
1269
yajl_kv_int (g , "phase" , msr -> intercept_phase );
1270
+ yajl_kv_string (g , "message" , msr -> intercept_message );
1231
1271
yajl_gen_map_close (g );
1232
1272
#endif
1233
1273
}
@@ -1242,27 +1282,25 @@ void sec_audit_logger(modsec_rec *msr) {
1242
1282
#endif
1243
1283
}
1244
1284
1285
+ #ifndef WITH_JSON_LOGGING
1245
1286
/* Stopwatch; left in for compatibility reasons */
1246
1287
text = apr_psprintf (msr -> mp , "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n" ,
1247
1288
msr -> request_time , (now - msr -> request_time ));
1248
- #ifndef WITH_JSON_LOGGING
1249
1289
sec_auditlog_write (msr , text , strlen (text ));
1250
- #else
1251
- yajl_kv_string (g , "stopwatch" , text );
1252
1290
#endif
1253
1291
1254
1292
/* Stopwatch2 */
1293
+ #ifndef WITH_JSON_LOGGING
1255
1294
{
1256
1295
char * perf_all = format_all_performance_variables (msr , msr -> mp );
1257
1296
1258
1297
text = apr_psprintf (msr -> mp , "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT
1259
1298
"; %s\n" , msr -> request_time , (now - msr -> request_time ), perf_all );
1260
- #ifndef WITH_JSON_LOGGING
1261
1299
sec_auditlog_write (msr , text , strlen (text ));
1300
+ }
1262
1301
#else
1263
- yajl_kv_string ( g , "stopwatch2" , text );
1302
+ format_performance_variables_json ( msr , g );
1264
1303
#endif
1265
- }
1266
1304
1267
1305
/* Our response body does not contain chunks */
1268
1306
/* ENH Only write this when the output was chunked. */
@@ -1293,8 +1331,7 @@ void sec_audit_logger(modsec_rec *msr) {
1293
1331
}
1294
1332
1295
1333
#ifdef WITH_JSON_LOGGING
1296
- yajl_string (g , "sanitized" );
1297
- yajl_gen_map_open (g ); // open a separate map for sanitized values
1334
+ been_opened = 0 ;
1298
1335
#endif
1299
1336
1300
1337
/* Sanitised arguments */
@@ -1310,6 +1347,12 @@ void sec_audit_logger(modsec_rec *msr) {
1310
1347
text = apr_psprintf (msr -> mp , "Sanitised-Args: " );
1311
1348
sec_auditlog_write (msr , text , strlen (text ));
1312
1349
#else
1350
+ if (been_opened == 0 ) {
1351
+ yajl_string (g , "sanitized" );
1352
+ yajl_gen_map_open (g );
1353
+ been_opened = 1 ;
1354
+ }
1355
+
1313
1356
yajl_string (g , "args" );
1314
1357
yajl_gen_array_open (g );
1315
1358
#endif
@@ -1346,6 +1389,12 @@ void sec_audit_logger(modsec_rec *msr) {
1346
1389
text = apr_psprintf (msr -> mp , "Sanitised-Request-Headers: " );
1347
1390
sec_auditlog_write (msr , text , strlen (text ));
1348
1391
#else
1392
+ if (been_opened == 0 ) {
1393
+ yajl_string (g , "sanitized" );
1394
+ yajl_gen_map_open (g );
1395
+ been_opened = 1 ;
1396
+ }
1397
+
1349
1398
yajl_string (g , "request_headers" );
1350
1399
yajl_gen_array_open (g );
1351
1400
#endif
@@ -1380,6 +1429,12 @@ void sec_audit_logger(modsec_rec *msr) {
1380
1429
text = apr_psprintf (msr -> mp , "Sanitised-Response-Headers: " );
1381
1430
sec_auditlog_write (msr , text , strlen (text ));
1382
1431
#else
1432
+ if (been_opened == 0 ) {
1433
+ yajl_string (g , "sanitized" );
1434
+ yajl_gen_map_open (g );
1435
+ been_opened = 1 ;
1436
+ }
1437
+
1383
1438
yajl_string (g , "response_headers" );
1384
1439
yajl_gen_array_open (g );
1385
1440
#endif
@@ -1402,7 +1457,9 @@ void sec_audit_logger(modsec_rec *msr) {
1402
1457
}
1403
1458
1404
1459
#ifdef WITH_JSON_LOGGING
1405
- yajl_gen_map_close (g ); // sanitized args map is finished
1460
+ if (been_opened == 1 ) {
1461
+ yajl_gen_map_close (g ); // sanitized args map is finished
1462
+ }
1406
1463
#endif
1407
1464
1408
1465
/* Web application info. */
@@ -1493,7 +1550,7 @@ void sec_audit_logger(modsec_rec *msr) {
1493
1550
}
1494
1551
1495
1552
#ifdef WITH_JSON_LOGGING
1496
- yajl_gen_map_close (g ); // data top-level key is finished
1553
+ yajl_gen_map_close (g ); // audit_data top-level key is finished
1497
1554
#endif
1498
1555
1499
1556
/* AUDITLOG_PART_UPLOADS */
@@ -1552,7 +1609,6 @@ void sec_audit_logger(modsec_rec *msr) {
1552
1609
yajl_gen_array_open (g ); // matched_rules top-level key
1553
1610
#endif
1554
1611
1555
-
1556
1612
/* Matched Rules */
1557
1613
1558
1614
for (i = 0 ; i < msr -> matched_rules -> nelts ; i ++ ) {
@@ -1608,7 +1664,7 @@ void sec_audit_logger(modsec_rec *msr) {
1608
1664
}
1609
1665
}
1610
1666
#ifdef WITH_JSON_LOGGING
1611
- yajl_gen_array_close (g ); // matched_rules top-level key is finished
1667
+ yajl_gen_array_close (g ); // matched_rules top-level key is finished
1612
1668
#endif
1613
1669
1614
1670
}
0 commit comments