-
Notifications
You must be signed in to change notification settings - Fork 2
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
0 parents
commit 947a011
Showing
7 changed files
with
1,477 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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,127 @@ | ||
# WireGuard VPN in a Network Namespace | ||
|
||
A script for setting up and managing a WireGuard VPN in a network namespace. | ||
|
||
Supports Private Internet Access (PIA) VPN only, but can be (relatively) easily modified to work with any other VPN provider as the PIA bits are not that tightly integrated with the rest of the script. | ||
|
||
This is just something I wrote for myself that I'm sharing on the off chance someone finds it useful. | ||
I have no plans on supporting any other VPN provider for now, but if in the future I change which VPN service I use, I might update the script and rename the repo appropriately. | ||
|
||
## FAQ | ||
|
||
### Why run a VPN in a network namespace? | ||
|
||
By running a VPN in a network namespace you get these awesome perks for free: | ||
|
||
- Ability to run only selected applications through VPN, instead of running everything on your computer through it. | ||
- Kill-switch functionality, as the WireGuard VPN is the only network interface in the network namespace, aside from the loopback, so if it goes down -- there is no network in that namespace. | ||
- DNS protection, as applications inside the namespace will use VPN's DNS servers by default. | ||
- Ability to nest VPN connections. Who doesn't want to be behind 7 proxies? | ||
|
||
To get these features in traditional, non-namespace, VPN setups you would have to create a GID per VPN, setup iptables/nftables mangle rules to fwmark application traffic based on GID, setup masquerade nat rules, add a routing table for the VPN traffic, setup routing rules for the fwmark, etc. -- so much work and potential to get things wrong. | ||
|
||
### Why not just use \<this-other-script\>? | ||
|
||
You might be wondering why I don't just use [`pia-foss/manual-connections`](https://github.com/pia-foss/manual-connections) or something else. | ||
|
||
The issue is that all these scripts use [`wg-quick`](https://manpages.debian.org/unstable/wireguard-tools/wg-quick.8.en.html), which doesn't support creating WireGuard connections in a separate namespace and does a lot of unnecessary for us stuff. | ||
|
||
To create a WireGuard connection in a separate namespace, [you want to create the wg interface in the init namespace and then move it into a separate namespace, that way it remembers that it was created in the init namespace and routes traffic though it](https://www.wireguard.com/netns/). | ||
|
||
### How to access a web server running in a network namespace / how to forward a port? | ||
|
||
You can use the provided `netns-socat-forward.service` as an example of how to forward connections made on host's 127.0.0.1:1234 to 127.0.0.1:1234 inside the network namespace. | ||
|
||
Edit `netns-socat-forward.service` for your needs: host ip port, netns ip port, tcp or udp, vpn name, rename the file, change syslog identifier, etc., and run: | ||
|
||
```bash | ||
sudo install -o root -g root -m 644 netns-socat-forward.service /etc/systemd/system/netns-socat-forward.service | ||
sudo systemctl daemon-reload | ||
sudo systemctl start netns-socat-forward.service | ||
sudo systemctl status netns-socat-forward.service | ||
``` | ||
|
||
# Setup | ||
|
||
```bash | ||
# install the scripts | ||
sudo install -o root -g root -m 755 -D vpn /usr/local/bin/vpn | ||
sudo install -o root -g root -m 755 -D bash-completion/completions/vpn /usr/local/share/bash-completion/completions/vpn | ||
# install deps (Debian/Ubuntu) | ||
sudo apt-get install curl gawk jq wireguard-tools | ||
# this will create directory structure under /var/lib/vpn and prompt about missing deps | ||
vpn regions | ||
# setup other things | ||
sudo install -o root -g root -m 600 pia_auth.sh /var/lib/vpn/secret/pia_auth.sh | ||
# enter your username/password | ||
sudo editor /var/lib/vpn/secret/pia_auth.sh | ||
sudo install -o root -g root -m 600 pia_ca.rsa.4096.crt /var/lib/vpn/secret/pia_ca.rsa.4096.crt | ||
``` | ||
|
||
By default the script uses `/var/lib/vpn` for its purposes. | ||
You can change the location by changing the `VPN_ROOT_DIR` variable in the script. | ||
Note that `VPN_ROOT_DIR` will be chown'ed to root to protect username/password whenever the script runs. | ||
|
||
# Usage | ||
|
||
```bash | ||
$ vpn --help | ||
vpn - creates a network namespace with a PIA WireGuard VPN connection in it. | ||
|
||
Usage: [sudo ] vpn regions list available VPN regions | ||
[sudo ] vpn up <name> <region-id> create VPN <name> connected to <region-id> region | ||
[sudo ] vpn down <name> delete VPN <name> | ||
[sudo ] vpn list list created VPNs | ||
[sudo ] vpn stat <name> show information for VPN <name> | ||
[sudo -E] vpn exec <name> <program> [args] run a program in VPN <name>'s network namespace as the current user | ||
It's preferred that you don't call the script with "sudo", the script will | ||
auto-sudo with the correct flags on its own. | ||
A bit counter-intuitively, "sudo -E vpn exec" will run the program as the user | ||
who invoked sudo, not necessarily as the root user. Run it as "sudo sudo vpn | ||
exec" if you want to run it as root. | ||
``` | ||
Just for fun, if you want to get behind 7 proxies, you can do it like this: | ||
```bash | ||
/bin/bash | ||
vpn up vpn1 region1 && trap "vpn down vpn1" EXIT && vpn exec vpn1 /bin/bash | ||
# we are inside vpn1's namespce | ||
vpn up vpn2 region2 && trap "vpn down vpn2" EXIT && vpn exec vpn2 /bin/bash | ||
# we are inside vpn2's namespce | ||
vpn up vpn3 region3 && trap "vpn down vpn3" EXIT && vpn exec vpn3 /bin/bash | ||
# we are inside vpn3's namespce | ||
vpn up vpn4 region4 && trap "vpn down vpn4" EXIT && vpn exec vpn4 /bin/bash | ||
# we are inside vpn4's namespce | ||
vpn up vpn5 region5 && trap "vpn down vpn5" EXIT && vpn exec vpn5 /bin/bash | ||
# we are inside vpn5's namespce | ||
vpn up vpn6 region6 && trap "vpn down vpn6" EXIT && vpn exec vpn6 /bin/bash | ||
# we are inside vpn6's namespce | ||
vpn up vpn7 region7 && trap "vpn down vpn7" EXIT && vpn exec vpn7 /bin/bash | ||
# we are inside vpn7's namespce | ||
# do your stuff here | ||
``` | ||
|
||
Then just logout 8 times, to get out of each bash session and trigger the set traps. | ||
|
||
When nesting past a few VPNs the connection becomes rather unstable, so you might want to do less than 7 nestings. | ||
|
||
Note that the following will NOT work [because of this](https://serverfault.com/a/961592), i.e. you need to keep a process in a network namespace for the nested namespaces to work, like what all these bash processes in the snippet above did: | ||
|
||
```bash | ||
# you would think this would work but it doesn't | ||
vpn up vpn1 region1 | ||
vpn exec vpn1 vpn up vpn2 region2 | ||
vpn exec vpn2 vpn up vpn3 region3 | ||
vpn exec vpn3 vpn up vpn4 region4 | ||
vpn exec vpn4 vpn up vpn5 region5 | ||
vpn exec vpn5 vpn up vpn6 region6 | ||
vpn exec vpn6 vpn up vpn7 region7 | ||
vpn exec vpn7 /bin/bash | ||
``` | ||
|
||
# License | ||
|
||
GPL-3.0-only |
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,43 @@ | ||
_vpn() | ||
{ | ||
local cur prev words cword | ||
_init_completion || return | ||
|
||
# echo "cur: ${cur[@]} | prev: ${prev[@]} | words: ${words[@]} | cword: ${cword[@]}" | ||
|
||
if ((cword == 1)); then | ||
COMPREPLY=($(compgen -W 'regions up down list stat exec' -- "$cur")) | ||
return | ||
fi | ||
|
||
local command=${words[1]} | ||
|
||
if ((cword == 2)); then | ||
case $command in | ||
down | stat | exec) | ||
COMPREPLY=($(compgen -W "$(vpn --help 2>&1 > /dev/null && VPN_BASH_COMPLETION=1 vpn bash-completion-list)" -- "$cur")) | ||
;; | ||
esac | ||
return | ||
fi | ||
|
||
if ((cword == 3)); then | ||
case $command in | ||
up) | ||
COMPREPLY=($(compgen -W "$(vpn --help 2>&1 > /dev/null && VPN_BASH_COMPLETION=1 vpn bash-completion-regions)" -- "$cur")) | ||
return | ||
;; | ||
esac | ||
fi | ||
|
||
if ((cword >= 3)); then | ||
case $command in | ||
exec) | ||
for ((i = 3; i <= cword; i++)); do | ||
_command_offset $i | ||
return | ||
done | ||
;; | ||
esac | ||
fi | ||
} && complete -F _vpn vpn |
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,15 @@ | ||
# We could make this a socket activated service, but socat is so ridiculously | ||
# small that it's not worth the trouble, unless you need hundreds of these. | ||
[Unit] | ||
Description=Forward TCP connections made on host's 127.0.0.1:1234 to vpn-name network namespace's 127.0.0.1:1234 | ||
After=network.target | ||
|
||
[Service] | ||
# Use this if you need to forward a UDP socket instead | ||
#ExecStart=/usr/bin/socat udp4-listen:1234,fork,reuseaddr,bind=127.0.0.1 exec:'ip netns exec vpn-name socat STDIO "udp-connect:127.0.0.1:1234"',nofork | ||
ExecStart=/usr/bin/socat tcp4-listen:1234,fork,reuseaddr,bind=127.0.0.1 exec:'ip netns exec vpn-name socat STDIO "tcp-connect:127.0.0.1:1234"',nofork | ||
Restart=always | ||
SyslogIdentifier=netns-socat-forward | ||
|
||
[Install] | ||
WantedBy=default.target |
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,2 @@ | ||
PIA_USER="" | ||
PIA_PASS="" |
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,43 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD | ||
VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV | ||
BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu | ||
dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx | ||
IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB | ||
FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQw | ||
MzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex | ||
EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg | ||
QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE | ||
AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50 | ||
ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy | ||
bmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVk | ||
hjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULN | ||
De4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9K | ||
V2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ | ||
25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SND | ||
fCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZyl | ||
p7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7p | ||
Kwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzj | ||
tRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wi | ||
jSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNz | ||
meGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz | ||
1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNV | ||
HQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRt | ||
yWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQI | ||
EwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRl | ||
cm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAw | ||
HgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0 | ||
ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRl | ||
aW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkq | ||
hkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCt | ||
pXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dv | ||
Em89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1G | ||
tF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZu | ||
LfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs | ||
6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj3 | ||
5xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnX | ||
JUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJ | ||
iyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l | ||
8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW | ||
+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ= | ||
-----END CERTIFICATE----- |
Oops, something went wrong.