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_EVENTSrecords on a kernel that lacks thesock:inet_sock_set_statetracepoint. 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.