Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
83 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# netns_tcp_bridge | ||
|
||
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 [socat][s]s, 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 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][gr]. | ||
|
||
# Example session | ||
|
||
``` | ||
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 | ||
``` | ||
|
||
|
||
# Limitations | ||
|
||
* Tricky TCP features like FIN/RST distinction, OOB data are not preserved. Forwarding engine is a basic Tokio's [`copy_bidirectional`][cb]. | ||
* 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. | ||
|
||
[cb]:https://docs.rs/tokio/latest/tokio/io/fn.copy_bidirectional.html | ||
[s]:http://www.dest-unreach.org/socat/ | ||
[gr]:https://github.com/vi/netns_tcp_bridge/releases/ | ||
|
||
# Usage message | ||
|
||
``` | ||
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 | ||
``` |