search by tags

for the user

adventures into the land of the command line

openvpn between two networks in routing mode

This post assumes we have an openvpn server already set up, we are using ubuntu 14.04 and we also have an environment that looks like this:

 server A          openvpn server                       openvpn client         server B
 eth0: 10.1.1.5    eth0: 10.1.1.4                     eth0: 192.168.0.4    eth0: 192.168.0.5

    O <-------x--------> O <----------------x---------------> O <--------x-------> O

                tun0: 172.168.1.4                      tun0: 172.168.1.5

Mission: Enable communication between servers A and B.

On the openvpn server, create a new vpn config:

$ vim /etc/openvpn/my_awesome_vpn.conf

    dev tun0
    proto udp
    ifconfig 172.168.1.4 172.168.1.5
    secret my_awesome_vpn.key
    port 8888
    keepalive 10 60
    ping-timer-rem
    persist-tun
    persist-key
    comp-lzo
    script-security 2

Generate an openvpn static key. The key needs to be in the same directory as the config file:

$ openvpn --genkey --secret /etc/openvpn/my_awesome_vpn.key

The folder should look like this:

$ ls -l /etc/openvpn

-rw-r--r-- 1 root root 277 Nov  7 13:11 my_awesome_vpn.conf
-rw-r--r-- 1 root root 636 Nov  7 13:12 my_awesome_vpn.key

Start the openvpn service:

$ service openvpn start my_awesome_vpn

To check the status:

$ service openvpn status

 * VPN 'my_awesome_vpn' is running

On the openvpn client, first install openvpn:

$ apt-get install openvpn

Create a client config:

$ vim /etc/openvpn/my_awesome_vpn_client.conf

    remote 172.168.1.4
    proto udp
    port 8888
    dev tun0
    ifconfig 172.168.1.5 172.168.1.4
    secret my_awesome_vpn.key
    comp-lzo
    keepalive 10 60
    ping-timer-rem
    persist-tun
    persist-key

Copy the server’s key file:

$ vim /etc/openvpn/my_awesome_vpn.key
#PASTE KEY FROM OPENVPN SERVER

Start the openvpn client service:

$ service openvpn start my_awesome_vpn_client

You should now be able to ping from the openvpn server to the client and vice versa:

[email protected]> $ ping 192.168.0.4

PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 192.168.0.4: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 192.168.0.4: icmp_seq=3 ttl=64 time=0.033 ms

[email protected]> $ ping 10.1.1.4

PING 10.1.1.4 (10.1.1.4) 56(84) bytes of data.
64 bytes from 10.1.1.4: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 10.1.1.4: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 10.1.1.4: icmp_seq=3 ttl=64 time=0.033 ms

Our network should now look like this:

 server A          openvpn server                       openvpn client         server B
 eth0: 10.1.1.5    eth0: 10.1.1.4                     eth0: 192.168.0.4    eth0: 192.168.0.5

    O <--------x-------> O <---------------:)---------------> O <--------x-------> O

                tun0: 172.168.1.4                      tun0: 172.168.1.5

But we have a problem. Because we are using openvpn in routing mode, it will create a virtual device on either server (tap or tun) with an ip address which is not part of the local network. When we try to communicate with a host that is outside of our local network (the openvpn network 172.168.1.X), responses are automatically routed to the default gateway. The default gateway on the host will be either 10.1.1.255 or 192.168.0.255. These two networks don’t know about the openvpn network yet, and so they will not know what to do with the response.

Next step, enable server A to communicate with our openvpn client.

Server A is already in the same local network as our openvpn server, the 10.1.1.X network. So by default these two servers can already communicate with one another. However, server A cannot reach tun0 on our openvpn server. tun0 is a different network interface, and it is also the network interface which is used to reach the openvpn client. So the first thing we need to do is allow traffic from eth0 on server A to go through eth0 on our openvpn server to reach tun0 on the openvpn server.

To do this, enable kernel ip forwarding:

$ sysctl -w net.ipv4.ip_forward=1
$ echo 1 > /proc/sys/net/ipv4/ip_forward

Make it persistent:

$ vim /etc/sysctl.conf

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

Enable the new configuration:

$ sudo sysctl -p

We also need to make packets coming from the openvpn client on tun0 look like they are coming from eth0. On the openvpn server, set up the NAT table in iptables to masquerade packets:

$ iptables -t nat -A POSTROUTING -s 172.168.1.5/32 -o eth0 -j MASQUERADE

Make sure to make the iptables rules persistent:

$ iptables-save > /etc/iptable.save

Also add a static route to the network on the other side of the openvpn client via the client’s tunnel ip:

$ ip r a 192.168.0.0/24 via 172.168.1.4 dev tun0

We can and should also add this to the openvpn config so that every time the tunnel is started, the route will be there, making it reboot safe:

$ vim /etc/openvpn/my_awesome_vpn.conf

.
.
.
route 192.168.0.0 255.255.255.0

At this point we should be able to ping the openvpn client from server A and vice versa:

[email protected]> $ ping 192.168.0.4

PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data.
64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 192.168.0.4: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 192.168.0.4: icmp_seq=3 ttl=64 time=0.033 ms

[email protected]> $ ping 10.1.1.5

PING 10.1.1.5 (10.1.1.5) 56(84) bytes of data.
64 bytes from 10.1.1.5: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 10.1.1.5: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 10.1.1.5: icmp_seq=3 ttl=64 time=0.033 ms

Our network should now look like this:

 server A          openvpn server                       openvpn client         server B
 eth0: 10.1.1.5    eth0: 10.1.1.4                     eth0: 192.168.0.4    eth0: 192.168.0.5

    O <-------:)-------> O <---------------:)---------------> O <--------x-------> O

                tun0: 172.168.1.4                      tun0: 172.168.1.5

Next we have to do pretty much exactly the same thing, but on the openvpn client, to allow server B to communicate with the openvpn server.

On the openvpn client, set up the packet forwarding, and the NAT table in iptables to masquerade packets:

$ sysctl -w net.ipv4.ip_forward=1
$ echo 1 > /proc/sys/net/ipv4/ip_forward

$ vim /etc/sysctl.conf

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

$ sudo sysctl -p

$ iptables -t nat -A POSTROUTING -s 172.168.1.4/32 -o eth0 -j MASQUERADE
$ iptables-save > /etc/iptable.save

Add the static route to the network on the other side of the openvpn client via the client’s tunnel ip:

$ ip r a 10.1.1.0/24 via 172.168.1.5 dev tun0

Make the static route reboot safe by adding it to the openvpn client config:

$ vim /etc/openvpn/my_awesome_vpn_client.conf

.
.
.
route 10.1.1.0 255.255.255.0

The last thing we need to do is to set up some routes on server A, so that it knows how to get to sever B:

ip r a 172.168.1.5/32 via 10.1.1.4 dev eth0
ip r a 192.168.0.0/24 via 10.1.1.4 dev eth0

Make them persistent:

$ vim /etc/network/interfaces

up ip route add 172.168.1.5/32 via 10.1.1.4 dev eth0
up ip route add 192.168.0.0/24 via 10.1.1.4 dev eth0

At this point we should be able to ping server B from server A and vice versa:

[email protected]> $ ping 192.168.0.5

PING 192.168.0.5 (192.168.0.5) 56(84) bytes of data.
64 bytes from 192.168.0.5: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 192.168.0.5: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 192.168.0.5: icmp_seq=3 ttl=64 time=0.033 ms

[email protected]> $ ping 10.1.1.5

PING 10.1.1.5 (10.1.1.5) 56(84) bytes of data.
64 bytes from 10.1.1.5: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 10.1.1.5: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 10.1.1.5: icmp_seq=3 ttl=64 time=0.033 ms

Our network should now look like this:

 server A          openvpn server                       openvpn client         server B
 eth0: 10.1.1.5    eth0: 10.1.1.4                     eth0: 192.168.0.4    eth0: 192.168.0.5

    O <-------:)-------> O <---------------:)---------------> O <-------:)-------> O

                tun0: 172.168.1.4                      tun0: 172.168.1.5