Skip to content

Probe Framework and Extension Mechanism

Relevant source files

The following files were used as context for generating this wiki page:

This page documents the internal framework used by eCapture to manage eBPF probes. It defines the interfaces, base templates, and registration patterns that allow eCapture to support multiple capture targets (TLS, Databases, Shells) across different platforms (Linux, Android) and kernel modes (CO-RE, non-CO-RE).

Core Interfaces and Contracts

The framework is built upon a set of domain interfaces defined in internal/domain/. These interfaces establish the contract between the CLI control plane and the probe implementations.

Configuration Contract

Every probe must have a configuration object that implements the Configuration interface. This ensures that common settings like PID filtering, UID filtering, and BTF modes are handled consistently.

internal/domain/configuration.go:20-77

MethodPurpose
Validate()Ensures probe-specific settings (e.g., library paths) are correct.
GetBTF()Returns the BTF mode (Auto, CO-RE, or Non-CO-RE).
GetPid() / GetUid()Provides the target filters for the eBPF programs.
GetPerfReorder()Returns settings for userland event reordering by timestamp.

Probe and Event Contracts

The Probe interface defines the lifecycle of an eBPF-based capture module, while EventDecoder defines how raw bytes from the kernel are transformed into structured Go objects.

internal/domain/probe.go:20-42internal/domain/event.go:20-43

Base Classes and Inheritance

To reduce boilerplate, eCapture provides base implementations for configurations and probes.

BaseConfig

The BaseConfig struct in internal/config/ provides the standard fields for every probe, such as Pid, Uid, and BtfMode.

internal/config/base_config.go:45-66

BaseProbe (Template Method Pattern)

The BaseProbe in internal/probe/base/ implements the standard lifecycle of a probe. It handles logger initialization, dispatcher setup, and the management of perf/ring buffer readers.

internal/probe/base/base_probe.go:46-56

Lifecycle Sequence:

  1. Initialize: Sets up the EventDispatcher and registers output writers (e.g., Text, PCAP). internal/probe/base/base_probe.go:73-135
  2. Start: Transitions the probe to a running state. internal/probe/base/base_probe.go:139-147
  3. Stop: Gracefully halts capture. internal/probe/base/base_probe.go:150-158
  4. Close: Releases all resources, closes eBPF maps, and waits for reader goroutines to exit. internal/probe/base/base_probe.go:173-215

Sources:

Data Flow Architecture

The following diagram illustrates the relationship between the domain interfaces and their concrete implementations during the lifecycle of a probe.

Probe Framework Entity Map

Title: Entity Relationship and Data Flow

Sources: internal/domain/configuration.go:20-77, internal/probe/base/base_probe.go:46-56, internal/probe/openssl/openssl_probe.go:45-58

Factory Registration Pattern

eCapture uses a factory pattern in internal/factory/ to decouple the CLI from specific probe implementations. This allows the CLI to instantiate probes by a string identifier (e.g., "tls", "gotls").

Implementation in Concrete Probes

Each probe typically provides a NewProbe() function that returns an initialized instance.

internal/probe/openssl/openssl_probe.go:61-68internal/probe/gotls/gotls_probe.go:70-77

Factory Logic

The factory maintains a registry of available probe types. When a user runs a command like ecapture tls, the factory retrieves the corresponding probe constructor.

Title: Factory Registration and Initialization

Sources: internal/factory/factory.go:1-50, internal/probe/openssl/openssl_probe.go:61-98

Extension Mechanism: Adding a New Probe

The framework is designed for easy extension. Adding a new probe (e.g., for a new database or protocol) involves:

  1. Define Configuration: Create a struct that embeds config.BaseConfig.
  2. Define Events: Create structs that implement domain.EventDecoder to parse the eBPF data.
  3. Implement Probe: Create a struct that embeds base.BaseProbe.
  4. Register with Factory: Add the new probe type to internal/factory/.

Bytecode Selection

The BaseProbe provides a helper GetBPFName which automatically appends _core.o or _noncore.o based on the user's configuration and kernel support.

internal/probe/base/base_probe.go:161-171

Sources:

Probe Framework and Extension Mechanism has loaded