RIP and Routing
I have been trying to set up RIP with OpenVPN for a few days and found that there are lots of people on the Internet trying to do the same thing, but I could not find solutions easily with google, so I decided to document what I came up with (with lots of help form ##openvpn).
The basic scenario I have is a number of hosts (numbered 1-10 say) have VPNs set up in random configuration, between each other. I want to route traffic between the hosts regardless of which VPN is connected where. (This system is actually driven by a web interface that allows the VPNs to be established pretty randomly between hosts). If a link goes down, I want routes to change so that traffic can be carried through other VPNs in a mesh network.
What didnt work
I think its important to document what didnt work so as to save someone some time if they try to do it the same way. I first started using a standard client/server arrangement like in the manual. I immediately ran into a couple of problems:
- The client/server set up point to point IP addresses in a confusing way for the tunnel. For example the server might have its tun0 interface with 192.168.1.1 and the remote end is 192.168.1.2 while the client has tun0 at 192.168.1.6 pointtopoint 192.168.1.5. Both interfaces are /32 by default. What happens here is that quagga will receive a RIP update packet from 192.168.1.1 on tun0. According to the interface data the host 192.168.1.1 is not even on that interface. What might happen is that even if the route is added it will be disabled (because the client cant really reach 192.168.1.1 on any actual interface).
- I then tried using the topology directive to expand the interface to /30 which worked but I then ran into another problem. The server needs to have iroutes for the networks behind the client networks and it will not forward packets to remote networks behind the client unless it has iroutes for them. Since the whole point of using RIP is to avoid having to specify hard coded routes its impossible to maintain iroutes within OpenVPN for dynamic networks. In a sense OpenVPN is acting as a router by itself in client/server mode and it only supports having static routes put in (Wishlist: can OpenVPN understand RIP announcements and adjust iroutes by itself?).
What does work
After wasting time with this I realised that I needed point to point mode (--p2p which is the default). After I realised this the VPNs were set up in a matter of minutes so it is really easy to use - you just need to know how to do it.
The trick with p2p modes is that even though its called p2p - one end has to be the tls-server and the other must be the tls-client so they are not exactly the same (wishlist: can OpenVPN just switch modes if it doesnt work by itself so the two configs may be the same?).
Quagga is a fork of zebra with an open license. Quagga has a similar interface to a Cisco IOS, but dont hold that against it - its still a daemon based program. I will be describing installing it on debian based distros but its pretty easy to set up everywhere:
apt-get install quagga
Edit the /etc/quagga/daemons file to enable zebra and ripd. Add the following two files to /etc/quagga:
hostname Router password zebra enable password zebra
hostname ripd password zebra log file /var/log/quagga/ripd.log ! router rip redistribute connected
So the default configuration is to enable RIP but not to give it any interfaces to actually send messages on. As the VPNs come up and down these interfaces are added using an up script.
The OpenVPN configurations are:
ca /etc/openvpn/ca.crt cert /etc/openvpn/router2.crt key /etc/openvpn/router2.key ns-cert-type server tls-remote "/C=AU/ST=VIC/L=Melbourne/O=XYZ/CN=router1/emailAddressfirstname.lastname@example.org" tls-client ## Connections remote router1.example.com 1202 port 1202 ## We set up the two end points ifconfig 184.108.40.206 220.127.116.11 ## This script does stuff when the vpn comes up (mainly sets up rip) up "/etc/openvpn/vpn_up.py" dev tun1 proto udp resolv-retry infinite float persist-tun persist-key cipher BF-CBC comp-lzo keepalive 5 30
The other side is similar too:
ca /etc/openvpn/ca.crt cert /etc/openvpn/router1.crt key /etc/openvpn/router1.key ns-cert-type server tls-remote "/C=AU/ST=VIC/L=Melbourne/O=XYZ/CN=router2/emailAddressemail@example.com" tls-server ## Connections remote router2.example.com 1202 port 1202 ## We set up the two end points ifconfig 18.104.22.168 22.214.171.124 ## This script does stuff when the vpn comes up (mainly sets up rip) up "/etc/openvpn/vpn_up.py" dev tun1 proto udp resolv-retry infinite float persist-tun persist-key cipher BF-CBC comp-lzo keepalive 5 30
The things to note are:
- Each connection must be on a different port because the tunnels are point to point.
- The ifconfig line sets up the end points in opposite order.
- Each tunnel is set up on its own tun device (OpenVPN will just choose a tun device to use when a new connection is made). The device is passed the vpn_up.py script which adds the tun device to RIP.
- We specified persist-tun to maintain the tun interface even if the VPN went down. This allows routes to remain in the RIP tables if the VPN is dropped for a short time.
The vpn_up.py script just adds the new interface to the RIP daemon:
#!/usr/bin/python import os try: os.spawnl(os.P_WAIT, "/usr/bin/vtysh", "vtysh", "-c", "configure terminal", "-c", "router rip", "-c", "network %s" % os.environ['dev']) except Exception,e: pass