This recipe will demonstrate how to set up server-side and client-side routing in client/server mode. With this setup, the OpenVPN client will be able to reach all the machines behind the OpenVPN server, and the server will be able to reach all the machines behind the client.
This recipe uses the PKI files created in the first recipe of this chapter. Install OpenVPN 2.3.9 or higher on two computers. Make sure the computers are connected over a network. For this recipe, the server computer was running CentOS 6 Linux and OpenVPN 2.3.9 and the client was running Fedora 20 Linux and OpenVPN 2.3.9. Keep the server configuration file, basic-udp-server.conf
, handy along with the client configuration file, basic-udp-client.conf
, from the Server-side routing recipe.
We use the following network layout:
basic-udp-server.conf
, by adding these lines:client-config-dir /etc/openvpn/cookbook/clients route 192.168.4.0 255.255.255.0 10.200.0.1
Then save it as example2-6-server.conf
.
[root@server]# mkdir -m 755 /etc/openvpn/cookbook/clients
iroute 192.168.4.0 255.255.255.0
The name of the client certificate can be retrieved from the client certificate file using the following command:
$ openssl x509 -subject -noout -in client1.crt subject= /C=US/O=Cookbook 2.4/CN=client1
Thus, for this recipe, the client configuration file needs to be named client1
, without an extension.
[root@server]# openvpn --config example2-6-server.conf
[root@client]# openvpn --config basic-udp-client.conf
[root@server]# sysctl -w net.ipv4.ip_forward=1
[siteB-gw]> ip route add 192.168.4.0/24 via 10.198.1.1 [siteB-gw]> ip route add 10.200.0.0/24 via 10.198.1.1
Here, 10.198.1.1
is the LAN IP address of the OpenVPN server used in this recipe.
[client]$ sysctl -w net.ipv4.ip_forward=1
[siteA-gw]> ip route add 10.198.0.0/16 via 192.168.4.5 [siteA-gw]> ip route add 10.200.0.0/24 via 192.168.4.5
Here, 192.168.4.5
is the LAN IP address of the OpenVPN client used in this recipe.
[client]$ ping -c 2 10.198.0.10 PING 10.198.0.10 (10.198.0.10) 56(84) bytes of data. 64 bytes from 10.198.0.10: icmp_seq=1 ttl=63 time=31.1 ms 64 bytes from 10.198.0.10: icmp_seq=2 ttl=63 time=30.0 ms
We verify the same vice versa:
[server]$ ping -c 2 192.168.4.164 PING 192.168.4.164 (192.168.4.164) 56(84) bytes of data. 64 bytes from 192.168.4.164: icmp_seq=1 ttl=64 time=30.2 ms 64 bytes from 192.168.4.164: icmp_seq=2 ttl=64 time=29.7 ms
When a client connects to the server with its certificate and with the certificate's common name, client1
, the OpenVPN server reads the client configuration file (also known as a CCD file) in the client-config-dir
directory. The following directive in this file tells the OpenVPN server that the subnet 192.168.4.0/24
is reachable through the client client1
:
iroute 192.168.4.0 255.255.255.0
This directive has nothing to do with a kernel routing table and is only used internally by the OpenVPN server process.
The following server directive is used by OpenVPN to configure the routing table of the operating system so that all of the traffic intended for the subnet 192.168.4.0/24
is forwarded to the interface with the IP address 10.200.0.1
, which is the VPN IP of the server:
route 192.168.4.0 255.255.255.0 10.200.0.1
With the appropriate routing set up on both ends, site-to-site routing is now possible.
When routing client-side traffic to and from multiple clients, there are several caveats to be aware of.
We could have used masquerading on both ends as well, but with multiple clients it becomes very hard to keep track of the network traffic.
If another VPN client needs to reach the subnet 192.168.4.0/24
behind client client1
, the server configuration file needs to be extended with the following:
push "route 192.168.4.0 255.255.255.0"
This instructs all clients that subnet 192.168.4.0/24
is reachable through the VPN tunnel, except for client client1
. The client client1
itself is excluded due to the matching iroute
entry.
Note that you cannot use the route directive inside a CCD file. This is a long-standing missing feature of OpenVPN. It is possible to achieve similar behavior using a learn-address
script, as we will learn in Chapter 5, Scripting and Plugins.
learn-address
script to dynamically set and remove server-side routes18.220.203.200