Skip to content
Merged
14 changes: 14 additions & 0 deletions coraza.i
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
%ignore coraza_add_debug_log_callback;
%ignore coraza_add_error_callback;
%ignore coraza_free_string;

/*
* Handle the char** output parameter for error messages.
Expand Down Expand Up @@ -330,6 +331,12 @@ typedef struct coraza_intervention_t {
char *data;
} coraza_intervention_t;

typedef enum coraza_result_t {
CORAZA_ERROR = -1,
CORAZA_OK = 0,
CORAZA_INTERRUPTION = 1,
} coraza_result_t;

typedef enum coraza_debug_log_level_t {
CORAZA_DEBUG_LOG_LEVEL_UNKNOWN,
CORAZA_DEBUG_LOG_LEVEL_TRACE,
Expand Down Expand Up @@ -401,3 +408,10 @@ extern int coraza_free_waf(coraza_waf_t t);
extern coraza_severity_t coraza_matched_rule_get_severity(
coraza_matched_rule_t r);
extern char *coraza_matched_rule_get_error_log(coraza_matched_rule_t r);
extern int coraza_add_request_headers(coraza_transaction_t t,
const char *packed, int packed_len,
int count);
extern int coraza_add_response_headers(coraza_transaction_t t,
const char *packed, int packed_len,
int count);
extern void coraza_free_string(char *s);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
10 changes: 5 additions & 5 deletions examples/java/SimpleGet.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,21 @@ static void testLifecycle() throws IOException {
ret = coraza.coraza_process_uri(tx, "/someurl?foo=bar", "GET", "HTTP/1.1");
check(ret == 0, "coraza_process_uri failed: " + ret);

// coraza_process_request_headers
// coraza_process_request_headers (returns CORAZA_INTERRUPTION for the deny rule)
ret = coraza.coraza_process_request_headers(tx);
check(ret == 0, "coraza_process_request_headers failed: " + ret);
check(ret == 1, "coraza_process_request_headers: expected CORAZA_INTERRUPTION (1), got " + ret);

// coraza_append_request_body (byte[] typemap: single array arg)
ret = coraza.coraza_append_request_body(tx, "hello=world".getBytes());
check(ret == 0, "coraza_append_request_body failed: " + ret);

// coraza_process_request_body
ret = coraza.coraza_process_request_body(tx);
check(ret == 0, "coraza_process_request_body failed: " + ret);
check(ret >= 0, "coraza_process_request_body failed: " + ret);

// coraza_process_response_headers
ret = coraza.coraza_process_response_headers(tx, 200, "HTTP/1.1");
check(ret == 0, "coraza_process_response_headers failed: " + ret);
check(ret >= 0, "coraza_process_response_headers failed: " + ret);

// coraza_add_response_header
String cname = "Content-Type", cvalue = "text/plain";
Expand All @@ -130,7 +130,7 @@ static void testLifecycle() throws IOException {

// coraza_process_response_body
ret = coraza.coraza_process_response_body(tx);
check(ret == 0, "coraza_process_response_body failed: " + ret);
check(ret >= 0, "coraza_process_response_body failed: " + ret);

// coraza_update_status_code
coraza.coraza_update_status_code(tx, 200);
Expand Down
10 changes: 5 additions & 5 deletions examples/python/simple_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ def test_lifecycle():
ret = _c.coraza_process_uri(tx, "/someurl?foo=bar", "GET", "HTTP/1.1")
_check(ret == 0, f"coraza_process_uri failed: {ret}")

# coraza_process_request_headers
# coraza_process_request_headers (returns CORAZA_INTERRUPTION for the deny rule)
ret = _c.coraza_process_request_headers(tx)
_check(ret == 0, f"coraza_process_request_headers failed: {ret}")
_check(ret == 1, f"coraza_process_request_headers: expected CORAZA_INTERRUPTION (1), got {ret}")

# coraza_append_request_body (bytes typemap: single argument)
body = b"hello=world"
Expand All @@ -119,11 +119,11 @@ def test_lifecycle():

# coraza_process_request_body
ret = _c.coraza_process_request_body(tx)
_check(ret == 0, f"coraza_process_request_body failed: {ret}")
_check(ret >= 0, f"coraza_process_request_body failed: {ret}")

# coraza_process_response_headers
ret = _c.coraza_process_response_headers(tx, 200, "HTTP/1.1")
_check(ret == 0, f"coraza_process_response_headers failed: {ret}")
_check(ret >= 0, f"coraza_process_response_headers failed: {ret}")

# coraza_add_response_header
cname, cvalue = "Content-Type", "text/plain"
Expand All @@ -139,7 +139,7 @@ def test_lifecycle():

# coraza_process_response_body
ret = _c.coraza_process_response_body(tx)
_check(ret == 0, f"coraza_process_response_body failed: {ret}")
_check(ret >= 0, f"coraza_process_response_body failed: {ret}")

# coraza_update_status_code
_c.coraza_update_status_code(tx, 200)
Expand Down
121 changes: 111 additions & 10 deletions libcoraza/coraza.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ typedef uintptr_t coraza_waf_t;
typedef uintptr_t coraza_transaction_t;
typedef uintptr_t coraza_matched_rule_t;

typedef enum coraza_result_t {
CORAZA_ERROR = -1,
CORAZA_OK = 0,
CORAZA_INTERRUPTION = 1,
} coraza_result_t;

typedef enum coraza_debug_log_level_t {
CORAZA_DEBUG_LOG_LEVEL_UNKNOWN,
CORAZA_DEBUG_LOG_LEVEL_TRACE,
Expand Down Expand Up @@ -239,10 +245,14 @@ func coraza_process_connection(t C.coraza_transaction_t, sourceAddress *C.char,
//export coraza_process_request_body
func coraza_process_request_body(t C.coraza_transaction_t) C.int {
tx := fromRaw[types.Transaction](t)
if _, err := tx.ProcessRequestBody(); err != nil {
return 1
it, err := tx.ProcessRequestBody()
if err != nil {
return C.CORAZA_ERROR
}
return 0
if it != nil {
return C.CORAZA_INTERRUPTION
}
return C.CORAZA_OK
}

//export coraza_update_status_code
Expand Down Expand Up @@ -277,11 +287,50 @@ func coraza_add_request_header(t C.coraza_transaction_t, name *C.char, name_len
return 0
}

// coraza_add_request_headers adds multiple request headers from a packed buffer.
// Encoding: [name_len u16][name_bytes][value_len u32][value_bytes] × count
//
//export coraza_add_request_headers
func coraza_add_request_headers(t C.coraza_transaction_t, packed *C.char, packed_len C.int, count C.int) C.int {
if packed_len < 0 || count < 0 {
return -1
}
tx := fromRaw[types.Transaction](t)
buf := C.GoBytes(unsafe.Pointer(packed), packed_len)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
off := 0
for i := 0; i < int(count); i++ {
if off+2 > len(buf) {
return -1
}
nameLen := int(uint16(buf[off])<<8 | uint16(buf[off+1]))
off += 2
if off+nameLen > len(buf) {
return -1
}
name := string(buf[off : off+nameLen])
off += nameLen
if off+4 > len(buf) {
return -1
}
valueLen := int(uint32(buf[off])<<24 | uint32(buf[off+1])<<16 | uint32(buf[off+2])<<8 | uint32(buf[off+3]))
off += 4
if off+valueLen > len(buf) {
return -1
}
value := string(buf[off : off+valueLen])
off += valueLen
tx.AddRequestHeader(name, value)
}
return 0
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

//export coraza_process_request_headers
func coraza_process_request_headers(t C.coraza_transaction_t) C.int {
tx := fromRaw[types.Transaction](t)
tx.ProcessRequestHeaders()
return 0
if it := tx.ProcessRequestHeaders(); it != nil {
return C.CORAZA_INTERRUPTION
}
return C.CORAZA_OK
}

//export coraza_process_logging
Expand Down Expand Up @@ -314,6 +363,43 @@ func coraza_add_response_header(t C.coraza_transaction_t, name *C.char, name_len
return 0
}

// coraza_add_response_headers adds multiple response headers from a packed buffer.
// Same encoding as coraza_add_request_headers.
//
//export coraza_add_response_headers
func coraza_add_response_headers(t C.coraza_transaction_t, packed *C.char, packed_len C.int, count C.int) C.int {
if packed_len < 0 || count < 0 {
return -1
}
tx := fromRaw[types.Transaction](t)
buf := C.GoBytes(unsafe.Pointer(packed), packed_len)
off := 0
for i := 0; i < int(count); i++ {
if off+2 > len(buf) {
return -1
}
nameLen := int(uint16(buf[off])<<8 | uint16(buf[off+1]))
off += 2
if off+nameLen > len(buf) {
return -1
}
name := string(buf[off : off+nameLen])
off += nameLen
if off+4 > len(buf) {
return -1
}
valueLen := int(uint32(buf[off])<<24 | uint32(buf[off+1])<<16 | uint32(buf[off+2])<<8 | uint32(buf[off+3]))
off += 4
if off+valueLen > len(buf) {
return -1
}
value := string(buf[off : off+valueLen])
off += valueLen
tx.AddResponseHeader(name, value)
}
return 0
}

//export coraza_append_response_body
func coraza_append_response_body(t C.coraza_transaction_t, data *C.uchar, length C.int) C.int {
tx := fromRaw[types.Transaction](t)
Expand All @@ -326,17 +412,23 @@ func coraza_append_response_body(t C.coraza_transaction_t, data *C.uchar, length
//export coraza_process_response_body
func coraza_process_response_body(t C.coraza_transaction_t) C.int {
tx := fromRaw[types.Transaction](t)
if _, err := tx.ProcessResponseBody(); err != nil {
return 1
it, err := tx.ProcessResponseBody()
if err != nil {
return C.CORAZA_ERROR
}
return 0
if it != nil {
return C.CORAZA_INTERRUPTION
}
return C.CORAZA_OK
}

//export coraza_process_response_headers
func coraza_process_response_headers(t C.coraza_transaction_t, status C.int, proto *C.char) C.int {
tx := fromRaw[types.Transaction](t)
tx.ProcessResponseHeaders(int(status), C.GoString(proto))
return 0
if it := tx.ProcessResponseHeaders(int(status), C.GoString(proto)); it != nil {
return C.CORAZA_INTERRUPTION
}
return C.CORAZA_OK
}

//export coraza_is_response_body_processable
Expand Down Expand Up @@ -417,6 +509,15 @@ func coraza_free_waf(t C.coraza_waf_t) C.int {
return 0
}

// coraza_free_string frees a string returned by libcoraza (e.g. from
// coraza_matched_rule_get_error_log). Callers must use this instead of
// libc free() to avoid allocator mismatches on Windows.
//
//export coraza_free_string
func coraza_free_string(s *C.char) {
C.free(unsafe.Pointer(s))
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Returns the severity of a matched rule.
* @param[in] pointer to matched rule
Expand Down
Loading