Contributor Guide
Where to code each feature, backend development roadmap
Overview
This guide maps each ExfilGuardian feature to the exact files and functions where development happens. Use it to know where to start coding, what exists, and what's missing.
Status Legend
| Status | Meaning |
|---|---|
| Done | Code exists and works |
| Partial | Scaffold or partial implementation exists |
| TODO | Not yet implemented |
Feature Map
F1: WFP Kernel Filtering
Status: Done
| What | Where |
|---|---|
| Driver entry/unload | driver/src/lib.rs → DriverEntry, DriverUnload |
| WFP callout registration | driver/src/security/filter.rs → register_callouts() |
| WFP API bindings | driver/src/security/wfp.rs |
| Packet capture callback | driver/src/security/filter.rs → classify_fn() |
| Device IOCTL handler | driver/src/device/io.rs → device_control() |
| IRP inversé model | driver/src/device/io.rs → pending IRP completion on packet arrival |
Corrected driver version: rust-driver-rectified-version/ contains the latest working driver. Compare with driver/ for any divergences.
To modify WFP behavior: Edit driver/src/security/filter.rs. The classify_fn callback receives each packet from WFP and decides whether to pass, block, or queue it for the agent.
F2: Local Telemetry Agent
Status: Done
| What | Where |
|---|---|
| Service main | agent/src/main.rs → run() (SCM dispatcher + console fallback) |
| IOCTL loop | agent/src/main.rs → run_agent() (DeviceIoControl blocking loop) |
| Packet conversion | agent/src/main.rs → ExfilPacketKernel → NetworkPacket |
| Registry config | agent/src/main.rs → reads HKLM\SOFTWARE\ExfilGuardian\TargetUrl |
| gRPC client | agent/src/main.rs → tonic client + ReceiverStream |
To add agent-side logic: The agent is currently a single main.rs. To add pre-filtering or flow tracking on the agent side, use the analysis crate's agent modules:
use exfil_analysis::agent::pre_filter::PreFilter;
use exfil_analysis::agent::flow_tracker::FlowTracker;These modules are already implemented in analysis/src/agent/ but not yet wired into the agent binary.
F3: SQLite WAL Queue
Status: Done
| What | Where |
|---|---|
| Queue init | agent/src/main.rs → Connection::open("exfil_queue.db") + WAL pragma |
| Producer | agent/src/main.rs → IOCTL loop inserts Protobuf bytes into packets table |
| Consumer | agent/src/main.rs → Tokio task reads 50 packets, sends via gRPC, deletes on success |
| Wake mechanism | agent/src/main.rs → mpsc::channel between producer and consumer |
To modify queue behavior: Edit the consumer task in agent/src/main.rs. The batch size (50), retry delay (5s), and queue table schema are all in that file.
F4: gRPC/Protobuf Transport
Status: Done
| What | Where |
|---|---|
| Proto definition | proto/exfil.proto → ExfilService, NetworkPacket, StreamResponse |
| Server receiver | server/src/grpc/receiver.rs → ExfilServerImpl::stream_packets() |
| Agent client | agent/src/main.rs → ExfilServiceClient::stream_packets() |
| Code generation | agent/build.rs and server/build.rs → tonic_build::compile_protos() |
To add new RPCs: Edit proto/exfil.proto, add the RPC definition, then implement the handler in server/src/grpc/receiver.rs. The agent side goes in agent/src/main.rs (or a new module).
F5: mTLS Dynamic Authentication
Status: Partial (certificates generated, mTLS disabled for debugging)
| What | Where |
|---|---|
| CA + server cert generation | server/src/main.rs → ensure_certs() (uses rcgen) |
| Agent cert generation | server/src/api/enroll.rs → per-enrollment client cert signed by CA |
| Certs generator CLI | certs/src/main.rs → standalone cert generation tool |
| TLS config (disabled) | server/src/main.rs → commented out .tls_config(tls)? |
To re-enable mTLS:
- In
server/src/main.rs, uncomment the TLS configuration block:
let grpc_server = Server::builder()
.tls_config(tls)? // Uncomment this line
.add_service(ExfilServiceServer::new(grpc_service))
.serve(grpc_addr);- In the agent, configure
tonicto use the client certificate:
let tls = ClientTlsConfig::new()
.ca_certificate(Certificate::from_pem(ca_pem))
.identity(Identity::from_pem(client_cert, client_key));
let channel = Channel::from_shared(url)?
.tls_config(tls)?
.connect().await?;- Ensure the agent reads its certificate files from
C:\Program Files\ExfilGuardian\certs\(written by the enrollment script).
F6: Zero-Touch Deployment
Status: Done
| What | Where |
|---|---|
| Token generation | server/src/api/enroll.rs → POST /api/v1/agent/tokens |
| Token storage | server/src/api/enroll.rs → HashSet<String> in AppState |
| PowerShell script | server/src/api/enroll.rs → GET /api/v1/enroll/windows (generates script dynamically) |
| Static file serving | server/src/api/routes.rs → ServeDir for server/static/ |
| Installer (manual alt) | installer/src/main.rs → sc.exe create for both services |
To modify the enrollment script: Edit the PowerShell template string in server/src/api/enroll.rs. The script is generated dynamically with the server IP, agent certificate, and binary download URLs embedded.
F7: Anti-Kill Process Protection
Status: Done
| What | Where |
|---|---|
| ObRegisterCallbacks | driver/src/security/process.rs → register_process_protection() |
| Handle stripping | driver/src/security/process.rs → pre_operation_callback() strips PROCESS_TERMINATE |
| Registration | driver/src/lib.rs → called from DriverEntry |
To modify protection: Edit driver/src/security/process.rs. The pre_operation_callback function receives each handle-open request and can strip specific access rights. Currently strips PROCESS_TERMINATE and PROCESS_SUSPEND_RESUME.
F8: Registry Tamper Protection
Status: Done
| What | Where |
|---|---|
| CmRegisterCallbackEx | driver/src/security/registry.rs → register_registry_protection() |
| Key filtering | driver/src/security/registry.rs → registry_callback() blocks operations on EXFILGUARDIAN keys |
| Covered operations | RegNtPreDeleteKey, RegNtPreSetValueKey, RegNtPreDeleteValueKey, RegNtPreRenameKey |
To protect additional keys: Edit the key name filter in driver/src/security/registry.rs. Currently only protects SOFTWARE\EXFILGUARDIAN.
F9: DKOM Bypass
Status: Done (development only)
| What | Where |
|---|---|
| Force Integrity flag | driver/src/lib.rs → find_and_set_flag() |
| Module list traversal | driver/src/lib.rs → walks PsLoadedModuleList linked list |
| Flag modification | Sets bit 0x20 on LDR_DATA_TABLE_ENTRY.Flags |
Note: This is a development-only technique. In production, the driver should be signed with an EV certificate, making DKOM unnecessary.
F10: Cloud-Native Async Backend
Status: Done
| What | Where |
|---|---|
| Server entry | server/src/main.rs → tokio::select! for gRPC + REST |
| gRPC server | server/src/grpc/receiver.rs → Tonic-based ExfilService |
| REST API | server/src/api/routes.rs → Axum router |
| Config loading | server/src/core/config.rs → ServerConfig::load("config.yaml") |
| Pipeline | server/src/core/pipeline.rs → ServerPipeline (FlowTracker + AnalysisPipeline) |
| Bridge | server/src/core/bridge.rs → gRPC NetworkPacket → analysis PacketMetadata |
To add REST endpoints: Add a handler function in server/src/api/ and register the route in server/src/api/routes.rs → create_router().
To modify the pipeline: Edit server/src/core/pipeline.rs. The process_packet() method is the entry point for all incoming packets.
F11: Multi-Layer Analysis
Status: Done (analysis crate), partially wired (signature field gap)
The analysis engine is fully implemented in analysis/src/. Here's what exists and what needs work:
DPI (Deep Packet Inspection)
| Analyzer | File | Status |
|---|---|---|
| DNS (entropy, DGA, tunneling) | analysis/src/server/dpi/dns_analyzer.rs | Done |
| TLS (JA3, cert anomaly, SNI) | analysis/src/server/dpi/tls_analyzer.rs | Done |
| ICMP (covert channel, payload) | analysis/src/server/dpi/icmp_analyzer.rs | Done |
Signatures
| Component | File | Status |
|---|---|---|
| Rule struct | analysis/src/server/signatures/rule.rs | Done |
| Condition evaluator | analysis/src/server/signatures/condition.rs | Done (12 operators, 23 fields) |
| Engine | analysis/src/server/signatures/engine.rs | Done |
| YAML loader | analysis/src/server/signatures/loader.rs | Done (hot-reload) |
| YAML rules | signatures/{dns,flow,icmp,tls,http}/*.yaml | Done (16 rules) |
Known gap: The extract_fields() function in engine.rs only populates flow-level fields (23 fields: flow.*, net.*, process.*). Protocol-specific fields used in HTTP and TLS rules (like content_length, cert_self_signed, sni_cert_match) are not yet populated. DNS, HTTP, and TLS rules that reference these fields will silently fail to match.
To fix: Add protocol-specific field extraction in analysis/src/server/signatures/engine.rs → extract_fields(). The data is available in FlowRecord.dns_metadata and FlowRecord.tls_metadata; it just needs to be unpacked into the fields HashMap.
Behavioral
| Analyzer | File | Status |
|---|---|---|
| Baseline (Welford) | analysis/src/server/behavioral/baseline.rs | Done |
| Anomaly (Z-score, CUSUM) | analysis/src/server/behavioral/anomaly.rs | Done |
| Beaconing (CV) | analysis/src/server/behavioral/beaconing.rs | Done |
| Volume (EMA) | analysis/src/server/behavioral/volume.rs | Done |
Correlation
| Component | File | Status |
|---|---|---|
| Temporal window | analysis/src/server/correlation/temporal.rs | Done |
| Bayesian scorer | analysis/src/server/correlation/scorer.rs | Done |
| Alert engine | analysis/src/server/correlation/engine.rs | Done |
Pipeline Orchestrator
| Component | File | Status |
|---|---|---|
| Fan-out/fan-in | analysis/src/server/pipeline.rs | Done |
| Server integration | server/src/core/pipeline.rs | Done |
F12: All-Rust Ecosystem
Status: Done
All crates are pure Rust. No C, no FFI (except the kernel driver's WDK bindings which are Rust crates wrapping kernel APIs).
F13: Multi-Platform (Linux)
Status: TODO
The analysis crate already compiles on Linux/macOS. To add Linux endpoint support:
- Create
driver-linux/: An eBPF/XDP program that captures packets (equivalent of the WFP driver) - Modify
agent/: Add#[cfg(target_os = "linux")]paths for reading from eBPF maps instead of DeviceIoControl - Server: No changes needed; the server is already platform-agnostic
Where to Start for Each Task
"I need to add a new detection rule"
- Create a new
.yamlfile insignatures/<protocol>/ - Use available fields:
flow.*,net.*,process.*(seeengine.rs→extract_fields()) - The rule is picked up automatically by the hot-reload watcher
- See Signatures for the full YAML format
"I need to detect a new protocol"
- Add a new analyzer in
analysis/src/server/dpi/(e.g.,http_analyzer.rs) - Register it in
analysis/src/server/dpi/mod.rs - Call it from
analysis/src/server/pipeline.rs→analyze_flow() - Add new
ThreatCategoryvariants inanalysis/src/types/detection.rs
"I need to add a REST endpoint"
- Create handler in
server/src/api/(e.g.,agents.rs) - Add
pub mod agents;inserver/src/api/mod.rs - Register routes in
server/src/api/routes.rs→create_router() - The handler receives
State<Arc<ServerPipeline>>for access to pipeline data
"I need to modify the gRPC protocol"
- Edit
proto/exfil.proto, add fields or new RPCs - Run
cargo build -p exfil-serverandcargo build -p exfil-agent(build.rsregenerates the code) - Implement the server handler in
server/src/grpc/receiver.rs - Implement the client call in
agent/src/main.rs
"I need to wire the frontend to real data"
- Implement the IPC handlers in
desktop/electron/ipc/index.ts - Each handler should call the Rust REST API (
http://server:8080/api/v1/*) - The frontend hooks in
desktop/src/hooks/already use thewindow.exfilguardianAPI - Replace mock store data with TanStack Query hooks that call through IPC
"I need to change analysis configuration"
- Edit
config.yaml→analysis.server.*section - Config structs are in
analysis/src/config.rs - The server loads config in
server/src/core/config.rs→ServerConfig::load() - Analysis pipeline reads config in
analysis/src/server/pipeline.rs→AnalysisPipeline::new()