Documents
Protobuf IPC Implementation
Protobuf IPC Implementation
Type
External
Status
Published
Created
Apr 18, 2026
Updated
Apr 18, 2026
Source
View

This document describes the Protocol Buffer implementation for Inter-Process Communication (IPC) between the procmond and daemoneye-agent components in DaemonEye.

Overview#

The protobuf schema defines type-safe message contracts that enable efficient and reliable communication between:

  • procmond: Privileged process collector
  • daemoneye-agent: Detection orchestrator

Message Types#

Core Messages#

DetectionTask#

Sent from daemoneye-agent to procmond to request process data collection.

message DetectionTask {
    string task_id = 1; // Unique correlation ID
    TaskType task_type = 2; // Type of operation
    optional ProcessFilter process_filter = 3; // Optional filtering
    optional HashCheck hash_check = 4; // Optional hash verification
    optional string metadata = 5; // Optional task metadata
}

DetectionResult#

Returned from procmond to daemoneye-agent with collection results.

message DetectionResult {
    string task_id = 1; // Matching correlation ID
    bool success = 2; // Operation success status
    optional string error_message = 3; // Error details if failed
    repeated ProcessRecord processes = 4; // Collected process data
    optional HashResult hash_result = 5; // Hash verification result
}

Data Types#

ProcessRecord#

Comprehensive process information structure.

message ProcessRecord {
    uint32 pid = 1; // Process ID
    optional uint32 ppid = 2; // Parent process ID
    string name = 3; // Process name
    optional string executable_path = 4; // Full executable path
    repeated string command_line = 5; // Command line arguments
    optional int64 start_time = 6; // Start time (Unix timestamp)
    optional double cpu_usage = 7; // CPU usage percentage
    optional uint64 memory_usage = 8; // Memory usage in bytes
    optional string executable_hash = 9; // File hash (hex-encoded)
    optional string hash_algorithm = 10; // Hash algorithm name
    optional string user_id = 11; // User ID
    bool accessible = 12; // Data accessibility flag
    bool file_exists = 13; // Executable file existence
    int64 collection_time = 14; // Collection timestamp (millis)
}

TaskType Enum#

enum TaskType {
    ENUMERATE_PROCESSES = 0; // List all accessible processes
    CHECK_PROCESS_HASH = 1; // Verify executable hash
    MONITOR_PROCESS_TREE = 2; // Monitor process hierarchy
    VERIFY_EXECUTABLE = 3; // Verify executable integrity
}

ProcessFilter#

message ProcessFilter {
    repeated string process_names = 1; // Filter by process names
    repeated uint32 pids = 2; // Filter by process IDs
    optional string executable_pattern = 3; // Filter by path pattern
}

HashCheck/HashResult#

message HashCheck {
    string expected_hash = 1; // Expected hash value
    string hash_algorithm = 2; // Algorithm (e.g., "sha256")
    string executable_path = 3; // Path to verify
}

message HashResult {
    string hash_value = 1; // Computed hash
    string algorithm = 2; // Algorithm used
    string file_path = 3; // File path processed
    bool success = 4; // Computation success
    optional string error_message = 5; // Error details if failed
}

Rust Integration#

Module Structure#

The protobuf types are available in the daemoneye_lib::proto module:

use daemoneye_lib::proto::{
    DetectionResult, DetectionTask, ProtoHashCheck, ProtoHashResult,
    ProtoProcessFilter, ProtoProcessRecord, ProtoTaskType,
};

Type Conversions#

Automatic conversions between native and protobuf types:

use daemoneye_lib::models::process::ProcessRecord;
use daemoneye_lib::proto::ProtoProcessRecord;

fn convert_process_record() {
    // Convert native to protobuf
    let native_process = ProcessRecord::new(1234, "firefox".to_string());
    let proto_process: ProtoProcessRecord = native_process.into();

    // Convert protobuf to native
    let converted_back: ProcessRecord = proto_process.into();
}

Helper Methods#

fn create_tasks_and_results() {
    // Create enumeration task
    let task = DetectionTask::new_enumerate_processes("task-123", None);

    // Create hash check task
    let hash_check = ProtoHashCheck {
        expected_hash: "abc123...".to_string(),
        hash_algorithm: "sha256".to_string(),
        executable_path: "/usr/bin/firefox".to_string(),
    };
    let task = DetectionTask::new_hash_check("task-456", hash_check);

    // Create results
    let processes = vec![];
    let success = DetectionResult::success("task-123", processes);
    let failure = DetectionResult::failure("task-123", "Permission denied");
}

Build System Integration#

Dependencies#

[dependencies]
prost = "0.13.5"
prost-types = "0.13.5"
serde = { version = "1.0", features = ["derive"] }

[build-dependencies]
prost-build = "0.13.5"

Build Script#

Automatic code generation via build.rs:

fn main() -> Result<(), Box<dyn std::error::Error>> {
    prost_build::Config::new()
        .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]")
        .protoc_arg("--experimental_allow_proto3_optional")
        .compile_protos(&["proto/ipc.proto"], &["proto/"])?;
    Ok(())
}

Generated Code#

The build system generates type-safe Rust structs with:

  • Automatic serialization/deserialization support
  • JSON compatibility via serde
  • Optional field handling
  • Type safety with strong typing

Security Considerations#

Message Validation#

  • All messages include correlation IDs for request/response matching
  • Optional fields provide graceful degradation
  • Error messages are structured and actionable

Size Limits#

  • Individual messages limited to prevent DoS attacks
  • Streaming support for large result sets
  • Backpressure mechanisms in transport layer

Type Safety#

  • Strongly typed enums prevent invalid operations
  • Required fields enforce data integrity
  • Optional fields provide extensibility

Usage Examples#

Basic Process Enumeration#

fn basic_process_enumeration() -> Result<(), Box<dyn std::error::Error>> {
    let task = DetectionTask::new_enumerate_processes("enum-001", None);
    let bytes = prost::Message::encode_to_vec(&task);
    // Send via IPC transport...

    // Deserialize response
    let result = DetectionResult::decode(&response_bytes[..])?;
    if result.success {
        for process in result.processes {
            println!("Process: {} (PID: {})", process.name, process.pid);
        }
    }
    Ok(())
}

Filtered Process Collection#

use daemoneye_lib::proto::ProtoProcessFilter;

fn filtered_process_collection() {
    let filter = ProtoProcessFilter {
        process_names: vec!["firefox".to_string(), "chrome".to_string()],
        pids: vec![],
        executable_pattern: Some("/usr/bin/*".to_string()),
    };
    let task = DetectionTask::new_enumerate_processes("filtered-001", Some(filter));
}

Hash Verification#

use daemoneye_lib::proto::ProtoHashCheck;

fn hash_verification() {
    let hash_check = ProtoHashCheck {
        expected_hash: "a1b2c3d4...".to_string(),
        hash_algorithm: "sha256".to_string(),
        executable_path: "/usr/bin/suspicious".to_string(),
    };
    let task = DetectionTask::new_hash_check("verify-001", hash_check);
}

Performance Characteristics#

Serialization Efficiency#

  • Binary protobuf format provides compact serialization
  • Typical message sizes: 50-500 bytes for tasks, 1-10KB for results
  • Zero-copy deserialization where possible

Memory Usage#

  • Streaming support prevents unbounded memory growth
  • Optional fields reduce memory footprint
  • Efficient string handling with Rust's ownership model

Testing#

The implementation includes comprehensive tests for:

  • Message creation and validation
  • Type conversions between native and protobuf formats
  • Serialization/deserialization round-trips
  • Error handling and edge cases
    Run tests with: just test

Future Extensions#

The protobuf schema is designed for evolution:

  • Optional fields enable backward compatibility
  • Reserved field numbers prevent conflicts
  • Extensible message types support new features
  • Versioned schemas for major changes