uRPF behavior


I want to show the behavior of the uRPF feature. Unicast Reverse Path Forwarding.

Basically this is a security feature, to prevent spoofed source IP address (very basic). Its function is to prevent a router from processing a packet comming from an unknown source/wrong interface.

So there are two modes of uRPF: Loose and Strict.

Loose Mode: This mode says, that as long as we have a route to the source IP address, its okay to route/process this packet. It doesnt matter what interface the packet comes in on. Please note, that default, it does not accept a default route as a valid return path. We will change this behavior later on.

Strict Mode: This mode will further enforce the uRPF check, so that the incomming interface of the packet, must be the correct one, as dictated by the routing table.

This is the topology I will use to demonstrate the functionality:

uRPF Topology

uRPF Topology

This topology is set up, so that R1 will have the IP address of .1 in the end on each subnet, R2 will have .2 and finally R3 will have .3. A loopback on each of the spoke routes have been set up with the ip address of 10.0.0.100/32. This is the IP address we will use to “spoof”. No routing protocols will be in effect at all. Output will be from “debug ip packet”.

First, lets ping the R1 IP address of 192.168.12.1 from R2’s loopback interface, without any configuration on s0/0 on R1:

R1#
*Mar  1 00:02:36.867: IP: tableid=0, s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), routed via RIB
*Mar  1 00:02:36.867: IP: s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), len 100, rcvd 3
*Mar  1 00:02:36.871: IP: s=192.168.12.1 (local), d=10.0.0.100, len 100, unroutable

As can be seen, R1 actually receives the packet and tries to route it accordingly. Since there’s no route to return the traffic its unroutable. The important thing to remember here, is that the router will try to route the traffic. Something we dont want in the case of a spoofing attack.

Now we enable the uRPF loose mode feature on s0/0:

R1(config-if)#ip verify unicast source reachable-via any
R1(config-if)#^Z
R1#

We try to ping from R2 again:

R1#

Nothing at all. R1 does not have any route to reach the source IP address of 10.0.0.100 address, so it wont even try to route it! great!

Lets try to make a route back to R2 from R1 and do a ping from R2 to R1 again:

R1(config)#ip route 10.0.0.0 255.255.255.0 192.168.12.2
*Mar  1 00:05:30.307: IP: tableid=0, s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), routed via RIB
*Mar  1 00:05:30.307: IP: s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), len 100, rcvd 3
*Mar  1 00:05:30.311: IP: tableid=0, s=192.168.12.1 (local), d=10.0.0.100 (Serial0/0), routed via FIB
*Mar  1 00:05:30.311: IP: s=192.168.12.1 (local), d=10.0.0.100 (Serial0/0), len 100, sending

Everything  works out! We have a route match, and uRPF allows the traffic to pass through.

If we now enable uRPF on s0/1 on R1, and ping from R3:

R1(config)#int s0/1
R1(config-if)#ip verify unicast source reachable-via any

Watch R2:

*Mar  1 00:08:30.603: IP: tableid=0, s=192.168.13.1 (Serial0/0), d=10.0.0.100 (Loopback0), routed via RIB
*Mar  1 00:08:30.603: IP: s=192.168.13.1 (Serial0/0), d=10.0.0.100, len 100, rcvd 4

What happens here, is actually the spoof attack itself, even though we have loose mode on. R3 pings to R1 with the source of 10.0.0.100. R1’s uRPF checks if it has a route. It does! so everything is fine as far as uRPF is concerned. Now we route it accordingly, which means sending it to R2! By doing this manipulation we are actually sending traffic to R2, from R3. This is certainly not what we want.

Now, instead of using the loose mode, lets use the strict mode and try pinging from R3 again:

R1(config-if)#ip verify unicast source reachable-via rx
R1#

Nothing! since the traffic from R3, with the IP address of 10.0.0.100 does not match the interface where R1 expects it, it drops it immediately, and does not try to route it at all! We have, by using the strict mode, prevented the spoofing attack.

Allow-Default:

Lets delete the route we created on R1, and install a default route instead:

R1(config)#no ip route 10.0.0.0 255.255.255.0 192.168.12.2
R1(config)#ip route 0.0.0.0 0.0.0.0 192.168.12.2

Pinging from R2 to R1 now doesnt succeed! Remember that by default, default routes are not considered valid for uRPF check. We can disable this by using the “allow-default” parameter:

R1(config-if)#ip verify unicast source reachable-via any allow-default
R1#
*Mar  1 00:33:37.971: IP: tableid=0, s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), routed via RIB
*Mar  1 00:33:37.975: IP: s=10.0.0.100 (Serial0/0), d=192.168.12.1 (Serial0/0), len 100, rcvd 3
*Mar  1 00:33:37.975: IP: tableid=0, s=192.168.12.1 (local), d=10.0.0.100 (Serial0/0), routed via FIB
*Mar  1 00:33:37.979: IP: s=192.168.12.1 (local), d=10.0.0.100 (Serial0/0), len 100, sending

And we have reachability again 🙂

I hope this little post has shed some light on the uRPF command. A little overseen, but pretty cool feature.