-
-
Notifications
You must be signed in to change notification settings - Fork 973
Description
Is your feature request related to a problem? Please describe.
Running Nebird on AXIS cameras works, but only TCP seems to be properly forwarded.
# Works
ffplay -rtsp_transport tcp rtsp://root:[email protected]/axis-media/media.amp
# Fails
ffplay -rtsp_transport udp rtsp://root:[email protected]/axis-media/media.ampNetstack mode runs WireGuard entirely in userspace; the host OS has no route into the tunnel. The userspace forwarder only handles traffic coming from the tunnel toward the host: it can proxy inbound TCP/UDP to local listeners. It does not capture or route traffic that originates on the host (the camera).
RTSP-over-UDP is server-initiated: after SETUP, the camera’s RTSP server sends RTP/RTCP from the native stack to the client’s ports. Because there’s no outbound path into the tunnel in netstack mode, those UDP packets never enter WireGuard—hence silence. RTSP over TCP works because the client-initiated TCP connection is proxied inbound.
Describe the solution you'd like
I'd like it to work with UDP :-)
Describe alternatives you've considered
AI suggested this client trick:
The userspace forwarder only instantiates a UDP proxy when it first sees a packet on a given 5‑tuple. By poking the camera’s RTP/RTCP ports, we hope to create the mapping so that the camera’s outbound RTP/RTCP would flow back through the forwarder. It was a plausible workaround because TCP works (the inbound SYN triggers the proxy), so seeding UDP traffic might have unlocked the same path. In practice, even with correct ports (e.g., server_port=50000-50001) primed, the netstack forwarder still doesn’t carry the camera’s outbound UDP.
But after some tries it does not seem to work.
Additional context
@lixmal: summonning you here as you implemented the feature and might be interested.
AI suggest the following fix, not sure if hallucination or real path forward:
Add outbound UDP handling in netstack mode:
- Goal: give local-origin traffic a path into the userspace WireGuard stack when NB_USE_NETSTACK_MODE is on.
- Approach:
- Capture outbound UDP (and TCP, optionally) from the native stack destined for the NetBird network. Implementation options:
- Raw socket/pcap listener bound to the WireGuard IP and/or NetBird CIDR, filtering UDP.
- TPROXY-like userspace hook if available, but raw capture is simplest in netstack mode.
- Inject captured packets into the gVisor/WireGuard netstack:
- Parse the IP/UDP headers and call the forwarder’s InjectIncomingPacket (similar to inbound path, but in reverse direction). Alternatively, build a small “outbound forwarder” that mirrors the existing inbound forwarder but sources packets from captured native traffic.
- Maintain minimal state:
- Track 5‑tuple and NAT if needed (the existing conntrack could be reused or extended) to avoid duplicates and handle checksums after any port/address rewriting.
- Enforce ACLs: apply the same route ACL logic to outbound to avoid opening bypasses.
- Dial out to the peer:
- For UDP, the forwarder can already create a gonet.UDPConn bound to the netstack; use that to send the captured payload into the tunnel toward the remote client.
- Guardrails:
- Only enable when NB_USE_NETSTACK_MODE (or a new env flag) is set.
- Keep it limited to destinations in the NetBird network to avoid acting as a general NAT.
- Add logging at a low rate for visibility and a timeout for idle flows.
- Capture outbound UDP (and TCP, optionally) from the native stack destined for the NetBird network. Implementation options:
- Trade-offs:
- Added complexity and CPU: raw packet capture plus userspace forwarding.
- Needs careful checksum handling when rewriting and when injecting.
- Security: must respect ACLs and only forward to NetBird destinations.
- Minimal viable slice:
- UDP-only, NetBird-destination-only capture and injection, no NAT, reuse existing forwarder for injection, gated by env flag. This is enough to unblock RTSP-over-UDP from the camera.