Repository navigation
eBPF WG proxy: injected packets dropped after ICE handover on Kubernetes nodes (EPERM) #7489
Unanswered
Spiritreader
asked this question in
Issue Triage
Replies: 1 comment
|
netbird-talos-unraid-ums-w-1-redacted.log Here are the full redacted logs |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Before posting
Affected area
Client / Agent
Deployment type
Self-hosted - advanced/custom deployment
Operating system or environment
Linux, Kubernetes
NetBird version and upgrade status
kubeProxyReplacement: falseDid this work before?
Not sure
Regression details
No response
Summary
Disclaimer: I'm only somewhat confident in this bug report's causality as I have done this with Claude. At the very least the issue exists in this k8s scenario and the cause makes sense to me looking at the logs and iptables rules.
Whenever a connection drops to relay, the eBPF injection for the relay fails:
Rate on two nodes, sampled over a 6.7 minute window (2000 log lines each): 1203 and
1415 occurrences.
Happens every time when a peer transitions to relay
Socket creation succeeds, so
CAP_NET_RAWis present. Onlysendtofails.Current behavior
client/iface/wgproxy/ebpf/wrapper.go(v0.76.3):Two callers pass different endpoints:
endpoint.IPAddTurnConn(ebpf/proxy.go:122)net.ParseIP(loopbackAddr), 127.0.0.1RedirectAs(ebpf/wrapper.go:190-215)The kubelet creates this rule in the filter table on every node
(
pkg/kubelet/kubelet_network_linux.go, "block incoming localnet connections"):Packets from
RedirectAsmatch it: non-loopback source, loopback destination, anduntracked. A
NF_DROPverdict in the output hook is returned to the sender asEPERM, which is the errno logged.The steady-state case passes because NetBird's own rules exempt it, and those
counters show the mechanism working when the source is loopback:
Both rules require
ip saddr 127.0.0.1, so they do not cover the redirected shape.client/iface/wgproxy/udp/rawsocket.gohas the same problem:NewSrcFakeris calledfrom
WGUDPProxy.RedirectAswith the peer endpoint, so settingNB_DISABLE_EBPF_WG_PROXY=truemoves the error rather than avoiding it.Every injected packet fails with
sendto: operation not permitted, and thekubelet's drop counter is the only rule in the output path matching that packet shape.
Expected behavior
Relay connection can be established successfully.
The injected packets reach the local WireGuard listener.
Steps to reproduce
KUBE-FIREWALLruleis present. Confirm with
nft list chain ip filter KUBE-FIREWALL.for example by having one side behind a NAT that drops idle UDP mappings.
Environment and topology
Self-hosted details, if available
No response
Logs, status output, or debug evidence
Related issues or discussions
No response
Impact
Workaround
Allow injected packets
Use the client's WireGuard listen port if it is not 51820. The rule has to sit ahead
of the jump to the kubelet's chain. On our nodes the chain reads:
An accept verdict reached before that jump ends traversal of the filter hook, so the
injected packet is delivered and both the relayed and the redirected paths work.
Two things to know about it. It narrows the kubelet's anti-spoof rule for one UDP
port on the loopback interface; since only locally generated packets reach the output
hook, nothing from the wire is admitted by it. And it does not survive a reboot on its
own. An immutable distribution such as Talos has no place in machine configuration for
an output rule, so keeping it means a privileged DaemonSet or equivalent that
re-asserts it, which is a component whose only job is this rule.
Additional context
Suggested Fixes
output path, ahead of the kubelet's chain. NetBird already manages rules in that
table (
netbird-raw-out,netbird-acl-*), so this fits the existing shape; thecurrent
netbird-raw-outrules would need to match the redirected source too.port, as the eBPF port swap already does, so no packet ever has a non-loopback
source with a loopback destination.
EPERMfromsendPkgas a signal to fallback to the loopback-sourced header, so a handover degrades to working relay
instead of a silent blackhole.
All reactions