feat(netprobe): IPv6 UDP + ICMPv6 flow attribution (#3425) #3528

Merged
mfreeman451 merged 2 commits from feat/netprobe-udp-icmp into staging 2026-06-04 20:14:14 +00:00
Owner

What

Extends netprobe flow attribution (built on the #3425 native add-on framework) to cover UDP-over-IPv6 and ICMPv6, on top of the base UDP/ICMP-v4 5-tuple fix.

netprobe (eBPF + userspace)

  • UDP/IPv6: udpv6_sendmsg/udpv6_recvmsg kprobes — IPv6 UDP never traverses the v4 udp_* path, so it was missed entirely. Both share a new emit_udp helper (socket_tuple reads the family → one helper serves v4 + v6).
  • ICMPv6: ping_v6_sendmsg/rawv6_sendmsg kprobes; emit_icmp_send derives IPPROTO_ICMPV6 (58) from the socket address family.
  • All v6 probes attach best-effort (attach_optional_probe, renamed from attach_icmp_probe) — a missing optional hook (IPv6 disabled, renamed symbol) must not take down core TCP/UDP attribution.
  • Userspace accepts proto 58 in flow_key_from_record; transport_protocol maps 58 → "icmpv6".

core

  • The pushed FlowAttributionEvent transport string "icmpv6" was being dropped by flow_attribution.ex (it only knew icmp6/ipv6-icmp), so ICMPv6 rows never reached flow_process_attributions. Both transport_to_proto mappings (flow_attribution + attributed_flow_joiner) now accept all three variants icmp6/icmpv6/ipv6-icmp → 58.

Validation

On a kernel 6.8 box (attribution-only mode), flow_process_attributions now carries:

  • TCP v4 + v6 (proto 6)
  • UDP v4 + v6 (proto 17) — v6 via udpv6_sendmsg
  • ICMP v4 (proto 1)
  • ICMPv6 kprobes fire and reach FLOW_EVENTS (flow_to_pid family=10 proto=58); end-to-end proto-58 rows land once this core proto-mapping fix is deployed.

🤖 Generated with Claude Code

## What Extends netprobe flow attribution (built on the #3425 native add-on framework) to cover **UDP-over-IPv6** and **ICMPv6**, on top of the base UDP/ICMP-v4 5-tuple fix. ### netprobe (eBPF + userspace) - **UDP/IPv6**: `udpv6_sendmsg`/`udpv6_recvmsg` kprobes — IPv6 UDP never traverses the v4 `udp_*` path, so it was missed entirely. Both share a new `emit_udp` helper (`socket_tuple` reads the family → one helper serves v4 + v6). - **ICMPv6**: `ping_v6_sendmsg`/`rawv6_sendmsg` kprobes; `emit_icmp_send` derives `IPPROTO_ICMPV6` (58) from the socket address family. - All v6 probes attach **best-effort** (`attach_optional_probe`, renamed from `attach_icmp_probe`) — a missing optional hook (IPv6 disabled, renamed symbol) must not take down core TCP/UDP attribution. - Userspace accepts proto 58 in `flow_key_from_record`; `transport_protocol` maps 58 → `"icmpv6"`. ### core - The pushed `FlowAttributionEvent` transport string `"icmpv6"` was being dropped by `flow_attribution.ex` (it only knew `icmp6`/`ipv6-icmp`), so ICMPv6 rows never reached `flow_process_attributions`. Both `transport_to_proto` mappings (`flow_attribution` + `attributed_flow_joiner`) now accept all three variants `icmp6`/`icmpv6`/`ipv6-icmp` → 58. ## Validation On a kernel 6.8 box (attribution-only mode), `flow_process_attributions` now carries: - **TCP** v4 + v6 (proto 6) - **UDP** v4 + v6 (proto 17) — v6 via `udpv6_sendmsg` - **ICMP** v4 (proto 1) - ICMPv6 kprobes fire and reach `FLOW_EVENTS` (`flow_to_pid` family=10 proto=58); end-to-end proto-58 rows land once this core proto-mapping fix is deployed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
netprobe only attributed TCP: the udp_sendmsg/udp_recvmsg kprobes emitted
FlowTuple::empty() (zero 5-tuple, dropped in userspace), and only the
inet_sock_set_state tracepoint (TCP-only) populated a tuple. So UDP (NTP, DNS)
and ICMP (ping) flows never got a process attribution.

- eBPF: read the real 5-tuple off `struct sock` (sock_common) in the UDP kprobes
  via a `socket_tuple` helper using offset_of! on a #[repr(C)] sock_common mirror
  (offsets validated against the committed vmlinux.h); fail-safe bpf_probe_read.
- ICMP: add ping_v4_sendmsg (dgram ICMP) + raw_sendmsg (raw ICMP) kprobes emitting
  proto=1 with the socket IPs and zero ports; attached BEST-EFFORT so a missing
  per-kernel symbol can't take down TCP/UDP attribution.
- userspace: accept proto 17 + proto 1 (ICMP has no ports → keep zero-port records).

Validated on kernel 6.8 (box 192.168.1.62), attribution-only mode: TCP/UDP/ICMP
all attributed (p6/p17/p1), UDP tuples correct (e.g. NTP 129.6.15.28:123, DNS
8.8.8.8:53 → comm=bash). No XDP/capture touched — no black-hole risk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(netprobe): IPv6 UDP + ICMPv6 flow attribution (#3425)
Some checks failed
Netprobe eBPF Verifier / Verify eBPF programs on Linux 5.15 (push) Waiting to run
Netprobe eBPF Verifier / Verify eBPF programs on Linux 5.8 (push) Waiting to run
Netprobe eBPF Verifier / Verify eBPF programs on Linux 6.x (push) Waiting to run
Netprobe eBPF Verifier / Verify eBPF refusal on Linux 5.4 (push) Waiting to run
Rust Tests / test-rust (rust/rdp-adapter, cargo) (push) Successful in 1m16s
Helm Lint / Helm Lint (pull_request) Successful in 39s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 1m27s
Secret Scan / gitleaks (pull_request) Successful in 43s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m12s
lint / lint (push) Successful in 2m2s
Rust Tests / test-rust (//rust/rperf-server:rperf, rust/rperf-server, bazel) (push) Successful in 2m7s
Rust Tests / test-rust (//rust/netprobe:netprobe, //build/platforms:linux_x86_64_musl, rust/netprobe, bazel-static) (push) Successful in 2m26s
Rust Tests / test-rust (rust/rperf-client, cargo) (push) Successful in 2m29s
Rust Tests / test-rust (//rust/netprobe:netprobe_test, rust/netprobe, bazel-test) (push) Successful in 2m38s
Rust Tests / test-rust (rust/trapd, cargo) (push) Successful in 2m36s
Rust Tests / test-rust (rust/consumers/zen, cargo) (push) Successful in 2m50s
Golang Tests / test-go (push) Successful in 3m1s
Rust Tests / test-rust (rust/log-collector, cargo) (push) Successful in 3m3s
Rust Tests / test-rust (//rust/netprobe:netprobe, //build/platforms:linux_aarch64_musl, rust/netprobe, bazel-static) (push) Successful in 3m12s
lint / lint (pull_request) Successful in 2m43s
Rust Tests / test-rust (rust/rdp-connector-probe, cargo) (push) Successful in 3m42s
Rust Tests / test-rust (rust/srql, cargo) (push) Successful in 5m7s
Elixir Quality / Elixir Quality (pull_request) Failing after 13m50s
CI / build (pull_request) Failing after 23m26s
9d807e6993
UDP-over-IPv6 traverses udpv6_sendmsg/udpv6_recvmsg, never the v4
udp_* path, so the v4-only hooks missed UDP/IPv6 entirely. Add
udpv6_sendmsg/udpv6_recvmsg kprobes sharing a new emit_udp helper
(socket_tuple already reads the address family, so one helper serves
both v4 and v6).

ICMPv6: add ping_v6_sendmsg/rawv6_sendmsg kprobes; emit_icmp_send now
derives IPPROTO_ICMPV6 (58) from the socket family so the protocol
stays consistent with the v6 addresses. All v6 probes attach
best-effort via attach_optional_probe (renamed from attach_icmp_probe)
- a missing optional hook (IPv6 disabled, renamed/inlined symbol) must
not take down the core TCP/UDP attribution that just loaded.

netprobe userspace: accept proto 58 in flow_key_from_record;
transport_protocol maps 58 -> "icmpv6".

core: the pushed FlowAttributionEvent transport string "icmpv6" was
dropped by flow_attribution.ex (it only recognized icmp6/ipv6-icmp),
so ICMPv6 rows never reached flow_process_attributions. Align both
transport_to_proto mappings (flow_attribution + attributed_flow_joiner)
to accept all three variants icmp6/icmpv6/ipv6-icmp -> 58.

Validated on a kernel 6.8 box (attribution-only mode): fpa now carries
TCP and UDP over both IPv4 and IPv6 (proto 6/17, v4+v6) plus ICMP v4;
ICMPv6 kprobes fire and reach FLOW_EVENTS (flow_to_pid family=10
proto=58).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mfreeman451 deleted branch feat/netprobe-udp-icmp 2026-06-04 20:14:14 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!3528
No description provided.