# Run OpenVPN in a Linux network namespace
2022-02-04
Users may wish to conceal their home IP for a variety of reasons. This is often
done with a proxy such as Tor. Redirecting all traffic through a proxy is slow
however and may not be necessary for all applications. Making only specific
applications use a proxy can be done using Linux network namespaces.
This guide assumes you're using OpenVPN, though any type of VPN should work.
## Creating a new network namespace
A new network namespace can be created with the `ip` utility:
```sh
$ ip netns add mynetns
```
To execute a program inside this namespace, use `ip netns exec`
```sh
$ ip netns exec mynetns ip l
1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
```
For `ip`, a shorter syntax is:
```sh
$ ip -n mynetns l
```
To allow connections to the outside world a `veth` device must be added.
```sh
$ ip l add mynetns_a type veth peer name mynetns_b
$ ip l
...
6: mynetns_b@mynetns_a: mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 0a:3d:7c:b3:f9:a4 brd ff:ff:ff:ff:ff:ff
7: mynetns_a@mynetns_b: mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 0e:94:83:65:95:e8 brd ff:ff:ff:ff:ff:ff
```
We now need to move one of the interfaces into the proper namespace:
```sh
$ ip l set mynetns_a netns mynetns
$ ip -n mynetns l
1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: mynetns_a@if6: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 0e:94:83:65:95:e8 brd ff:ff:ff:ff:ff:ff link-netnsid 0
```
Give the interfaces an IP:
```sh
$ ip -n mynetns a add 192.168.0.2/24 dev mynetns_a
$ ip a add 192.168.0.1/24 dev mynetns_b
```
Bring the interfaces up:
```sh
$ ip -n mynetns l set up dev mynetns_a
$ ip l set up dev mynetns_b
```
You should now be able to send packets through the interface:
```
$ ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.040 ms
```
## Forwarding packets
We now need to forward packets to the interface. Since we're using IPv4 we'll
use NAT:
```sh
$ echo 1 > /proc/sys/net/ipv4/ip_foward
$ iptables -t filter -A FORWARD -i mynetns_b -j ACCEPT
$ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```
Configure the default route:
```sh
$ ip -n mynetns r add default via 192.168.0.1
```
To test if it works, try pinging a public IP:
```
$ ip netns exec ping demindiro.com
PING demindiro.com (104.244.79.104) 56(84) bytes of data.
64 bytes from mail.salt-inc.org (104.244.79.104): icmp_seq=1 ttl=62 time=0.165 ms
```
## Running OpenVPN inside the namespace
Running any service inside the namespace is trivial:
```sh
$ cd /etc/openvpn
$ ip netns exec openvpn myvpn.conf
```
## Service script
This `run` script can be used with `runit`:
```sh
#!/bin/sh
ip netns add mynetns
ip l add mynetns_a type veth peer name mynetns_b
ip l set mynetns_a netns mynetns
ip a add 192.168.0.1/24 dev mynetns_b
ip -n mynetns a add 192.168.0.2/24 dev mynetns_a
ip l set up mynetns_b
ip -n mynetns l set up mynetns_a
ip -n mynetns r add default via 192.168.0.1
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t filter -A FORWARD -i mynetns_b -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
cd /etc/openvpn
exec ip netns exec mynetns openvpn myvpn.conf
```
For cleanup, use this `finish` script:
```sh
#!/bin/sh
ip netns del mynetns
echo 0 > /proc/sys/net/ipv4/ip_forward
iptables -t filter -D FORWARD -i mynetns_b -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
```
In any service that should use the VPN, add this:
```sh
sv start myvpn || exit
# ...
exec ip netns exec mynetns myservice ...
```