Skip to content

Commit 7d19b8d

Browse files
authored
Merge pull request #47 from wtzhang23/error-callbacks
feat: implement registering error callbacks
2 parents 5882ac3 + b3a5f02 commit 7d19b8d

3 files changed

Lines changed: 98 additions & 5 deletions

File tree

libcoraza/coraza.go

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ typedef struct coraza_intervention_t
1919
typedef uintptr_t coraza_waf_config_t;
2020
typedef uintptr_t coraza_waf_t;
2121
typedef uintptr_t coraza_transaction_t;
22+
typedef uintptr_t coraza_matched_rule_t;
2223
2324
typedef enum coraza_debug_log_level_t {
25+
CORAZA_DEBUG_LOG_LEVEL_UNKNOWN,
2426
CORAZA_DEBUG_LOG_LEVEL_TRACE,
2527
CORAZA_DEBUG_LOG_LEVEL_DEBUG,
2628
CORAZA_DEBUG_LOG_LEVEL_INFO,
@@ -30,11 +32,30 @@ typedef enum coraza_debug_log_level_t {
3032
3133
typedef void (*coraza_debug_log_cb) (void *, coraza_debug_log_level_t, const char *msg, const char *fields);
3234
35+
typedef enum coraza_severity_t {
36+
CORAZA_SEVERITY_UNKNOWN,
37+
CORAZA_SEVERITY_DEBUG,
38+
CORAZA_SEVERITY_INFO,
39+
CORAZA_SEVERITY_NOTICE,
40+
CORAZA_SEVERITY_WARNING,
41+
CORAZA_SEVERITY_ERROR,
42+
CORAZA_SEVERITY_CRITICAL,
43+
CORAZA_SEVERITY_ALERT,
44+
CORAZA_SEVERITY_EMERGENCY,
45+
} coraza_severity_t;
46+
47+
typedef void (*coraza_error_cb) (void *, coraza_matched_rule_t);
48+
49+
#endif
50+
3351
static void call_debug_log_cb(coraza_debug_log_cb cb, void *ctx, coraza_debug_log_level_t level, const char *msg, const char *fields) {
3452
cb(ctx, level, msg, fields);
3553
}
3654
37-
#endif
55+
static void call_error_cb(coraza_error_cb cb, void *ctx, coraza_matched_rule_t rule) {
56+
cb(ctx, rule);
57+
}
58+
3859
*/
3960
import "C"
4061
import (
@@ -86,7 +107,7 @@ func coraza_rules_add(c C.coraza_waf_config_t, directives *C.char) C.int {
86107
func coraza_add_debug_log_callback(c C.coraza_waf_config_t, cb C.coraza_debug_log_cb, userContext *C.void) C.int {
87108
configHandle := fromRaw[*WafConfigHandle](c)
88109
configHandle.config = configHandle.config.WithDebugLogger(newDebugLogger(func(lvl debuglog.Level, message, fields string) {
89-
rawLevel := C.CORAZA_DEBUG_LOG_LEVEL_DEBUG
110+
rawLevel := C.CORAZA_DEBUG_LOG_LEVEL_UNKNOWN
90111
switch lvl {
91112
case debuglog.LevelTrace:
92113
rawLevel = C.CORAZA_DEBUG_LOG_LEVEL_TRACE
@@ -98,6 +119,8 @@ func coraza_add_debug_log_callback(c C.coraza_waf_config_t, cb C.coraza_debug_lo
98119
rawLevel = C.CORAZA_DEBUG_LOG_LEVEL_WARN
99120
case debuglog.LevelError:
100121
rawLevel = C.CORAZA_DEBUG_LOG_LEVEL_ERROR
122+
default:
123+
rawLevel = C.CORAZA_DEBUG_LOG_LEVEL_UNKNOWN
101124
}
102125
cMsg := C.CString(message)
103126
cFields := C.CString(fields)
@@ -108,6 +131,25 @@ func coraza_add_debug_log_callback(c C.coraza_waf_config_t, cb C.coraza_debug_lo
108131
return 0
109132
}
110133

134+
/**
135+
* Adds a error callback to a WAF config
136+
* @param[in] pointer to valid WAF config
137+
* @param[in] pointer to error callback
138+
* @param[in] pointer to custom user context passed every time the error callback is called. This must live as long as
139+
* while the parent config and its dependent objects are active.
140+
* @returns 0 on success, 1 on failure
141+
*/
142+
//export coraza_add_error_callback
143+
func coraza_add_error_callback(c C.coraza_waf_config_t, cb C.coraza_error_cb, userContext *C.void) C.int {
144+
configHandle := fromRaw[*WafConfigHandle](c)
145+
configHandle.config = configHandle.config.WithErrorCallback(func(rule types.MatchedRule) {
146+
ruleHandle := cgo.NewHandle(rule)
147+
defer ruleHandle.Delete()
148+
C.call_error_cb(cb, unsafe.Pointer(userContext), C.coraza_matched_rule_t(ruleHandle))
149+
})
150+
return 0
151+
}
152+
111153
//export coraza_free_waf_config
112154
func coraza_free_waf_config(config C.coraza_waf_config_t) C.int {
113155
deleteRaw(config)
@@ -328,6 +370,47 @@ func coraza_free_waf(t C.coraza_waf_t) C.int {
328370
return 0
329371
}
330372

373+
/**
374+
* Returns the severity of a matched rule.
375+
* @param[in] pointer to matched rule
376+
* @returns severity of the matched rule
377+
*/
378+
//export coraza_matched_rule_get_severity
379+
func coraza_matched_rule_get_severity(r C.coraza_matched_rule_t) C.coraza_severity_t {
380+
matchedRule := fromRaw[types.MatchedRule](r)
381+
switch matchedRule.Rule().Severity() {
382+
case types.RuleSeverityEmergency:
383+
return C.CORAZA_SEVERITY_EMERGENCY
384+
case types.RuleSeverityAlert:
385+
return C.CORAZA_SEVERITY_ALERT
386+
case types.RuleSeverityCritical:
387+
return C.CORAZA_SEVERITY_CRITICAL
388+
case types.RuleSeverityError:
389+
return C.CORAZA_SEVERITY_ERROR
390+
case types.RuleSeverityWarning:
391+
return C.CORAZA_SEVERITY_WARNING
392+
case types.RuleSeverityNotice:
393+
return C.CORAZA_SEVERITY_NOTICE
394+
case types.RuleSeverityInfo:
395+
return C.CORAZA_SEVERITY_INFO
396+
case types.RuleSeverityDebug:
397+
return C.CORAZA_SEVERITY_DEBUG
398+
}
399+
return C.CORAZA_SEVERITY_UNKNOWN
400+
}
401+
402+
/*
403+
* Returns the error log of a matched rule. The caller is responsible for freeing the returned string.
404+
* @param[in] pointer to matched rule
405+
* @returns error log of the matched rule
406+
*/
407+
//export coraza_matched_rule_get_error_log
408+
func coraza_matched_rule_get_error_log(r C.coraza_matched_rule_t) *C.char {
409+
rule := fromRaw[types.MatchedRule](r)
410+
cMsg := C.CString(rule.ErrorLog())
411+
return cMsg
412+
}
413+
331414
/*
332415
Internal helpers
333416
*/

tests/simple_get.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ void logcb(void *context, coraza_debug_log_level_t level, const char *msg, const
88
}
99

1010

11+
void errorcb(void *context, coraza_matched_rule_t rule)
12+
{
13+
printf("[%s][severity %d] %s\n", (const char *)context, coraza_matched_rule_get_severity(rule), coraza_matched_rule_get_error_log(rule));
14+
}
15+
1116
int main()
1217
{
1318
coraza_waf_config_t config = coraza_new_waf_config();
@@ -21,6 +26,9 @@ int main()
2126
printf("Attaching log callback\n");
2227
coraza_add_debug_log_callback(config, logcb, "simple_get");
2328

29+
printf("Attaching error callback\n");
30+
coraza_add_error_callback(config, errorcb, "simple_get");
31+
2432
coraza_waf_t waf = 0;
2533
coraza_transaction_t tx = 0;
2634
coraza_intervention_t *intervention = NULL;

tests/simple_get.out

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
Compiling rules...
22
Attaching log callback
3+
Attaching error callback
34
Starting...
45
0 rules compiled
56
Creating transaction...
67
Processing connection...
78
Processing request line
89
Processing phase 1
10+
[simple_get][severity 8] [client "127.0.0.1"] Coraza: Access denied (phase 1). test 123 [file "_inline_"] [line "1"] [id "1"] [rev ""] [msg "test 123"] [data ""] [severity "emergency"] [ver ""] [maturity "0"] [accuracy "0"] [hostname ""] [uri "/someurl"] [unique_id "simple_get"]
911
Processing phase 2
10-
[simple_get][level 4] Calling ProcessRequestBody but there is a preexisting interruption tx_id="simple_get"
12+
[simple_get][level 5] Calling ProcessRequestBody but there is a preexisting interruption tx_id="simple_get"
1113
Processing phase 3
12-
[simple_get][level 4] Calling ProcessResponseHeaders but there is a preexisting interruption tx_id="simple_get"
14+
[simple_get][level 5] Calling ProcessResponseHeaders but there is a preexisting interruption tx_id="simple_get"
1315
Processing phase 4
14-
[simple_get][level 4] Calling ProcessResponseBody but there is a preexisting interruption tx_id="simple_get"
16+
[simple_get][level 5] Calling ProcessResponseBody but there is a preexisting interruption tx_id="simple_get"
1517
Processing phase 5
1618
Processing intervention
1719
Transaction disrupted with status 403

0 commit comments

Comments
 (0)