RIP FreeBSD
Disclaimer: this post was created on 04-15-2018 for FreeBSD 11.2, it might not work on other platforms or versions.
I mean Routing Information Protocol of course, not rest in peace! RIP is one of the most basic and easy-to-use routing protocols there is. It has its limitations, but it can be a viable solution for small environments. With RIP it is possible to exchange routing information between devices, and as it is a standard protocol, not only FreeBSD or Linux can use it, but it’s also implemented in many different networking devices, such as routers, firewalls, and even some layer 3 switches.
Table of contents:
Features and limitations
RIPv1 was introduced in 1988 and RIPv2 in 1993 and it became a standard in 1998. It is easy to use, but has a lot of limitations. The biggest such limitation is that the maximum hop count can only be 15, which means in practice that between the farthest two routers, there can be only 13 other routers. The routing domain can be of course bigger. RIPv2 has the ability to use authentication, however the only method for that is using plain passwords or MD5.
Preparing FreeBSD
In order to send packets between different subnets it is essential to know how one can get to the other subnet. If many subnets have only one common router, this is quite easy, as every local subnet is known and every packet sent to an unknown subnet will be forwarded to another router (aka. to the default gateway).
The information about which network is where is stored in the routing table. The currently known subnets can be listed with the netstat
command, where -r
is telling netstat to give us the routing information, -n
is not to resolve the IP addresses and -4
is to do it for IPv4.
root@router1# netstat -r4n
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 link#3 UH lo1
127.0.0.1 link#2 UH lo0
192.168.122.0/24 link#1 U vtnet0
192.168.122.45 link#1 UHS lo0
Each network has an associated cost in order to figure out which way is the best. In RIP, this cost is calculated from the number of hops, where one hop is one router. A directly connected subnet has a hop count of 0. With RIP, the whole routing table is sent to the neighbor which then processes it and sends the updated routing table to its neighbor, and so on. In the following examples, there are two FreeBSD machines on the same subnet (192.168.122.45/24 and 192.168.122.169/24). Additionally, they have loopback interfaces:
- lo1 on router1 with the IP Address of 10.0.1.1/24
- lo2 on router2 with the IP Address of 172.16.2.1/24
Naturally not only loopback interfaces can be included in RIP, but other, physical or VLAN interfaces too. Creating a loopback interface and the make it persistent between reboots:
Router 1:
root@router1# ifconfig lo1 create inet 10.0.1.1/24
root@router1# sysrc cloned_interfaces=lo1
cloned_interfaces: -> lo1
root@router1# sysrc ifconfig_lo1="inet 10.0.1.1/24"
ifconfig_lo1: -> inet 10.0.1.1/24
Router 2:
root@router2# ifconfig lo2 create inet 172.16.2.1/24
root@router2# sysrc cloned_interfaces=lo2
cloned_interfaces: -> tap2
root@router2# sysrc ifconfig_lo2="inet 172.16.2.1/24"
ifconfig_lo2: -> inet 172.16.2.1/24
The loopback interfaces on each of the routers exists, though they have no information about the interface on the other machine.
Router1:
root@router1# netstat -r4
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 link#3 UH lo1
localhost link#2 UH lo0
192.168.122.0/24 link#1 U vtnet0
router1 link#1 UHS lo0
Router 2:
root@router2# netstat -r4
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
localhost link#2 UH lo0
172.16.2.1 link#3 UH lo2
192.168.122.0/24 link#1 U vtnet0
router2 link#1 UHS lo0
Pinging the loopback address on router2 from router1 fails, because router1 has no idea where to send the packets.
root@router1# ping -v 172.16.2.1
PING 172.16.2.1 (172.16.2.1): 56 data bytes
^C
--- 172.16.2.1 ping statistics ---
7 packets transmitted, 0 packets received, 100.0% packet loss
In order to be able to reach the subnets behind the routers, the information about the networks has to be exchanged between the two routers. First, enable routing, this makes sure that if router1 receives a packet on the interface with the IP 192.168.122.45, it won’t drop it, but forward it to the loopback interface. Do this on all of the routers.
root@router1# sysctl net.inet.ip.forwarding=1
root@router1# echo net.inet.ip.forwarding=1 >> /etc/sysctl.conf
Starting routed.
RIP on FreeBSD is handled by routed(8). We start routed with 2 flags:
-s
tells routed to advertise the known routes even if there is only one interface. This is necessary if we want to advertise loopback interfaces.-P ripv2
tells routed to use RIPv2.
root@router1/2# sysrc routed_enable=YES
routed_enable: NO -> YES
root@router1/2# sysrc routed_flags="-s -P ripv2"
routed_flags: -q -> -s -P ripv2
root@router1/2# service routed start
After around 30 seconds, 10.0.1.1 should be known on router2, and also 172.16.2.1 is known on router1.
root@router1# netstat -r4n
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 link#3 UH lo1
127.0.0.1 link#2 UH lo0
172.16.2.1 192.168.122.169 UGH vtnet0
192.168.122.0/24 link#1 U vtnet0
192.168.122.45 link#1 UHS lo0
root@router2# netstat -r4n
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 192.168.122.45 UGH vtnet0
127.0.0.1 link#2 UH lo0
172.16.2.1 link#3 UH lo2
192.168.122.0/24 link#1 U vtnet0
192.168.122.169 link#1 UHS lo0
With that, RIP is up and running on our routers. Even though MD5 is the only option for authentication, it is worth it to turn it on, and shortening the hold time from the default 30 minutes is also useful, but having a lot of options in rc.conf is not convenient. RouteD by default looks for the /etc/gateways file for parameters.
md5_passwd=P4ssW0rd|1
tells routed to use P4ssW0rd as the authentication password. RouteD will only accept routes if the incoming routing table uses this password with the key ID 1. There can be more then 1 password, with different key IDs.rdisc_interval=N
tells routed how often to send the routing table over. The learned routes will stay in the routing table for 3*N.
# echo “ripv2” >> /etc/gateways
# echo “md5_passwd=P4ssW0rd|1” >> /etc/gateways
# echo “rdisc_interval=10” >> /etc/gateways
Make sure that etc/gateway can be only read by root!
# chmod 600 /etc/gateways
Remove the ripv2 parameter from rc.conf
# sysrc routed_flags="-s"
routed_flags: -s -P ripv2 -> -s
Finally restart routed
# service routed restart
Stopping routed.
Starting routed.
If the password matches, the route will still be propagated between the routers.
root@router1# netstat -r4
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 link#3 UH lo1
localhost link#2 UH lo0
172.16.2.1 router2 UGH vtnet0
192.168.122.0/24 link#1 U vtnet0
router1 link#1 UHS lo0
root@router2:/home/tetragir # netstat -r4
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.168.122.1 UGS vtnet0
10.0.1.1 router1 UGH vtnet0
localhost link#2 UH lo0
172.16.2.1 link#3 UH lo2
192.168.122.0/24 link#1 U vtnet0
router2 link#1 UHS lo0
If the necessary routes are present on both routers, ping will work.
root@router1:/home/tetragir # ping 172.16.2.1
PING 172.16.2.1 (172.16.2.1): 56 data bytes
64 bytes from 172.16.2.1: icmp_seq=0 ttl=64 time=0.433 ms
64 bytes from 172.16.2.1: icmp_seq=1 ttl=64 time=0.549 ms
64 bytes from 172.16.2.1: icmp_seq=2 ttl=64 time=0.499 ms
^C
--- 172.16.2.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.433/0.494/0.549/0.048 ms
Security and alternatives
Using MD5 is not the best to secure RIP, but this is unfortunately the only way (other then plain passwords of course…). Malicious hosts can advertise routes with better hop count then the other, forcing traffic to flow to them. In bigger networks, OSPF or even BGP can be used to propagate routes between routers.