#namespaces #tcp #tcp-connection #linux #netns #forwarder #networking

app netns_tcp_bridge

Linux CLI tool to forward TCP connections from one network namespace to another network namespace

1 unstable release

0.1.0 Aug 9, 2022

#4 in #forwarder

22 downloads per month


381 lines


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:

It works 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.

Example session

usual_netns# unshare --net xterm&
usual_netns# dig +short example.com               | new_netns# ip link set lo up                                    | 
usual_netns# ip route get           | new_netns# ip route get via dev wlan0          |  RTNETLINK answers: Network is unreachable
    src uid 0   cache               |
usual_netns# curl --head    | new_netns# curl --head
 HTTP/1.1 404 Not Found                           |  curl: (7) Couldn't connect to server
 Content-Type: text/html                          | new_netns# curl --head
 Date: Mon, 08 Aug 2022 23:48:10 GMT              |  curl: (7) Failed to connect to
 Server: ECS (nyb/1D07)                           |         port 80: Connection refused
 Content-Length: 345                              | new_netns# echo $$
                                                  |  6448
usual_netns# netns_tcp_bridge -l \   |
                   -f /proc/6448/ns/net \         |
                   -c            |                          
                                                  | new_netns# curl --head
                                                  |  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


  • Tricky TCP features like FIN/RST distinction, OOB data are not preserved. Forwarding engine is a basic Tokio's copy_bidirectional.
  • Single-threaded operation may limit performance.
  • Non-usage of 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.

Usage message

netns_tcp_bridge --help
Usage: netns_tcp_bridge [OPTIONS]

Optional arguments:
  -h, --help
  -l, --listen LISTEN        Socket address (e.g. `` 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


~169K SLoC