Skip to main content

Network event capture and scan detection

What this page is

How the Linux sensor captures inbound TCP connection attempts, how the collector bridges those network events to the backend detection plane, and how that path turns a port scan into a T1046 network-service-discovery alert. It also names the deterministic injector that proves the path without live traffic.

Why it exists this way

ADR 044 added network, file, and DNS event classes to a pipeline that previously carried one OCSF record type end to end. A process tree without its network egress is half an investigation, and a port scan is invisible without connection telemetry. Detection coverage (ADR 040) depends on those classes being present.

The capture stays kernel-verifiable by reading tracepoint payloads at documented byte offsets rather than dereferencing kernel structs, so the eBPF programs pass the verifier against the pinned nightly without BTF struct relocations.

How it works

Kernel capture

The network program in crates/edr-linux-ebpf/ attaches to the sock:inet_sock_set_state tracepoint and emits on the TCP state transitions that matter for scan detection, including the move into SYN_RECV for an inbound connection attempt. It writes a #[repr(C)] event into the NET_EVENTS ring buffer. The user-space Runtime drains that buffer in its own consumer thread and normalises each record in crates/edr-linux/src/ocsf.rs to OCSF network_activity (class_uid 4001), captured as one variant of the OcsfRecord sum type so the wire format is unchanged.

Collector bridge

The collector forwards network events to the backend detection plane through crates/collector/src/bridge.rs. The bridge takes the OCSF records the sensor ships over gRPC and posts them to the backend so the streaming detection workers can score them against the rule corpus. This is what closes the loop from a kernel event on the endpoint to an alert in the operator console.

Scan to alert

A host that receives connection attempts on many ports in a short window produces a burst of inbound network_activity records. The detection plane recognises that shape and raises a T1046 network-service-discovery alert, so an nmap scan against a monitored host surfaces as a triaged alert rather than silent traffic.

Verifying the path

The deterministic injector at crates/collector/examples/inject_scan.rs feeds EDR-shaped network events into the bridge without any live capture, and tests/backend/test_network_telemetry_detection.py asserts the injected scan is detected. Run those to prove the end-to-end path on a host that cannot run the eBPF capture.

What goes wrong

  • No NET_EVENTS records on a kernel that lacks the sock:inet_sock_set_state tracepoint. The program fails to attach at load time; check the loader log.
  • Events captured but no alert: confirm the collector bridge target URL is reachable and the detection workers are running. The injector isolates the bridge-to-detection half from the kernel half.