The Verify Source command.


In this small post i want to clarify the use of the “ip verify” command.

There has been some confusion on the usage of this command, especially in conjunction with the access-list parameter. I would like to clarify this here.

The command is basically a way to mitigate spoofing. You want to make sure that the source of the packet is received from the correct path, meaning interface.

First off the topology:

Verify Source Topology

We only have two routers here. R1 and R2.

R1 has a loopback0 interface with the 100.100.100.100/32 address.

R2 has two loopback interfaces. Loopback0, also with 100.100.100.100/32 and loopback200 with address 200.200.200.200/32.

R1 has a default route pointing to R2 (192.168.12.2):

R1(config)#do sh ip route | beg Gate
 Gateway of last resort is 192.168.12.2 to network 0.0.0.0
C    192.168.12.0/24 is directly connected, Serial0/0
100.0.0.0/32 is subnetted, 1 subnets
 C       100.100.100.100 is directly connected, Loopback0
 S*   0.0.0.0/0 [1/0] via 192.168.12.2

 

Reachability in this example is not important, but the output of R2 is. So lets turn on debugging on R2:

R2#debug ip routing
 IP routing debugging is on

 

So lets start with something that should work, namely a ping from R1 to R2. Without any parameters the ping will be sourced with 192.168.12.1:

R1#ping 200.200.200.200 rep 1
Type escape sequence to abort.
 Sending 1, 100-byte ICMP Echos to 200.200.200.200, timeout is 2 seconds:
 !
 Success rate is 100 percent (1/1), round-trip min/avg/max = 36/36/36 ms

 

And we can see on R2 that everything is as we expect:

*Mar  1 02:43:00.423: IP: tableid=0, s=192.168.12.1 (Serial0/0), d=200.200.200.200 (Loopback200), routed via RIB
*Mar  1 02:43:00.423: IP: s=192.168.12.1 (Serial0/0), d=200.200.200.200, len 100, rcvd 4
*Mar  1 02:43:00.427: IP: tableid=0, s=200.200.200.200 (local), d=192.168.12.1 (Serial0/0), routed via FIB
*Mar  1 02:43:00.427: IP: s=200.200.200.200 (local), d=192.168.12.1 (Serial0/0), len 100, sending

 

Now for the next part, we wont actually get a response back from R2. The reason for this is ofcourse that the source address is locally defined as the loopback0 interface. However it does demonstrates that R2 accepts the packet:

R1#ping 200.200.200.200 rep 1 source loo0
Type escape sequence to abort.
Sending 1, 100-byte ICMP Echos to 200.200.200.200, timeout is 2 seconds:
Packet sent with a source address of 100.100.100.100
.
Success rate is 0 percent (0/1)

 

And on R2:

*Mar  1 02:44:30.187: IP: tableid=0, s=100.100.100.100 (Serial0/0), d=200.200.200.200 (Loopback200), routed via RIB
*Mar  1 02:44:30.187: IP: s=100.100.100.100 (Serial0/0), d=200.200.200.200, len 100, rcvd 4
*Mar  1 02:44:30.191: IP: tableid=0, s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 02:44:30.191: IP: s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), len 100, sending
*Mar  1 02:44:30.195: IP: tableid=0, s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 02:44:30.199: IP: s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), len 100, rcvd 3

 

The command itself is interface specific. It also has an older version which accomplish the same but i wont cover (all interface is on R2 s0/0):

R2(config-if)#ip verify unicast ?
reverse-path  Reverse path validation of source address (old command format)
source        Validation of source address

 

Digging a bit deeper we get:

R2(config-if)#ip verify unicast source reachable-via ?
any  Source is reachable via any interface
rx   Source is reachable via interface on which packet was received

 

The any option basically tells the router to accept the packet if any known route to the source exists. The RX option will only accept the packet if the source of the packet is reachable through the received interface.

For this test, remember that R2 thinks that the correct path to reach 100.100.100.100 is on its loopback0 interface:

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

 

And lets try from R1 again, using 100.100.100.100 as the source:

R1#ping 200.200.200.200 rep 1 source loo0
Type escape sequence to abort.
Sending 1, 100-byte ICMP Echos to 200.200.200.200, timeout is 2 seconds:
Packet sent with a source address of 100.100.100.100
.
Success rate is 0 percent (0/1)

 

And on R2 nothing happens.

It is simply denying the packet.

Modifying the command on R2 to:

R2(config-if)#ip verify unicast source reachable-via any

 

And again from R1:

R1#ping 200.200.200.200 rep 1 source loo0
Type escape sequence to abort.
Sending 1, 100-byte ICMP Echos to 200.200.200.200, timeout is 2 seconds:
Packet sent with a source address of 100.100.100.100
.
Success rate is 0 percent (0/1)

 

And on R2 we now see we get a reply. R2 does have a route to 100.100.100.100, even though it is its own loopback interface.

R2(config-if)#
*Mar  1 02:53:20.935: IP: tableid=0, s=100.100.100.100 (Serial0/0), d=200.200.200.200 (Loopback200), routed via RIB
*Mar  1 02:53:20.935: IP: s=100.100.100.100 (Serial0/0), d=200.200.200.200, len 100, rcvd 4
*Mar  1 02:53:20.939: IP: tableid=0, s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 02:53:20.939: IP: s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), len 100, sending
*Mar  1 02:53:20.943: IP: tableid=0, s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 02:53:20.943: IP: s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), len 100, rcvd 3

 

Lets modify the R2 config back to RX mode but also see what options we have:

R2(config-if)# ip verify unicast source reachable-via rx ?
<1-199>          A standard IP access list number
<1300-2699>      A standard IP expanded access list number
allow-default    Allow default route to match when checking source address
allow-self-ping  Allow router to ping itself (opens vulnerability in
verification)
<cr>

 

Hmm. the access-list. How does that work?

It works in the following way, when a packet fails the verification, and only then, it goes through a second check. It checks the access-list to see if by any chance the source of this packet should be allowed anyways. If there is a permit for the source, it wont get dropped even though it failed the initial verification.

So lets write a simply standard access-list for our 100.100.100.100 network:

access-list 10 permit 100.100.100.100
access-list 10 deny   any

 

(please note that the explicit deny is not nessecary).

And lets attach it to the command:

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

 

Now once again, lets try from R1:

R1#ping 200.200.200.200 rep 1 source loo0
Type escape sequence to abort.
Sending 1, 100-byte ICMP Echos to 200.200.200.200, timeout is 2 seconds:
Packet sent with a source address of 100.100.100.100
.
Success rate is 0 percent (0/1)

 

And the output on R2:

R2(config-if)#
*Mar  1 03:13:39.859: IP: tableid=0, s=100.100.100.100 (Serial0/0), d=200.200.200.200 (Loopback200), routed via RIB
*Mar  1 03:13:39.859: IP: s=100.100.100.100 (Serial0/0), d=200.200.200.200, len 100, rcvd 4
*Mar  1 03:13:39.863: IP: tableid=0, s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 03:13:39.863: IP: s=200.200.200.200 (local), d=100.100.100.100 (Loopback0), len 100, sending
*Mar  1 03:13:39.867: IP: tableid=0, s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), routed via RIB
*Mar  1 03:13:39.871: IP: s=200.200.200.200 (Loopback0), d=100.100.100.100 (Loopback0), len 100, rcvd 3

 

So there we have it. It fails the first verification, but after checking the ACL it allows the the packet to go through anyways because of the permit statement.

A last note, the allow-default parameter makes it so it will take a default route into account. The allow-self-ping makes it so the router can actually ping its own interface without failing the verification.

Hope this shed some light on this command.