Documents
Protobuf IPC Implementation
Protobuf IPC Implementation
Type
External
Status
Published
Created
Mar 8, 2026
Updated
Apr 3, 2026
Updated by
Dosu Bot

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