Skip to content

Instantly share code, notes, and snippets.

@shakibamoshiri
Forked from EnigmaCurry/vpn_namespace.md
Created December 18, 2022 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shakibamoshiri/98d5429723dd32978f36a3797ccea589 to your computer and use it in GitHub Desktop.
Save shakibamoshiri/98d5429723dd32978f36a3797ccea589 to your computer and use it in GitHub Desktop.
OpenVPN and browser specific network routing with ip netns

OpenVPN and browser specific network routing with ip netns

Create network bridge

A network bridge allows us to have a virtual router that we can plug multiple network interfaces into. The IP address is assigned to the bridge rather than the individual network interface.

Create the bridge device, br0 :

ip link add name br0 type bridge
ip link set br0 up

Add your network interfaces to it:

ip link set eth0 master br0

Get a fresh IP address for the bridge:

dhcpcd br0

You should now see a LAN ip address for br0, rather than eth0:

ip addr

Create VPN network namespace

Network namespaces are a feature of the Linux kernel to run multiple independent routing tables at the same time, some processes using one, while other processes using a completely different one.

Most OpenVPN configs mess with the ip routing table and force all of the traffic on the system to flow through it. This means that when you have your VPN turned on, all your apps go through it, your browser, your package manager, etc. In addition, this breaks a lot of LAN traffic. You can configure OpenVPN to do some custom routing, but it gets complicated quick, and I find it much easier to just let it do it's thing the way it wants. Creating a seperate network namespace allows for the VPN to set whatever routing rules it wants to, but not have any effect on any other apps except the ones we specifically choose to run inside the same network namespace the VPN is running under.

Create a pair of virtual interfaces, these will form a link between the new namespace and the regular system.

ip link add vpn0 type veth peer name vpn1

vpn0 and vpn1 are linked together. Anything you put in one side goes out the other. Both interfaces show up in ip link show list.

Connect vpn0 to the bridge, just like we did earlier with eth0:

ip link set dev vpn0 master br0

Create a namespace just for apps we'll run inside a VPN:

ip netns add vpn

Move vpn1 to the vpn namespace:

ip link set vpn1 netns vpn

If you look again at the list of interfaces with ip link show you'll see that only vpn0 remains. vpn0 is gone! Not really, it's now in a completely fresh namespace:

ip netns exec vpn ip link

ip netns exec vpn - that's the command to run any other command inside of the vpn network namespace. So above all we're really doing is running ip link inside the vpn. And lo, behold, you see the vpn1 interface again.

So with vpn0 in the main namespace, and vpn1 inside the vpn namespace, vpn0 becomes the upstream network connection for vpn1.

Setup vpn0 for it's new routing duties:

ip link set dev vpn0 promisc on
ip link set vpn0 up

Get an IP address for vpn1:

ip netns exec vpn dhcpcd vpn1

See the new ip inside the vpn namespace:

ip netns exec vpn ip addr

Start your VPN in the vpn namespace:

ip netns exec vpn /usr/bin/openvpn --cd /etc/openvpn --config /etc/openvpn/vpn.conf --daemon openvpn@vpn --writepid /run/openvpn@vpn.pid

Start a shell, and all your network connections will be tunneled through the VPN:

ip netns exec vpn bash

alias to start chromium inside the vpn namespace:

alias chromium-vpn="sudo ip netns exec vpn sudo -u `whoami` PULSE_SERVER=$(ip -o -4 addr list br0 | awk '{print $4}' | cut -d/ -f1) chromium"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment