coraza-sys 3.7.0

Raw FFI bindings to OWASP Coraza WAF
/*
 * Copyright 2022 OWASP Coraza contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! # coraza-sys
//!
//! Raw FFI bindings to [OWASP Coraza](https://coraza.io/) Web Application Firewall.
//!
//! This crate provides low-level C bindings to the Coraza WAF engine, compiled
//! from Go source code via CGo. For a safe Rust wrapper, see the `coraza` crate.
//!
//! ## Build Requirements
//!
//! - Go toolchain (1.21+) in PATH
//! - C compiler (gcc/clang on Unix, MSVC on Windows)
//! - libclang (for bindgen)
//!
//! ## Usage
//!
//! ```no_run
//! use coraza_sys::*;
//!
//! // Create a WAF configuration
//! let config = unsafe { coraza_new_waf_config() };
//!
//! // Add rules
//! let rules = b"SecRuleEngine On\0";
//! unsafe { coraza_rules_add(config, rules.as_ptr() as *const i8) };
//!
//! // Compile the WAF
//! let mut err: *mut i8 = std::ptr::null_mut();
//! let waf = unsafe { coraza_new_waf(config, &mut err) };
//! if waf == 0 {
//!     let msg = unsafe { std::ffi::CStr::from_ptr(err) };
//!     panic!("Failed to create WAF: {:?}", msg);
//! }
//!
//! // Create a transaction
//! let tx = unsafe { coraza_new_transaction(waf) };
//!
//! // Process a request
//! unsafe {
//!     coraza_process_connection(tx, b"127.0.0.1\0".as_ptr() as *const i8, 8080, b"localhost\0".as_ptr() as *const i8, 80);
//!     coraza_process_uri(tx, b"/\0".as_ptr() as *const i8, b"GET\0".as_ptr() as *const i8, b"HTTP/1.1\0".as_ptr() as *const i8);
//!     coraza_process_request_headers(tx);
//!     coraza_process_logging(tx);
//! }
//!
//! // Cleanup
//! unsafe {
//!     coraza_free_transaction(tx);
//!     coraza_free_waf(waf);
//! }
//! ```

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

// Include generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CString;

    #[test]
    fn test_waf_lifecycle() {
        unsafe {
            let config = coraza_new_waf_config();
            assert_ne!(config, 0);

            let rules = CString::new("SecRuleEngine DetectionOnly").unwrap();
            let ret = coraza_rules_add(config, rules.as_ptr());
            assert_eq!(ret, 0);

            let mut err: *mut i8 = std::ptr::null_mut();
            let waf = coraza_new_waf(config, &mut err);
            assert_ne!(waf, 0);
            assert!(err.is_null());

            let tx = coraza_new_transaction(waf);
            assert_ne!(tx, 0);

            let ret = coraza_free_transaction(tx);
            assert_eq!(ret, 0);

            let ret = coraza_free_waf(waf);
            assert_eq!(ret, 0);
        }
    }

    #[test]
    fn test_process_connection() {
        unsafe {
            let config = coraza_new_waf_config();
            let rules = CString::new("SecRuleEngine DetectionOnly").unwrap();
            coraza_rules_add(config, rules.as_ptr());

            let mut err: *mut i8 = std::ptr::null_mut();
            let waf = coraza_new_waf(config, &mut err);
            let tx = coraza_new_transaction(waf);

            let src = CString::new("127.0.0.1").unwrap();
            let host = CString::new("localhost").unwrap();
            let ret = coraza_process_connection(tx, src.as_ptr(), 8080, host.as_ptr(), 80);
            assert_eq!(ret, 0);

            coraza_free_transaction(tx);
            coraza_free_waf(waf);
        }
    }

    #[test]
    fn test_process_uri() {
        unsafe {
            let config = coraza_new_waf_config();
            let rules = CString::new("SecRuleEngine DetectionOnly").unwrap();
            coraza_rules_add(config, rules.as_ptr());

            let mut err: *mut i8 = std::ptr::null_mut();
            let waf = coraza_new_waf(config, &mut err);
            let tx = coraza_new_transaction(waf);

            let uri = CString::new("/test").unwrap();
            let method = CString::new("GET").unwrap();
            let proto = CString::new("HTTP/1.1").unwrap();
            let ret = coraza_process_uri(tx, uri.as_ptr(), method.as_ptr(), proto.as_ptr());
            assert_eq!(ret, 0);

            coraza_free_transaction(tx);
            coraza_free_waf(waf);
        }
    }

    #[test]
    fn test_intervention_nil_when_no_match() {
        unsafe {
            let config = coraza_new_waf_config();
            let rules = CString::new("SecRuleEngine DetectionOnly").unwrap();
            coraza_rules_add(config, rules.as_ptr());

            let mut err: *mut i8 = std::ptr::null_mut();
            let waf = coraza_new_waf(config, &mut err);
            let tx = coraza_new_transaction(waf);

            let it = coraza_intervention(tx);
            assert!(it.is_null());

            coraza_free_transaction(tx);
            coraza_free_waf(waf);
        }
    }
}