Skip to main content
The scan_url function is the primary entry point for WAF detection. It sends multiple probes to a target URL and analyzes the responses to identify WAF signatures.

Function signature

pub fn scan_url<F>(
    url: &str,
    config: ScanConfig,
    mut on_probe: Option<F>,
) -> Result<Option<ProbeResult>, ScanError>
where
    F: FnMut(&ProbeResult) -> bool,

Parameters

url
&str
required
The target URL to scan. Must be a valid HTTP or HTTPS URL.
config
ScanConfig
required
Configuration for the scan behavior, including timeout, redirect handling, and proxy settings.See the Configuration page for details.
on_probe
Option<F>
default:"None"
Optional callback function invoked after each probe completes.The callback receives a reference to the ProbeResult and returns a bool:
  • Return true to continue with remaining probes
  • Return false to stop scanning immediately
This allows real-time processing and early termination based on detection results.

Return type

Result
Result<Option<ProbeResult>, ScanError>
Returns Ok(Some(ProbeResult)) with the last probe result if scanning completes successfully.Returns Ok(None) if no probes were executed (unlikely in normal operation).Returns Err(ScanError) if an error occurs during scanning.

Probe sequence

The function executes the following probes in order:
  1. Plain request - Baseline request to the original URL
  2. XSS probe - Adds parameter q=<script>alert(1)</script>
  3. SQL injection probe - Adds parameter id=' OR '1'='1'
  4. LFI probe - Adds parameter file=../../../../etc/passwd
Each probe generates a ProbeResult with detected WAFs (if any).

Callback mechanism

The optional callback function allows you to:
  • Display progress during scanning
  • Log each probe result
  • Terminate scanning early when a WAF is detected
  • Collect results for custom analysis

Callback example

use whatwaf::{scan_url, ScanConfig, ProbeResult};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ScanConfig {
        timeout: 10,
        follow_redirects: true,
        proxy: None,
    };

    let result = scan_url(
        "https://example.com",
        config,
        Some(|probe: &ProbeResult| {
            println!("Probe: {} (status: {})", probe.probe_name, probe.status);
            
            if let Some(wafs) = &probe.detected_wafs {
                println!("  Detected: {:?}", wafs);
                // Stop scanning after first detection
                return false;
            }
            
            // Continue with next probe
            true
        }),
    )?;

    if let Some(final_result) = result {
        println!("\nFinal result: {:?}", final_result);
    }

    Ok(())
}

Complete working example

Here’s a full example demonstrating different scan configurations:
use whatwaf::{scan_url, ScanConfig, ProbeResult, ScanError};

fn scan_with_progress(url: &str) -> Result<(), Box<dyn std::error::Error>> {
    let config = ScanConfig {
        timeout: 10,
        follow_redirects: true,
        proxy: None,
    };

    println!("Scanning {}...", url);

    let result = scan_url(
        url,
        config,
        Some(|probe: &ProbeResult| {
            print!("[{}] ", probe.probe_name);
            
            if let Some(wafs) = &probe.detected_wafs {
                if !wafs.is_empty() {
                    println!("Detected: {}", wafs.join(", "));
                } else {
                    println!("No detection");
                }
            } else {
                println!("No detection");
            }
            
            true // Continue scanning
        }),
    )?;

    if let Some(last) = result {
        println!("\nScan complete. Last probe: {}", last.probe_name);
        println!("Final status: {}", last.status);
    }

    Ok(())
}

fn main() {
    match scan_with_progress("https://example.com") {
        Ok(_) => println!("Scan successful"),
        Err(e) => eprintln!("Scan failed: {}", e),
    }
}

Error handling

The function can return the following errors:
  • InvalidProxy - The proxy configuration is invalid
  • ClientBuild - Failed to build the HTTP client
  • Request - A network request failed
See the Error handling page for detailed error handling strategies.

Using a proxy

use whatwaf::{scan_url, ScanConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ScanConfig {
        timeout: 15,
        follow_redirects: false,
        proxy: Some("http://127.0.0.1:8080".to_string()),
    };

    let result = scan_url("https://example.com", config, None)?;
    
    // Process result...
    
    Ok(())
}

Build docs developers (and LLMs) love