A laptop sits on the office /24 over Ethernet and also joins an OpenVPN server that lives in that same /24. A colleague pings the tunnel address; the request clearly arrives, and nothing goes back. The tunnel log is clean and browsing still works, so the tunnel is the wrong suspect. IPv4 source validation on the receiving machine throws the packet away before anything reads it.

The drop happens before anything reads the packet

Source validation asks one question about every inbound packet: if this host answered that source, would the answer leave through the interface the packet just arrived on? When the answer is no, the kernel throws the packet away on arrival. No socket and no forwarding path ever sees it, which is why a capture on the tunnel still records a request the application never receives.

The client here holds 10.66.0.9 on its tunnel, and the OpenVPN server answers at 192.168.80.10 inside the office prefix. A colleague at 192.168.80.25 pings the tunnel address, so the request crosses the LAN, the server routes it into the tunnel, and it arrives on the client's tunnel interface carrying an office source address. In that machine's routing table the office prefix belongs to the Ethernet device, not to the tunnel. Validation compares the arrival interface with the route, finds a mismatch, and discards the packet, so the colleague sees complete loss while both ends report a healthy tunnel.

The mirror direction has the same shape: when the client initiates toward the office, replies can be discarded on the office side for the identical reason. A fix verified in one direction only tends to return as a second ticket.

Prove the mode in force before you touch a sysctl

Read the effective values rather than trusting a distribution default, because the per-interface setting is only half of the decision. The mode in force is the higher of the interface value and the all value, so a zero on the tunnel interface means nothing while all is one. Strict mode's decision is a routing decision, so run the lookup the kernel runs and compare its answer with the interface the packet actually arrived on.

tcpdump -ni tun0 icmp and host 192.168.80.25
ip route get 192.168.80.25
sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.tun0.rp_filter

Then repeat the ping while watching the error counter. A rising count beside a request the capture already shows is the signature of this drop, not of a missing route. Turn on martian logging while you are there, so the kernel names the source and the interface it rejected. Together they rule out the cipher, the firewall and a missing iroute as explanations.

Write the baseline down before changing anything: both values, the device the lookup chose, and the counter you watched. That record is what tells you afterwards whether the change did what you think.

What each rp_filter mode actually accepts

The kernel exposes three values per interface, and they are not three shades of one rule. Zero disables the check. One is strict, requiring the source to be routed back out the arrival interface. Two is loose, requiring only that some route to the source exists in the table, wherever it points.

ValueNameAcceptsStill rejects
0offany source at allnothing on this check
1stricta source routed back out the arrival interfacea source whose route points elsewhere
2loosea source with any route in the tablea source with no route at all

The row that matters here is the loose one, and what it keeps rejecting. A spoofed source that is routable anywhere in your table passes, while a source with no route at all is still refused. On a laptop that is a narrow concession; on a router forwarding traffic for other people it is a wide one. The mode belongs to the host, so the same number carries different weight in the two places.

Which row this topology needs follows from the table rather than from habit. The packet is legitimate and its source is routable, so loose accepts it and strict does not. Nothing in the case calls for zero, and choosing zero would remove a check that costs nothing here.

Pick the smallest change that removes the ambiguity

Loose mode is the smallest change that fits, and it is a real reduction in strictness rather than a harmless switch. A better option exists whenever the topology allows it: remove the overlap, and the ambiguity disappears.

Where the office prefix is only ever needed over Ethernet, drop it from the routes the profile pulls and the address becomes reachable by one path. When both paths genuinely have to coexist, pin the source and the device with a policy rule instead of loosening validation on every interface. That keeps strict filtering for everything else on the machine and documents the exception where the next engineer will look for it.

Whichever route you take, record it in a sysctl drop-in rather than a live command. Set the all and default keys together, so a reconnect cannot quietly restore strict mode.

# /etc/sysctl.d/99-rp-filter.conf
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.all.rp_filter = 2
sysctl --system

What loose mode gives up, and where

Loose mode still rejects a source that no route could reach, and it stops rejecting a spoofed source that happens to be routable. On a laptop that is a narrow concession. On a device that forwards traffic it does not own, the same choice is a much wider one. The same setting therefore carries two very different meanings depending on where it runs.

Switching the check off entirely, on a host that forwards traffic for other people, is the one repair to avoid. Zero throws away the validation that loose mode is careful to keep. If the host forwards for other people, argue for the policy-rule option from the previous section instead.

Leave a note naming the two interfaces, the overlapping prefix and the exact probe that now succeeds. That is more useful to the next engineer than a line saying filtering was adjusted.

Ingingo zihuye