Linux CLI tool to forward TCP connections from one network namespace to another network namespace
MIT License
Special TCP forwarder (proxy) where listening part and connecing part can move to other
Linux network namespaces using setns(2)
call.
It is somewhat analogous to using a pair of socats, each in different netns.
socat tcp-l:1234,fork,reuseaddr unix:/path/to/unix-socket-shared-between-namespaces.sock
socat unix-listen:/path/to/unix-socket-shared-between-namespaces.sock tcp:127.0.0.1:1234
It works by forking into two processes: listener and connector and by passing (SCM_RIGHTS
) connected sockets from listener over a socketpair(2)
to the connector process. Each part can be moved into each own network namespace.
Build it with cargo build --release
or download it from Github releases.
usual_netns# unshare --net xterm&
usual_netns# dig +short example.com | new_netns# ip link set lo up
93.184.216.34 |
usual_netns# ip route get 93.184.216.34 | new_netns# ip route get 93.184.216.34
93.184.216.34 via 192.168.0.1 dev wlan0 | RTNETLINK answers: Network is unreachable
src 192.168.0.185 uid 0 cache |
usual_netns# curl --head http://93.184.216.34/ | new_netns# curl --head http://93.184.216.34/
HTTP/1.1 404 Not Found | curl: (7) Couldn't connect to server
Content-Type: text/html | new_netns# curl --head http://127.0.0.1/
Date: Mon, 08 Aug 2022 23:48:10 GMT | curl: (7) Failed to connect to 127.0.0.1
Server: ECS (nyb/1D07) | port 80: Connection refused
Content-Length: 345 | new_netns# echo $$
| 6448
usual_netns# netns_tcp_bridge -l 127.0.0.1:80 \ |
-f /proc/6448/ns/net \ |
-c 93.184.216.34:80 |
| new_netns# curl --head http://127.0.0.1/
| HTTP/1.1 404 Not Found
| Content-Type: text/html
| Date: Mon, 08 Aug 2022 23:53:32 GMT
| Server: ECS (nyb/1D2E)
| Content-Length: 345
copy_bidirectional
.io_uring
also limits performance - each forwarded packet is two or three syscalls.Note that I have implemented more modes (e.g. using raw FDs), but have tested only the most straightforward mode.
netns_tcp_bridge --help
Usage: netns_tcp_bridge [OPTIONS]
Optional arguments:
-h, --help
-l, --listen LISTEN Socket address (e.g. `127.0.0.1:1234` or `[::1]:1234`) to bind socket to.
-L, --listen-fd LISTEN-FD File descriptor to use as a listening socket
-S, --preaccepted-fd PREACCEPTED-FD
File descriptor to use as a single connected client (skip listening and accepting loop)
-c, --connect CONNECT Socket address to forward incoming connections to.
-C, --connect-fd CONNECT-FD
Pre-connected file descriptor to forward just one accepted connection to
-f, --listen-netns-file LISTEN-NETNS-FILE
Path to a nsfs file with mounted network namespace where listening part of the forwarder should operate. E.g. /proc/1234/ns/net
-F, --listen-netns-fd LISTEN-NETNS-FD
Already opened file descriptor to use for the `setns` call on listening side
-t, --connect-netns-file CONNECT-NETNS-FILE
Path to a nsfs netns file to `setns` on the connecting side
-T, --connect-netns-fd CONNECT-NETNS-FD
Already opened file descriptor to use for the `setns` call on the connecting side