Skip to content

Commit

Permalink
README and metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
vi committed Aug 8, 2022
1 parent c6f522b commit 63ac338
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 2 deletions.
7 changes: 5 additions & 2 deletions Cargo.toml
Expand Up @@ -2,8 +2,11 @@
name = "netns_tcp_bridge"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
categories = ["command-line-utilities", "network-programming"]
keywords = ["netns", "linux", "namespaces", "tcp", "forwarder"]
description = "Linux CLI tool to forward TCP connections from one network namespace to another network namespace"
repository = "https://github.com/vi/netns_tcp_bridge"
license = "MIT OR Apache-2.0"

[dependencies]
anyhow = { version = "1.0.59" }
Expand Down
78 changes: 78 additions & 0 deletions README.md
@@ -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
```

0 comments on commit 63ac338

Please sign in to comment.