Skip to content
Log in Sign up My account

3.2.c Troubleshooting Unicast Reverse Path Forwarding

Blueprint 3.2.c: Troubleshoot router security features: unicast reverse path forwarding (uRPF)

  • What uRPF checks and why it stops spoofed source addresses
  • Strict mode versus loose mode, and where each belongs
  • Options: allow-default, ACL exceptions, allow-self-ping
  • IPv6 uRPF
  • Fault symptoms: asymmetric routing, default-only routing, Null0 routes, missing CEF

The verb is troubleshoot. A uRPF question nearly always pairs a topology with two paths and a routing table that prefers one of them, then asks why some traffic is lost. Find the arrival interface, find the route back to the source, and compare.

What uRPF does

Normal forwarding looks only at the destination address. uRPF adds a check on the source address of every packet arriving on an interface where it is enabled. The router looks up the source in the CEF table (FIB), as if it were going to send a packet back to it, and decides whether the packet is plausible.

It is the router-level way to implement ingress filtering as described in BCP 38 (RFC 2827) and BCP 84 (RFC 3704). Spoofed packets used in reflection and flooding attacks often carry source addresses that are unallocated, private, or belong to someone else's network. uRPF drops many of them without a hand-maintained ACL, because the routing table already knows which sources are legitimate behind each interface.

graph TB
  P["Packet arrives on Gi0/1<br/>source 10.20.1.5"] --> L["FIB lookup of the SOURCE 10.20.1.5"]
  L --> M{"Mode"}
  M -->|"strict, rx"| S{"Is Gi0/1 one of the<br/>best paths back to 10.20.1.5?"}
  M -->|"loose, any"| A{"Is there any route to 10.20.1.5<br/>that is not Null0?"}
  S -->|"yes"| F["Forward normally"]
  S -->|"no"| X["Check optional ACL, else drop"]
  A -->|"yes"| F
  A -->|"no"| X

Strict versus loose

Strict mode Loose mode
Command ip verify unicast source reachable-via rx ip verify unicast source reachable-via any
Legacy form ip verify unicast reverse-path none
Check Best route to the source must point out the arrival interface A route to the source must exist through any interface
Equal-cost paths Passes if the arrival interface is any of the equal-cost best paths Passes
Route to Null0 Fails Fails
Default route Does not count unless allow-default Does not count unless allow-default
Stops Spoofing of any address not legitimately behind that interface Spoofing of addresses with no route at all (bogons, unallocated space, blackholed sources)
Safe with asymmetric routing No Yes
Typical place Single-homed customer or LAN edge, where traffic in and out always uses the same link Multihomed internet edge, dual links with unequal routing, transit links

Strict mode is the stronger check, and the one that breaks networks. It only works when routing is symmetric for every source behind the interface. As soon as a site is dual-homed and the router prefers one link for return traffic, legitimate packets arriving on the other link are dropped.

Exam trap

With strict mode, the question is not "can the router reach the source?" but "would the router send traffic to that source out of the interface the packet came in on?" A router with a perfectly good route to the source through a different interface still drops the packet. Look at the exit interface in show ip route <source>, not just whether a route exists.

The options

interface GigabitEthernet0/0
 ip verify unicast source reachable-via rx allow-default 101
Option Effect
allow-default The default route is accepted as a valid route for the check. In strict mode, the default route must also point out the arrival interface.
ACL number (here 101) Packets that fail the check are compared with the ACL. A permit forwards them anyway and counts them as suppressed drops. A deny drops them. Packets that pass the check never see the ACL.
allow-self-ping Allows the router to ping its own interface address through the check. Off by default, and Cisco recommends leaving it off.

Two special cases worth knowing. uRPF lets DHCP and BOOTP requests through: packets with source 0.0.0.0 and destination 255.255.255.255 are not dropped, so DHCP still works on a strict-mode LAN interface. And uRPF depends on CEF, so it is only active when CEF is on (ip cef, which is on by default on IOS XE).

Null0 and source-based remote triggered black hole

Because a route to Null0 fails the check in both modes, uRPF can be used to drop traffic from an attacker by installing a Null0 route for the attacker's address. In a source-based RTBH design, a trigger router advertises the attacker's prefix by BGP with a next hop that every edge router routes to Null0, and loose-mode uRPF on the edge drops all packets sourced from it. You need to recognise the mechanism, not build the whole design, for ENARSI.

Exam trap

A loose-mode interface drops packets from a source that is clearly routable. Check for a more specific static route to Null0 covering that source, often a summary discard route or an RTBH entry left behind. show ip route <source> showing via Null0 explains the drops.

IPv6 uRPF

IPv6 uses the same logic with the ipv6 keyword:

interface GigabitEthernet0/1
 ipv6 verify unicast source reachable-via rx
!
interface GigabitEthernet0/2
 ipv6 verify unicast source reachable-via any

The same placement rules apply: strict mode only where IPv6 routing is symmetric, loose mode on multihomed edges. Neighbor Discovery and IPv6 routing protocols use link-local source addresses, so after enabling IPv6 strict mode always confirm that OSPFv3 or EIGRP adjacencies and neighbor resolution still work on that link.

Verification and diagnostics

R1# show ip interface GigabitEthernet0/2 | section verify
  IP verify source reachable-via RX
   18233 verification drops
   0 suppressed verification drops
   0 verification drop-rate

R1# show ip traffic | include RPF
         0 no route, 18233 unicast RPF, 0 forced drop

R1# show ip route 10.20.0.0
Routing entry for 10.20.0.0/16
  Known via "ospf 1", distance 110, metric 11, type intra area
  Last update from 10.1.2.2 on GigabitEthernet0/0, 00:22:10 ago
  Routing Descriptor Blocks:
  * 10.1.2.2, from 10.255.255.2, 00:22:10 ago, via GigabitEthernet0/0
      Route metric is 11, traffic share count is 1

R1# show ip cef 10.20.1.5
10.20.0.0/16
  nexthop 10.1.2.2 GigabitEthernet0/0

Read this exhibit as a chain. Gi0/2 runs strict mode and has a growing drop counter. The best (and only) path to the source network is out of Gi0/0. Therefore every packet from 10.20.0.0/16 that arrives on Gi0/2 fails. The fix is one of:

  • change Gi0/2 to loose mode, if the requirement allows a weaker check;
  • make routing symmetric (equal cost on both links so both are best paths), if the requirement allows changing the IGP;
  • add an exception ACL that permits the known-good source range on that interface.

Which fix is correct depends on the restrictions in the question, so read them.

Symptom Likely cause Proof
About half of sessions from a dual-homed site fail Strict mode, asymmetric routing show ip route <source> exit interface differs from the arrival interface
All traffic from internet sources dropped on the edge Strict or loose mode, router has only a default route toward the ISP Verification drops climb; route to source is 0.0.0.0/0; add allow-default
One specific source always dropped, even in loose mode More specific route to Null0 show ip route <source> shows Null0
Drops stop after enabling ip cef, or uRPF configured but no effect CEF disabled show ip cef summary; show cef interface
Pings from the router to its own interface address fail through the uRPF interface Self-ping blocked by design Expected unless allow-self-ping
Drops on an interface after an IGP cost change elsewhere The change moved the best path for some sources off this interface Compare the route to the source before and after

Exam trap

The uRPF drop counter in show ip interface belongs to the interface where uRPF is configured, which is the arrival interface of the dropped packets. Do not look for drops on the interface the route points to.

Lab: uRPF break/fix

Topology

graph LR
  SITE["R2 Lo20 10.20.1.1/24<br/>site LAN"] --- R2
  R2 -- "Gi0/0 .2  10.1.2.0/30  .1 Gi0/0" --- R1
  R2 -- "Gi0/1 .6  10.1.2.4/30  .5 Gi0/2" --- R1
  R1 -- "Gi0/1 .1  10.1.3.0/30  .2 Gi0/0" --- R3["R3 ISP<br/>Lo0 203.0.113.1"]

This lab uses two parallel links between R1 and R2, so the second link takes the next /30 (10.1.2.4/30) rather than following the one-link-per-pair convention. R3 plays an ISP and is not in OSPF.

Device Interface Address
R1 Gi0/0 10.1.2.1/30
R1 Gi0/2 10.1.2.5/30
R1 Gi0/1 10.1.3.1/30
R2 Gi0/0 10.1.2.2/30
R2 Gi0/1 10.1.2.6/30
R2 Loopback20 10.20.1.1/24
R3 Gi0/0 10.1.3.2/30
R3 Loopback0 203.0.113.1/32

Steps

  1. Run OSPF area 0 between R1 and R2 on both links and advertise Lo20 as a network (ip ospf network point-to-point on the loopback). On R1, add ip route 0.0.0.0 0.0.0.0 10.1.3.2 and default-information originate under OSPF. On R3, add ip route 10.0.0.0 255.0.0.0 10.1.3.1.
  2. On R1, set ip ospf cost 50 on Gi0/2 so R1 prefers Gi0/0 for 10.20.1.0/24. On R2, leave both links equal cost so R2 load-shares toward R1 per destination.
  3. Verify: from R2, ping 203.0.113.1 source Loopback20 repeat 100 succeeds. Check show ip route 0.0.0.0 on R2 for two paths.
  4. Break 1: on R1, configure ip verify unicast source reachable-via rx on Gi0/0 and Gi0/2. Repeat pings to several destinations behind R3 (add Lo1 to Lo4 on R3 as 203.0.113.11 to .14 /32 and use them). Expected: some destinations work and some fail, depending on which link R2's CEF hash chooses. show ip interface Gi0/2 | section verify shows verification drops, and Gi0/0 shows none.
  5. Fix it two ways, one at a time: change Gi0/2 to reachable-via any, then revert and instead remove the cost so both links are equal-cost best paths. Confirm the drops stop in both cases. Note why the second fix works: strict mode accepts any of the equal-cost best paths.
  6. Break 2: on R1 Gi0/1 (toward the ISP) configure ip verify unicast source reachable-via any. From R3, ping 10.20.1.1 source Loopback0. Expected: it fails and the Gi0/1 verification drop counter rises, because R1's only route to 203.0.113.1 is the default route. Fix with ip verify unicast source reachable-via any allow-default, then explain why that check no longer stops much on an internet edge.
  7. Break 3: set R1 Gi0/0 and Gi0/2 to loose mode (reachable-via any), then add ip route 10.20.1.0 255.255.255.128 Null0 on R1. From R2, ping 203.0.113.1 source Loopback20. Expected: the ping fails and the verification drop counters rise on whichever link the packets arrive on, even in loose mode, because R1's most specific route to the source 10.20.1.1 now points to Null0. Remove the route. This is the same mechanism a source-based RTBH design uses on purpose.

Expected verification output after Break 1 is fixed with equal costs

R1# show ip route 10.20.1.0
Routing entry for 10.20.1.0/24
  Known via "ospf 1", distance 110, metric 2, type intra area
  Routing Descriptor Blocks:
  * 10.1.2.6, from 10.255.255.2, via GigabitEthernet0/2
      Route metric is 2, traffic share count is 1
    10.1.2.2, from 10.255.255.2, via GigabitEthernet0/0
      Route metric is 2, traffic share count is 1

R1# show ip interface GigabitEthernet0/2 | section verify
  IP verify source reachable-via RX
   312 verification drops
   0 suppressed verification drops
   0 verification drop-rate

The drop counter stays at the value it reached before the fix. Clear interface counters or watch it for a minute to prove it is no longer rising.

Quick check

R1 has two equal-cost OSPF routes to 10.5.0.0/16, through Gi0/1 and Gi0/2. Strict uRPF is on both interfaces. A packet from 10.5.1.1 arrives on Gi0/2. Is it dropped?

No. Strict mode passes the packet if the arrival interface is one of the best paths to the source. Both interfaces are best paths, so the check passes.

What happens to a packet that fails the uRPF check on an interface configured with ip verify unicast source reachable-via rx 120, when ACL 120 permits its source?

It is forwarded, and it is counted as a suppressed verification drop. The ACL is consulted only for packets that fail the check.

Why is loose mode with allow-default of limited value on a router that has only a default route toward the internet?

Every source matches the default route, so almost nothing fails the check. Only sources covered by a more specific Null0 route (or another non-default route through which the check fails) are dropped.

References