Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6de5934d3 | |||
739cca01c4 | |||
90cab573eb | |||
82aa6e0a4f | |||
b7373d6da5 | |||
37b120d2e5 | |||
ba4bbfa18c | |||
2b1095760f |
24
Makefile
Normal file
24
Makefile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
PREFIX=/usr
|
||||||
|
|
||||||
|
install:
|
||||||
|
install -Dm 644 nnss-ssh@.service -t "$(PREFIX)/lib/systemd/system"
|
||||||
|
install -Dm 644 nnssA@.service -t "$(PREFIX)/lib/systemd/system"
|
||||||
|
install -Dm 644 nnssB@.service -t "$(PREFIX)/lib/systemd/system"
|
||||||
|
install -Dm 644 nnss-sproxy@.service -t "$(PREFIX)/lib/systemd/system"
|
||||||
|
install -Dm 644 nnss-sproxy@.socket -t "$(PREFIX)/lib/systemd/system"
|
||||||
|
install -Dm 644 ssh_config -t "$(PREFIX)/lib/nnss"
|
||||||
|
install -Dm 755 tunsocks.sh -t "$(PREFIX)/lib/nnss"
|
||||||
|
install -Dm 644 README.md -t "$(PREFIX)/share/doc/nnss"
|
||||||
|
install -Dm 644 LICENSE -t "$(PREFIX)/share/doc/nnss"
|
||||||
|
install -Dm 644 tmpfiles.conf "$(PREFIX)/lib/tmpfiles.d/nnss.conf"
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rf "$(PREFIX)/lib/nnss" \
|
||||||
|
"$(PREFIX)/share/doc/nnss" \
|
||||||
|
"$(PREFIX)/lib/tmpfiles.d/nnss.conf" \
|
||||||
|
"$(PREFIX)/lib/systemd/system/nnssA@.service" \
|
||||||
|
"$(PREFIX)/lib/systemd/system/nnssB@.service" \
|
||||||
|
"$(PREFIX)/lib/systemd/system/nnss-sproxy@.service" \
|
||||||
|
"$(PREFIX)/lib/systemd/system/nnss-sproxy@.socket" \
|
||||||
|
"$(PREFIX)/lib/systemd/system/nnss-ssh@.service"
|
93
README.md
93
README.md
@@ -1,14 +1,31 @@
|
|||||||
# Network Namespace setup using SSH SOCKS proxy
|
# Network Namespace setup using SSH SOCKS proxy
|
||||||
|
|
||||||
Create network namespace where all¹ network requests go via ssh connection.
|
Create network namespace where all¹ network requests go via socks proxy.
|
||||||
|
|
||||||
|
## Dependency
|
||||||
|
|
||||||
|
Depends on [tun2socks][4]. Install from [AUR][5] or compile from [source][6].
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
1. Install from [AUR][2].
|
1. Install from [AUR][2].
|
||||||
2. Download and install pre-built archlinux package: [link][3].
|
2. Manual installation:
|
||||||
3. For other linux, copy the files to appropriate path as done [here][4].
|
|
||||||
|
|
||||||
## Creating new namespace
|
This will install under `/usr`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Change install directory using `PREFIX`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo make PREFIX=/usr/local install
|
||||||
|
```
|
||||||
|
|
||||||
|
For uninstall, run `make uninstall` or `make PREFIX=<prefix> uninstall`
|
||||||
|
|
||||||
|
## Type A: Use ssh to create socks proxy
|
||||||
|
|
||||||
1. Create a simple ssh config at `/etc/nnss/<namespace_name>/config`. This will
|
1. Create a simple ssh config at `/etc/nnss/<namespace_name>/config`. This will
|
||||||
be included with [other settings][0].
|
be included with [other settings][0].
|
||||||
@@ -37,14 +54,14 @@ Port 8822 # If the ssh server is not on default port 22
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Testing namespace
|
### Testing namespace
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
❯ sudo systemd-run \
|
❯ sudo systemd-run \
|
||||||
--property=NetworkNamespacePath=/run/netns/vps1ns \
|
--property=NetworkNamespacePath=/run/netns/vps1ns \
|
||||||
--property=User=$USER \
|
--property=User=$USER \
|
||||||
--property=Requires=nnssA@vps1.service \
|
--property=Requires=nnssA@vps1.service \
|
||||||
--property=After=nnssA@vps1.service \
|
--property=After=nnssA@vps1.service \
|
||||||
--shell
|
--shell
|
||||||
[sudo] password for balki:
|
[sudo] password for balki:
|
||||||
Running as unit: run-p233279-i233579.service
|
Running as unit: run-p233279-i233579.service
|
||||||
@@ -66,17 +83,57 @@ xx.xx.xx.xx
|
|||||||
valid_lft forever preferred_lft forever
|
valid_lft forever preferred_lft forever
|
||||||
inet6 fe80::fd64:c3f3:ce6:650c/64 scope link stable-privacy proto kernel_ll
|
inet6 fe80::fd64:c3f3:ce6:650c/64 scope link stable-privacy proto kernel_ll
|
||||||
valid_lft forever preferred_lft forever
|
valid_lft forever preferred_lft forever
|
||||||
|
|
||||||
❯
|
|
||||||
Finished with result: success
|
|
||||||
Main processes terminated with: code=exited, status=0/SUCCESS
|
|
||||||
Service runtime: 1min 4.383s
|
|
||||||
CPU time consumed: 201ms
|
|
||||||
Memory peak: 5.7M (swap: 0B)
|
|
||||||
IP traffic received: 3.2K sent: 1.3K
|
|
||||||
IO bytes written: 304K
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Type B: Use existing socks proxy
|
||||||
|
|
||||||
|
1. Create an environment file at `/etc/nnss/env_<namespace_name>`. This file
|
||||||
|
should contain one environment variable `SOCKS_PROXY`. See example below
|
||||||
|
2. [Edit][1] your application's service file to include below properties
|
||||||
|
|
||||||
|
```systemd
|
||||||
|
[Unit]
|
||||||
|
Requires=nnssB@<namespace_name>.service
|
||||||
|
After=nnssB@<namespace_name>.service
|
||||||
|
[Service]
|
||||||
|
NetworkNamespacePath=/run/netns/<namespace_name>ns
|
||||||
|
```
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Assuming tor daemon is running configured to listen on socks proxy on port 9050.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
❯ sudo tee /etc/nnss/env_tor > /dev/null
|
||||||
|
SOCKS_PROXY=socks5://127.0.0.1:9050
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a shell inside tor namespace
|
||||||
|
|
||||||
|
```bash
|
||||||
|
❯ sudo systemd-run \
|
||||||
|
--property=NetworkNamespacePath=/run/netns/torns \
|
||||||
|
--property=User=$USER \
|
||||||
|
--property=Requires=nnssB@tor.service \
|
||||||
|
--property=After=nnssB@tor.service \
|
||||||
|
--shell
|
||||||
|
```
|
||||||
|
|
||||||
|
Quick check:
|
||||||
|
```bash
|
||||||
|
❯ curl --silent https://check.torproject.org | grep -E "Sorry|Congratulations"
|
||||||
|
Congratulations. This browser is configured to use Tor.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comparison with torsocks
|
||||||
|
|
||||||
|
[torsocks][7] can be used to run a program to connect via tor. This works by
|
||||||
|
replacing network function calls in libc using `LD_PRELOAD`.
|
||||||
|
|
||||||
|
This does not work with programs not using libc functions for networking. E.g.
|
||||||
|
go programs. Or when a sub-process is created wihtout passing down
|
||||||
|
`LD_PRELOAD`. Network namespaces are more secure and works for any program.
|
||||||
|
|
||||||
|
|
||||||
## ¹DNS
|
## ¹DNS
|
||||||
|
|
||||||
DNS by default still goes via host.
|
DNS by default still goes via host.
|
||||||
@@ -84,5 +141,7 @@ DNS by default still goes via host.
|
|||||||
[0]: ./ssh_config
|
[0]: ./ssh_config
|
||||||
[1]: https://wiki.archlinux.org/title/Systemd#Editing_provided_units
|
[1]: https://wiki.archlinux.org/title/Systemd#Editing_provided_units
|
||||||
[2]: https://aur.archlinux.org/packages/nnss
|
[2]: https://aur.archlinux.org/packages/nnss
|
||||||
[3]: https://gitea.balki.me/balki-aur/-/packages/arch/nnss/0.1.0-1
|
[4]: https://github.com/xjasonlyu/tun2socks
|
||||||
[4]: https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=nnss#n14
|
[5]: https://aur.archlinux.org/packages/tun2socks-git
|
||||||
|
[6]: https://github.com/xjasonlyu/tun2socks/wiki/Install-from-Source
|
||||||
|
[7]: https://gitlab.torproject.org/tpo/core/torsocks
|
||||||
|
17
nnss-sproxy@.service
Normal file
17
nnss-sproxy@.service
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Connect to a service running inside a network namespace using socket activation
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=notify
|
||||||
|
User=nnss-sproxy-%i
|
||||||
|
DynamicUser=yes
|
||||||
|
|
||||||
|
# Add CONNECT_ADDR environment variable to below file. E.g.
|
||||||
|
# echo CONNECT_ADDR=127.0.0.1:8080 > /etc/nnss/sproxy_myapp/env
|
||||||
|
EnvironmentFile=/etc/nnss/sproxy_%i/env
|
||||||
|
|
||||||
|
ExecStart=/usr/lib/systemd/systemd-socket-proxyd $CONNECT_ADDR
|
||||||
|
|
||||||
|
# This should be a symlink to the actual network namespace file. E.g.
|
||||||
|
# ln -snf /run/netns/torns /etc/nnss/sproxy_myapp/ns
|
||||||
|
NetworkNamespacePath=/etc/nnss/sproxy_%i/ns
|
16
nnss-sproxy@.socket
Normal file
16
nnss-sproxy@.socket
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Socket to connect to a service running inside a network namespace
|
||||||
|
|
||||||
|
[Socket]
|
||||||
|
ListenStream=/run/nnss-%i.sock
|
||||||
|
|
||||||
|
# By default, the above socket is world writable
|
||||||
|
# To restrict to just the web server, Run
|
||||||
|
# sudo systemctl edit nnss-sproxy@.socket --drop-in=sockperms.conf
|
||||||
|
# and add below settings. (change to your web server user)
|
||||||
|
# SocketGroup=caddy
|
||||||
|
# SocketMode=0660
|
||||||
|
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sockets.target
|
@@ -8,10 +8,21 @@ StopWhenUnneeded=yes
|
|||||||
Type=notify
|
Type=notify
|
||||||
NotifyAccess=all
|
NotifyAccess=all
|
||||||
DynamicUser=yes
|
DynamicUser=yes
|
||||||
|
User=nnss-ssh-%i
|
||||||
|
|
||||||
LoadCredential=ssh:/etc/nnss/%i
|
LoadCredential=ssh:/etc/nnss/%i
|
||||||
|
|
||||||
|
# Note: App service running in the namespace should have Restart=always,
|
||||||
|
# otherwise, both the ssh connection and the app will be stopped as this unit
|
||||||
|
# has StopWhenUnneeded set
|
||||||
|
# https://enotty.pipebreaker.pl/posts/2024/01/how-systemd-exponential-restart-delay-works/
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5min
|
||||||
|
RestartSteps=6
|
||||||
|
RestartMaxDelaySec=24h
|
||||||
|
|
||||||
RuntimeDirectory=nnss-%i
|
RuntimeDirectory=nnss-%i
|
||||||
|
RuntimeDirectoryMode=0750
|
||||||
StateDirectory=nnss-%i
|
StateDirectory=nnss-%i
|
||||||
ExecStart=ssh -F /usr/lib/nnss/ssh_config default
|
ExecStart=ssh -F /usr/lib/nnss/ssh_config default
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ NotifyAccess=all
|
|||||||
RuntimeDirectory=nnssB%i
|
RuntimeDirectory=nnssB%i
|
||||||
|
|
||||||
# Add SOCKS_PROXY environment variable to below file. E.g.
|
# Add SOCKS_PROXY environment variable to below file. E.g.
|
||||||
# SOCKS_PROXY=socks5://127.0.0.1:9050
|
# echo SOCKS_PROXY=socks5://127.0.0.1:9050 > /etc/nnss/env_tor
|
||||||
EnvironmentFile=/etc/nnss/env_%i
|
EnvironmentFile=/etc/nnss/env_%i
|
||||||
|
|
||||||
ExecStart=/usr/lib/nnss/tunsocks.sh "%i" use_env setup
|
ExecStart=/usr/lib/nnss/tunsocks.sh "%i" use_env setup
|
||||||
|
75
tunsocks.sh
75
tunsocks.sh
@@ -2,44 +2,69 @@
|
|||||||
|
|
||||||
set -xeuo pipefail
|
set -xeuo pipefail
|
||||||
|
|
||||||
pidfile=${RUNTIME_DIRECTORY:-/tmp}/tunsocks.pid
|
rtdir=${RUNTIME_DIRECTORY:-/tmp}
|
||||||
|
pidfile="$rtdir/tunsocks.pid"
|
||||||
|
|
||||||
nsname="$1"
|
nsname="$1"
|
||||||
device="tun${nsname}"
|
device="tun${nsname}"
|
||||||
ns="${nsname}ns"
|
ns="${nsname}ns"
|
||||||
|
|
||||||
if [ "$2" = use_env ];then
|
if [ "$2" = use_env ]; then
|
||||||
proxy="$SOCKS_PROXY"
|
proxy="$SOCKS_PROXY"
|
||||||
shift
|
shift
|
||||||
else
|
else
|
||||||
proxy="socks5:///run/nnss-${nsname}/sock"
|
proxy="socks5:///run/nnss-${nsname}/sock"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setup()
|
setup() {
|
||||||
{
|
ip tuntap add mode tun dev "$device"
|
||||||
ip tuntap add mode tun dev "$device"
|
|
||||||
|
|
||||||
/usr/bin/tun2socks -device "$device" -proxy "$proxy" &
|
chan="$rtdir/chan"
|
||||||
echo "$!" > "$pidfile"
|
mkfifo "$chan"
|
||||||
sleep 5
|
|
||||||
|
|
||||||
ip netns add "$ns"
|
{
|
||||||
ip link set "$device" netns "$ns"
|
sleep 10
|
||||||
|
echo TIMEOUT >"$chan"
|
||||||
|
} &
|
||||||
|
timeout_pid=$!
|
||||||
|
|
||||||
ip -n "$ns" addr add 198.19.1.1/30 dev "$device"
|
done_cmd="sh -c 'echo DONE > \"$chan\"'"
|
||||||
ip -n "$ns" link set dev "$device" up
|
|
||||||
ip -n "$ns" route add default via 198.19.1.1 dev "$device" metric 100
|
tun2socks -device "$device" -proxy "$proxy" -tun-post-up "$done_cmd" &
|
||||||
ip -n "$ns" link set lo up
|
echo "$!" >"$pidfile"
|
||||||
systemd-notify --ready
|
|
||||||
wait
|
read -r status <"$chan"
|
||||||
|
|
||||||
|
if [ "$status" = DONE ]; then
|
||||||
|
kill "$timeout_pid"
|
||||||
|
else
|
||||||
|
echo "Failed: $status"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip netns add "$ns"
|
||||||
|
ip link set "$device" netns "$ns"
|
||||||
|
|
||||||
|
ip -n "$ns" addr add 198.19.1.1/30 dev "$device"
|
||||||
|
ip -n "$ns" link set dev "$device" up
|
||||||
|
ip -n "$ns" route add default via 198.19.1.1 dev "$device" metric 100
|
||||||
|
ip -n "$ns" link set lo up
|
||||||
|
|
||||||
|
systemd-notify --ready
|
||||||
|
wait
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup()
|
cleanup() {
|
||||||
{
|
# Cleanup as much as possible. Don't stop on first error
|
||||||
ip tuntap del mode tun dev "$device" || true
|
set +e
|
||||||
kill "$(cat "$pidfile")"
|
|
||||||
ip -n "$ns" tuntap del mode tun dev "$device"
|
# If the script failed after creating the device before moving it to namespace
|
||||||
ip netns del "$ns"
|
ip tuntap del mode tun dev "$device"
|
||||||
|
|
||||||
|
# Regular cleanup when when shutdown normally
|
||||||
|
kill "$(cat "$pidfile")"
|
||||||
|
ip -n "$ns" tuntap del mode tun dev "$device"
|
||||||
|
ip netns del "$ns"
|
||||||
}
|
}
|
||||||
|
|
||||||
$2
|
$2
|
||||||
|
Reference in New Issue
Block a user