Bash script to start Wireguard in its own Linux network namespace and then run arbitrary commands within that namespace. This "portals" individual process traffic through the Wireguard interface without affecting traffic for any other process. Requires root/sudo.
Portl is useful if you want select programs to (be forced to) use Wireguard as a VPN without affecting traffic from the rest of your system or having to calculate complicated AllowedIP ranges for some excluded IPs (like your local subnet). It's also a good solution for when you want a specific tool to be able to access both local and on-VPN network resources at different times, but have the same (or overlapping) subnet CIDRs on the local and remote ends.
Requires GNU sed
, grep
, cut
, and tr
to be installed. If you get errors about unsupported flags in these commands it's probably because you have a BSD (POSIX) version installed.
Start a Wireguard server on a machine you want to use a relay. If you're not familiar with this process, this or this should get you started.
Generate a basic Wireguard configuration file compatible with wg-quick
that will connect to your client machine to the Wireguard server. For this example, save it as tunnel.conf
.
- Set
AllowedIPs = 0.0.0.0/0
in this configuration file
Then run the following commands on your client:
./portl.sh config ./tunnel.conf
./portl.sh up
./portl.sh show
- If the Wireguard connection was successful, the
show
command output should include a line likelatest handshake: X seconds ago
that indicates a connection was established with a successful handshake.
Now you now can tunnel traffic for arbitrary programs through this connection by running ./portl.sh exec <any command>
./portl.sh run <any command>
is equivalent- You can also use
./portl.sh <any command>
so long as the first word in the command is not the same as one of the other portl commands.
Usage: portl.sh [ config FILE | up | down | show | exec CMD | run CMD | help ]
COMMANDS
config FILE
Set FILE as the wireguard configuration file to use when creating or deleting the portl namespace
up
Create the portl namespace (must run 'config' first)
down
Delete the configured portl namespace
show
Shortcut to run 'wg show' within the portl namespace
exec CMD...
Run any command within the portl namesapce
run CMD...
Alias for exec
help
Display this help message
Each command can also be run by specifying only its first letter, such as 's' instead of 'show'.
If none of the above commands are provided as the first argument, 'exec' is assumed. This means you can use 'portl.sh CMD...' instead of 'portl.sh exec CMD...'
Note that you cannot chain COMMANDs together with pipes inside the namespace; anything after the first pipe will run outside the namespace due to the way shells handle them. If you need to do this, start by running 'portl.sh bash' or similar, at which point everything that runs in the new shell will be inside the portl.sh namespace.
Example
-------
portl.sh config ./tunnel.conf
portl.sh up
portl.sh show
portl.sh exec ping -c 4 10.0.0.1
portl.sh curl 10.0.0.1:8080/info.txt
portl.sh down
Commands:
config path/to/config/file
: specify a Wireguard configuration file to use (caveats below).up
: brings up a namespaced Wireguard interface using the config file specified previously.show
: shortcut to runwg show
within the configured namespace.down
: removes the Wireguard interface and namespace created byup
.exec [command]
: run an arbitrary command within the namespace created byup
.run [command]
: same asexec
.
Note that the namespace and interface names are defined at the top of the script and can be changed. By default the namespace is portl
and the interface is portl0
. The rest of this documentation will describe the script's behavior assuming those values remain unchanged.
Tip
If you want to setup multiple portl tunnels to different systems just make a copy of the script file (with a different name, such as portl2.sh
) and change the NAMESPACE
and INTERFACE
values near the top of the file to something unique.
Tip
Rename the script to portl
and put it in a folder in your PATH to make it easy to use portl no matter what your current working directory is.
The script requires root privileges to function. The first thing it does is check if it's running as root, and if not it automatically attempts to elevate to root using sudo
. This may prompt the user for credentials.
The specified config file should be one that is compatible with wg
(see the CONFIGURATION FILE FORMAT section here), plus the (required) Address
and (optional) DNS
options supported by wg-quick
(detailed here). ANY OTHER wg-quick
-SPECIFIC OPTIONS USED BESIDES Address
OR DNS
WILL BE SILENTLY IGNORED. Comments (#
) are fine and will be respected/preserved, but avoid using a #~
combination anywhere because that is used as a special marker for parsing the supported wg-quick
commands.
At a minimum, the config file should contain the following:
[Interface]
PrivateKey = [base64 private key]
Address = [address/subnet to be used by the client]
[Peer]
PublicKey = [server's public key]
AllowedIPs = [IP range(s) for traffic that should be sent over wireguard]
Endpoint = [server IP or FQDN]:[port] #default port is 51820
- You may also swap out the Peer's
Endpoint
for an InterfaceListenPort
if you want to act more like a server and have the peer initiate connections to this machine.
The specified config file will be copied to /etc/wireguard/portl0.conf
. Address
and DNS
lines (not supported by wg
) will be commented out but parsed later by the up
command to configure the interface. The config file will persist after the interface is removed (via the down
command or otherwise) so you should only need to run config
once unless configuration changes are needed.
Uses the config file at /etc/wireguard/portl0.conf
(created via the config
command) to create a Wireguard interface named portl0
located in the portl
network namespace.
If the original config file contained DNS=IP
options (also allowing multiple comma-separated IPs), those will be parsed and applied as nameserver [IP]
values to a resolve.conf
file specific to the portl
namespace. This is done by writing the values to /etc/netns/portl/resolve.conf
, which Linux will make available inside the namespace at the standard /etc/resolve.conf
location without affecting that file outside the namespace. Like the config file in /etc/wireguard/
, this namespaced resolve.conf
file will be persistent and remain in use until modified manually or by the config
command. If /etc/netns/portl/resolve.conf
does not exist (either because it is deleted or DNS was never specified in a config file) then the namespace will use the same /etc/resolve.conf
file as the main OS.
Shortcut to run wg show
within the namespace.
Runs the specified command as the current user, even when sudo
is used to run the script with root privileges. To run a command as root just specify sudo
as part of the command. For example, portl.sh exec sudo iptables -L
.
Pretty much any command that you would normally run in your shell can be used and should work as expected. You can even use something like bash
as the target command to open a shell within the namespace, then return to the parent shell with exit
.
Important
Using a pipe (or other command-terminating shell characters) will NOT allow the next command to run inside the namespace. For example, if you run portl.sh exec echo "google.com" | xargs ping
, the ping
command will NOT run inside the namespace, it will use your normal host namespace.
Tip
If you need to use something like pipes, run portl.sh exec bash
to start a new shell inside the namespace, and then everything you run from that shell will also run inside that namespace.
Same as exec
.
Brings down the namespaced Wireguard interface, then deletes the portl
namespace (and all network interfaces in it). Any configuration options specified with the config
command will be preserved (no need to run config
again after down
), but any namespace-specific changes that were made inside the namespace (e.g. iptables rules) will be lost.
This script is the same as the original portl.sh
, except it moves the wireguard interface into an existing docker container's namespace instead of creating a new portl
namespace. As part of this process it also deletes all existing network interfaces inside the container, except for lo
(loopback).
- Deleting other interfaces ensures container traffic is forced through the Wireguard interface, but will probably break things if the container is meant to communicate with any other containers or do any other special local networking activity. This is intended mainly for use with containers that provide access to standalone tools/programs that target network resources, for example
nmap
.
Usage is exactly the same as the portl.sh
script described above, except the up
command takes a single argument: the truncated 12-character CONTAINER ID
of the target container, as displayed by docker ps
. E.g. dportl.sh up e90b8831a4b8
.