Linux rp_filter Explained: Fix Asymmetric Routing and Multi-NIC Packet Drops
A Linux server can receive a packet on the correct network interface and still silently discard it before your application ever sees it.
The interface is up.
The IP address is correct.
The firewall appears to allow the connection.
tcpdump confirms that packets are arriving.
Yet SSH, HTTPS, database connections, monitoring traffic, or another service never responds correctly.
On multi-homed Linux servers, one possible cause is reverse path filtering, controlled by the kernel parameter:
net.ipv4.conf.*.rp_filter
rp_filter is a source-validation mechanism. Instead of simply accepting an incoming IPv4 packet because it arrived at a valid local address, Linux can check whether the packet’s source address makes sense according to the kernel’s routing information.
That is valuable for reducing source-address spoofing.
But strict reverse-path validation can conflict with legitimate asymmetric routing, multiple gateways, policy routing, multiple NICs, VPNs, and complex multi-homed networks.
This guide explains exactly how Linux rp_filter works, the differences between values 0, 1, and 2, how to diagnose reverse-path filtering without blindly disabling it, and how it interacts with policy routing and multi-NIC servers.
What Is Linux rp_filter?
rp_filter stands for reverse path filtering.
The parameter belongs to Linux’s IPv4 networking configuration:
net.ipv4.conf.INTERFACE.rp_filter
You can inspect the global value with:
sysctl net.ipv4.conf.all.rp_filter
and the default applied to relevant interfaces with:
sysctl net.ipv4.conf.default.rp_filter
You can also inspect a specific interface:
sysctl net.ipv4.conf.enp1s0.rp_filter
The <a href=”https://docs.kernel.org/networking/ip-sysctl.html” target=”_blank” rel=”noopener”>official Linux kernel IP sysctl documentation</a> defines three modes:
0 = No source validation
1 = Strict reverse-path validation
2 = Loose reverse-path validation
The difference between these values is fundamental.
How Reverse Path Filtering Works
Imagine that a packet arrives:
Source: 203.0.113.50
Destination: 192.168.10.20
Interface: enp2s0
Without reverse-path validation, Linux can continue processing the packet according to the normal networking stack.
With rp_filter enabled, Linux performs a source-validation check.
Conceptually, Linux asks:
If I needed to send traffic toward
203.0.113.50, what route would my forwarding information base consider valid?
In strict mode, the incoming interface matters strongly.
The Linux kernel documentation states that in strict mode an incoming packet is tested against the FIB, and the check fails when the incoming interface is not the best reverse path. Failed packets are discarded.
This is why the feature can affect multi-homed systems.
If you are already seeing Linux choose an unexpected outbound interface, first read CorgiNetwork’s <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Linux Traffic Uses the Wrong Interface</a> guide because an incorrect routing decision can directly influence reverse-path validation.
Understanding rp_filter=0
The first mode is:
rp_filter = 0
This means:
No reverse-path source validation
The kernel does not perform this particular reverse-path filtering test.
This can accommodate complex routing topologies, but disabling source validation has security implications.
Therefore, this should not be your first troubleshooting command:
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
Doing so may make a symptom disappear without proving why it happened.
The better approach is:
Observe
↓
Inspect routes
↓
Reproduce reverse lookup
↓
Confirm asymmetric path
↓
Choose appropriate rp_filter behavior
Understanding rp_filter=1: Strict Mode
Strict mode is:
rp_filter = 1
Suppose a packet arrives on:
enp2s0
from:
203.0.113.50
Linux checks the route toward that source.
Imagine:
ip route get 203.0.113.50
returns:
203.0.113.50 via 192.168.10.1 dev enp1s0
The packet arrived through:
enp2s0
but Linux considers:
enp1s0
the best reverse path.
In strict mode, that mismatch can cause source validation to fail.
Conceptually:
Packet arrives
↓
enp2s0
↓
Source = 203.0.113.50
↓
Reverse route lookup
↓
Best path = enp1s0
↓
enp2s0 ≠ enp1s0
↓
Validation fails
The Linux kernel describes strict mode precisely in these terms: if the incoming interface is not the best reverse path according to the FIB, the packet fails the check.
Understanding rp_filter=2: Loose Mode
Loose mode is:
rp_filter = 2
The question changes.
Instead of requiring:
Is this incoming interface the best reverse path?
Linux effectively checks whether the source is reachable through any interface according to the routing information.
If the source address has a valid route somewhere, the reverse-path test can succeed.
The kernel documentation explicitly recommends loose mode when asymmetric routing or other complicated routing is required.
This distinction is critical:
STRICT MODE
Source reachable through THIS expected path?
↓
YES
↓
Accept
LOOSE MODE
Source reachable through ANY interface?
↓
YES
↓
Accept
Loose mode preserves source validation while accommodating more complicated paths.
rp_filter 0 vs 1 vs 2
A concise comparison:
| Value | Mode | Behavior |
|---|---|---|
0 |
Disabled | No rp_filter source validation |
1 |
Strict | Incoming interface must satisfy the strict reverse-path test |
2 |
Loose | Source must be reachable through an interface |
The Linux kernel notes that strict reverse-path validation is useful against source-address spoofing, while loose mode is appropriate when asymmetric or complicated routing is intentionally used.
That means the correct choice depends on the network architecture.
Why Multi-NIC Linux Servers Can Trigger the Problem
Consider:
Internet
|
+--------+--------+
| |
Gateway A Gateway B
| |
enp1s0 enp2s0
\ /
\ /
Linux Server
Addresses:
enp1s0 → 192.168.10.20
enp2s0 → 10.20.30.20
Now suppose an incoming connection reaches:
10.20.30.20
through:
enp2s0
but the main routing table contains:
default via 192.168.10.1 dev enp1s0
A reverse lookup toward the remote client may therefore prefer:
enp1s0
instead of:
enp2s0
Strict reverse-path filtering can see that as invalid.
This is one reason multi-NIC problems should not be diagnosed by changing sysctl parameters first.
The underlying routing architecture matters.
If each source IP should use its corresponding gateway, see CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing Guide</a>.
Asymmetric Routing Explained
In symmetric routing, traffic conceptually follows:
Client
|
| request
v
Gateway B
|
v
enp2s0
|
Linux
|
v
enp2s0
|
v
Gateway B
|
| response
v
Client
But an asymmetric path could look like:
REQUEST
Client
↓
Gateway B
↓
enp2s0
↓
Linux
RESPONSE
Linux
↓
enp1s0
↓
Gateway A
↓
Client
Asymmetric routing is not inherently invalid.
There are legitimate architectures where forward and reverse paths differ.
The problem is that strict source validation, stateful firewalls, NAT, upstream anti-spoofing systems, and other controls may expect more symmetric behavior.
The kernel documentation specifically identifies asymmetric routing as a case where loose reverse-path validation can be appropriate.
Symptoms of an rp_filter Problem
Possible symptoms include:
tcpdumpsees incoming packets but the application does not;- SSH works through one interface but fails through another;
- the secondary IP is reachable only from certain networks;
- adding a second default gateway causes connections to fail;
- policy routing appears correct but packets still disappear;
- multi-homed services work only when one NIC is disabled;
- connections fail after a route change;
- packets arrive but no expected response leaves.
None of these symptoms proves rp_filter is responsible.
They merely justify investigating it.
Step 1: Check the Current Values
Start with:
sysctl net.ipv4.conf.all.rp_filter
Then:
sysctl net.ipv4.conf.default.rp_filter
Now inspect every relevant interface:
sysctl net.ipv4.conf.enp1s0.rp_filter
sysctl net.ipv4.conf.enp2s0.rp_filter
You can display all matching values:
sysctl -a 2>/dev/null | grep '\.rp_filter'
This matters because the kernel documentation specifies that the maximum value from the all and interface-specific rp_filter settings is used for source validation on an interface.
That detail causes many troubleshooting mistakes.
Why Changing Only the Interface May Not Work
Suppose:
net.ipv4.conf.all.rp_filter = 1
and:
net.ipv4.conf.enp2s0.rp_filter = 0
You might assume reverse-path filtering is disabled on enp2s0.
But the kernel documentation says the maximum value between the relevant all and interface setting is used.
Therefore, always inspect both scopes before concluding that a change is active.
Step 2: Inspect the Actual Routing Tables
Run:
ip route
Then:
ip rule
Then:
ip route show table all
Linux supports multiple routing tables, and those additional tables become especially important with policy routing. The ip-route(8) documentation notes that multiple routing tables come into play when policy routing is used.
External reference: <a href=”https://man7.org/linux/man-pages/man8/ip-route.8.html” target=”_blank” rel=”noopener”>Linux ip-route(8) manual</a>.
Do not assume the visible default route in the main table tells the entire story.
Step 3: Reproduce the Reverse Lookup
Suppose tcpdump shows an incoming packet from:
203.0.113.50
on:
enp2s0
Ask Linux how it routes toward that source:
ip route get 203.0.113.50
Possible result:
203.0.113.50 via 192.168.10.1 dev enp1s0
Now you have something important:
Incoming interface = enp2s0
Best route toward source = enp1s0
That is exactly the type of topology that deserves investigation when strict reverse-path filtering is enabled.
The ip route get command supports detailed route lookups including source, incoming interface, output interface, packet mark, protocol, and ports.
Test the Incoming Interface Explicitly
For deeper diagnostics, ip route get also accepts an incoming interface.
For example:
ip route get 203.0.113.50 iif enp2s0
The exact lookup you need depends on the topology, but this capability is useful because Linux routing decisions can involve more than destination addresses.
The <a href=”https://man7.org/linux/man-pages/man8/ip-route.8.html” target=”_blank” rel=”noopener”>ip-route manual</a> documents from, iif, oif, mark, ipproto, sport, and dport as route-lookup inputs.
Step 4: Capture the Packet
Run:
sudo tcpdump -ni enp2s0 host 203.0.113.50
Suppose you see:
203.0.113.50.52140 > 10.20.30.20.443: Flags [S]
repeated several times.
The packet definitely reaches the interface.
Now capture across all interfaces:
sudo tcpdump -ni any host 203.0.113.50
Ask:
Does the SYN arrive?
Does Linux generate a SYN-ACK?
Does the SYN-ACK leave?
Does the client respond?
For packet-level troubleshooting beyond tcpdump, use CorgiNetwork’s <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a> guide.
Step 5: Confirm the Service Is Actually Listening
Before blaming the kernel, run:
ss -lntp
Suppose you expect HTTPS on:
10.20.30.20:443
but the service listens only on:
192.168.10.20:443
That is not an rp_filter problem.
Likewise, if:
0.0.0.0:443
is listening, investigate the next layer.
Good troubleshooting eliminates simpler explanations before changing security-related kernel parameters.
Step 6: Check the Firewall
Inspect nftables:
sudo nft list ruleset
or the firewall framework used by your distribution.
A packet can be visible in tcpdump but still be rejected later in the network stack.
CorgiNetwork’s <a href=”https://corginetwork.com/firewalls-explained/“>Firewalls Explained</a> guide covers the relationship between interfaces, addresses, protocols, connection state and filtering.
Do not disable the firewall and rp_filter simultaneously.
If connectivity suddenly works, you will not know which change mattered.
rp_filter and Policy Routing
Now consider a more advanced configuration:
192.168.10.20
↓
Table 100
↓
Gateway A
10.20.30.20
↓
Table 200
↓
Gateway B
Linux policy routing uses rules to determine which routing table should be consulted.
Inspect them with:
ip rule
The ip utility exposes rule specifically for managing the routing policy database.
Then inspect:
ip route show table 100
ip route show table 200
If policy routing correctly establishes the expected reverse path, you may be able to preserve stronger source validation rather than weakening rp_filter.
That is why routing should usually be corrected before filtering is relaxed.
For a complete Ubuntu implementation, use the published CorgiNetwork guide:
<a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes: Ubuntu Policy Routing and Two-NIC Servers</a>.
Policy Routing Can Be the Real Fix
Imagine this configuration:
Packet arrives on enp2s0
Source: 203.0.113.50
Main table:
default via Gateway A dev enp1s0
Without appropriate policy routing:
Reverse lookup
↓
enp1s0
But if your architecture requires traffic associated with the second path to use a separate routing table, policy routing may produce a route consistent with that design.
The important lesson is:
Do not treat
rp_filteras a substitute for correct routing.
Sometimes strict validation exposes a routing configuration that was already inconsistent.
rp_filter and fwmark-Based Routing
Advanced Linux configurations can route packets using firewall marks.
The kernel provides:
net.ipv4.conf.*.src_valid_mark
The official documentation explains that when src_valid_mark=1, a packet’s fwmark is included in the reverse-path route lookup. This allows rp_filter to function with configurations that use marks for routing in both directions.
This is particularly relevant to:
- transparent proxies;
- advanced policy routing;
- multi-WAN systems;
- nftables marking;
- specialized gateways.
Do not modify src_valid_mark unless your routing architecture actually uses packet marks.
Loose Mode vs Disabling rp_filter
Administrators sometimes jump directly from:
rp_filter = 1
to:
rp_filter = 0
But loose mode exists:
rp_filter = 2
and can be a better fit for legitimate asymmetric routing.
Conceptually:
Strict
↓
Must satisfy strict reverse path
Loose
↓
Source must be reachable somewhere
Disabled
↓
No rp_filter validation
The kernel documentation explicitly identifies loose mode as appropriate for asymmetric or complicated routing.
Red Hat’s security documentation likewise describes values 0, 1, and 2, and cautions against simply disabling reverse-path validation without another source-validation mechanism where it is needed.
External reference: <a href=”https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/security_guide/sec-securing_network_access” target=”_blank” rel=”noopener”>Red Hat Reverse Path Forwarding documentation</a>.
Temporarily Testing Loose Mode
If your investigation demonstrates that legitimate asymmetric routing conflicts with strict validation, you can perform a controlled test.
For example:
sudo sysctl -w net.ipv4.conf.all.rp_filter=2
and, depending on the existing settings:
sudo sysctl -w net.ipv4.conf.enp2s0.rp_filter=2
Then immediately repeat the same packet test.
Do not change five networking parameters at once.
Use:
Baseline test
↓
One controlled change
↓
Repeat identical test
↓
Compare packet capture
If the previously failing connection begins working, you now have evidence supporting the hypothesis.
You still need to decide whether loose mode is the correct production design.
Do Not Test by Disabling Every Security Control
This is poor troubleshooting:
systemctl stop firewalld
sysctl -w net.ipv4.conf.all.rp_filter=0
# disable security group
# disable ACL
If connectivity works afterward, you have learned almost nothing.
Instead:
Test firewall
↓
Test routing
↓
Test rp_filter
↓
Test upstream path
Change one relevant variable at a time.
Making rp_filter Changes Persistent
A runtime command such as:
sudo sysctl -w net.ipv4.conf.all.rp_filter=2
does not by itself provide a maintainable permanent configuration.
On systems using sysctl.d, you can create an appropriately named configuration file, for example:
/etc/sysctl.d/90-multihoming.conf
A configuration might contain values chosen for your topology, such as:
# Reverse-path filtering for intentionally asymmetric multi-homed routing.
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
Then load the appropriate sysctl configuration according to your distribution’s management practices.
Before making it permanent, document why loose mode is required.
A future administrator should not find:
rp_filter = 2
without knowing which routing architecture depends on it.
Verify After Reboot
After rebooting during an appropriate maintenance window:
sysctl net.ipv4.conf.all.rp_filter
Then:
sysctl net.ipv4.conf.default.rp_filter
and:
sysctl net.ipv4.conf.enp1s0.rp_filter
sysctl net.ipv4.conf.enp2s0.rp_filter
Also verify:
ip rule
ip route show table all
Persistent reverse-path settings are useless if the routing configuration they were designed for did not load correctly.
rp_filter vs arp_filter
These two kernel settings have similar names but solve completely different problems.
rp_filter
Concerned with:
Incoming IP packet
↓
Source address
↓
Reverse route validation
arp_filter
Concerned with:
ARP request
↓
Which interface should answer?
The kernel documentation says arp_filter=1 can be used with multiple interfaces on the same subnet and relies on source-based routing to decide whether an interface should answer an ARP request.
If your problem is that the wrong NIC/MAC answers ARP requests, use CorgiNetwork’s:
<a href=”https://corginetwork.com/linux-arp-flux-multiple-nics-same-subnetpolicy-routing/“>Linux ARP Flux: Multiple NICs on the Same Subnet</a>.
Do not change rp_filter to solve an ARP-layer problem.
rp_filter vs ARP Flux
A useful distinction:
ARP FLUX
Who answers:
"Who has this IPv4 address?"
↓
Layer 2 / neighbor resolution behavior
versus:
REVERSE PATH FILTERING
Packet has already arrived
↓
Does this source make sense
according to routing?
They can occur on the same multi-homed server, which is why confusing them is easy.
The correct troubleshooting order is often:
ARP / neighbor resolution
↓
Incoming interface
↓
Reverse-path validation
↓
Routing
↓
Firewall
↓
Application
rp_filter vs Firewall Drops
Suppose tcpdump sees:
SYN → server
but the application never sees the connection.
Several mechanisms could be responsible:
rp_filter
firewall
policy routing
application binding
security software
Inspect the firewall rather than assuming rp_filter.
For example:
sudo nft list ruleset
Then inspect system logs where appropriate.
A strong diagnosis identifies the exact layer responsible for the drop.
Practical Example: Two ISP Connections
Consider a Linux server with:
ISP A
|
enp1s0
192.0.2.10
|
Linux
|
enp2s0
198.51.100.10
|
ISP B
An Internet client reaches:
198.51.100.10
through ISP B.
But the server’s ordinary default route points to ISP A.
Without suitable routing policy:
Packet arrives via ISP B
↓
enp2s0
↓
Linux checks route to source
↓
Main table says ISP A
↓
enp1s0
With strict reverse-path validation, this topology can cause incoming traffic to fail validation.
Potential solutions depend on the design:
- correct source-based policy routing;
- use loose reverse-path validation where asymmetry is intentional;
- redesign the routing architecture;
- use appropriate multi-WAN routing.
Simply disabling validation is not necessarily the correct solution.
Practical Example: Management NIC + Production NIC
Suppose:
enp1s0
10.10.10.20
Management network
enp2s0
172.16.20.20
Production network
The management network should be reachable only through:
10.10.10.1
while production traffic uses:
172.16.20.1
If both interfaces depend on one global default route, the reverse route for management clients may point through the production NIC.
Instead of weakening rp_filter, a cleaner architecture may be:
Management source/network
↓
Management routing table
Production source/network
↓
Production routing table
CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Policy Routing Guide</a> demonstrates this type of separation on Ubuntu.
Practical Example: Packet Arrives but SSH Fails
Suppose:
sudo tcpdump -ni enp2s0 tcp port 22
shows:
client → SYN → server
client → SYN → server
client → SYN → server
but:
ss -lntp | grep ':22'
confirms SSH is listening.
Now check:
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.enp2s0.rp_filter
Then:
ip route get CLIENT_IP
If:
Incoming = enp2s0
Reverse route = enp1s0
Strict rp_filter = active
you have a strong hypothesis worth testing.
That is much better than immediately editing /etc/ssh/sshd_config.
Use Netcat to Separate Routing from Application Problems
If SSH or HTTPS fails, test the actual port:
nc -vz SERVER_IP 22
or:
nc -vz SERVER_IP 443
CorgiNetwork’s <a href=”https://corginetwork.com/netcat-explained/“>Netcat Explained</a> guide covers direct TCP and UDP connectivity testing.
If multiple services fail only through one NIC, the probability of a network-path problem increases.
If only one application fails while others work through the same interface, investigate that application first.
Use Wireshark or tcpdump to Confirm the Direction
Command-line capture:
sudo tcpdump -ni any host CLIENT_IP
A healthy TCP handshake should resemble:
Client → SYN
Server → SYN-ACK
Client → ACK
If you only see:
Client → SYN
Client → SYN
Client → SYN
the server is not successfully responding.
Now determine whether the packet:
- reaches the interface;
- survives reverse-path validation;
- survives firewall processing;
- reaches the listening socket.
For more advanced analysis, see <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a>.
A Complete rp_filter Troubleshooting Workflow
Use this order.
Step 1 — Identify interfaces
ip -br link
Step 2 — Identify addresses
ip -br addr
Step 3 — Check main routes
ip route
Step 4 — Check policy rules
ip rule
Step 5 — Check every routing table
ip route show table all
Step 6 — Inspect rp_filter
sysctl -a 2>/dev/null | grep '\.rp_filter'
Step 7 — Capture the incoming packet
sudo tcpdump -ni INTERFACE host CLIENT_IP
Step 8 — Reproduce the reverse lookup
ip route get CLIENT_IP
Step 9 — Check firewall rules
sudo nft list ruleset
Step 10 — Confirm listening sockets
ss -lntp
Step 11 — Test the service
nc -vz SERVER_IP PORT
Step 12 — If justified, test an alternative rp_filter mode
Make one controlled change and repeat exactly the same test.
This process gives you evidence instead of guesses.
Diagnostic Decision Tree
Packet reaches interface?
|
+----+----+
| |
NO YES
| |
Upstream v
network Correct destination?
|
+----+----+
| |
NO YES
| |
Routing v
rp_filter active?
|
+----+----+
| |
NO YES
| |
Firewall / v
application Reverse route
|
+----+----+
| |
Expected Different
| |
v v
Check next Policy routing /
layer loose-mode analysis
Common Mistake 1: Immediately Setting rp_filter=0
This is perhaps the most common mistake.
A connection fails on the secondary NIC, so an administrator searches online and finds:
sysctl -w net.ipv4.conf.all.rp_filter=0
Connectivity returns.
Problem solved?
Not necessarily.
The test proved that reverse-path validation was relevant.
It did not prove that disabling validation is the best architecture.
You may instead need:
- policy routing;
- corrected route metrics;
- a missing route;
- loose mode;
- a better multi-WAN design.
Common Mistake 2: Changing Only default.rp_filter
The default value is important for interface configuration, but you should inspect:
all
default
actual interface
rather than assuming one value describes the active behavior.
Use:
sysctl -a 2>/dev/null | grep '\.rp_filter'
and inspect the complete state.
Common Mistake 3: Confusing rp_filter with a Stateful Firewall
Reverse-path filtering is not the same thing as:
nftables
iptables
UFW
firewalld
It is kernel source validation based on routing information.
Both mechanisms can drop traffic, but they do so for different reasons.
Common Mistake 4: Fixing Filtering Before Fixing Routing
Suppose:
ip route get CLIENT_IP
clearly returns the wrong interface.
That routing problem should receive attention before you weaken validation to accommodate it.
Use the CorgiNetwork <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Wrong Interface Troubleshooting Guide</a> to investigate route selection first.
Common Mistake 5: Confusing rp_filter and arp_filter
Remember:
rp_filter
=
Reverse path validation of IP source
arp_filter
=
ARP response behavior
For multiple NICs on the same subnet and unexpected MAC/interface behavior, see the <a href=”https://corginetwork.com/linux-arp-flux-multiple-nics-same-subnetpolicy-routing/“>Linux ARP Flux Guide</a> instead.
Common Mistake 6: Ignoring Distribution Defaults
The upstream Linux kernel documentation lists the default rp_filter value as 0, while noting that some distributions enable it through startup configuration.
Therefore, never assume:
"My Linux distribution must use value X."
Measure the actual machine:
sysctl net.ipv4.conf.all.rp_filter
and:
sysctl net.ipv4.conf.INTERFACE.rp_filter
The running configuration is what matters.
Production Checklist
Before changing rp_filter permanently, confirm:
✓ Incoming interface identified
✓ Source address identified
✓ Reverse route verified
✓ Main routing table inspected
✓ Policy-routing rules inspected
✓ Custom routing tables inspected
✓ Firewall checked
✓ Listening application verified
✓ Packet capture performed
✓ Asymmetric routing confirmed or ruled out
✓ Security implications considered
✓ Strict vs loose mode evaluated
✓ Configuration documented
✓ Persistence tested after reboot
If you cannot explain why the current reverse route differs from the incoming interface, continue diagnosing before changing the security policy.
Frequently Asked Questions
What does Linux rp_filter do?
It performs IPv4 reverse-path source validation. Linux checks an incoming packet’s source against routing information to determine whether the source is plausible according to the configured mode.
What does rp_filter=0 mean?
It disables this reverse-path source-validation mechanism.
What does rp_filter=1 mean?
It enables strict mode. The kernel checks the source against the FIB, and the incoming interface must satisfy the strict best-reverse-path requirement.
What does rp_filter=2 mean?
It enables loose mode. The source needs to be reachable through an interface rather than satisfying strict incoming-interface validation. The kernel recommends loose mode for asymmetric or complicated routing scenarios.
Should I disable rp_filter on a multi-homed server?
Not automatically. First determine whether the routing configuration is correct. If legitimate asymmetric routing is intentional, loose mode may be appropriate depending on the architecture.
How do I check rp_filter for all interfaces?
Use:
sysctl -a 2>/dev/null | grep '\.rp_filter'
How can I test the reverse route?
If a packet arrives from:
203.0.113.50
run:
ip route get 203.0.113.50
Then compare the selected path with the interface on which the packet arrived.
Can policy routing fix an rp_filter problem?
Sometimes the real problem is incorrect reverse-path routing. Source-based policy routing can make routing consistent with a multi-interface architecture rather than weakening filtering to accommodate incorrect routes.
Is rp_filter a firewall?
No. It is an IPv4 source-validation mechanism associated with routing information. Firewall frameworks such as nftables provide separate packet-filtering capabilities.
Is rp_filter the same as arp_filter?
No. rp_filter deals with IP reverse-path validation. arp_filter controls aspects of ARP response behavior.
Why does tcpdump see packets when my application doesn’t?
Packet capture can observe traffic at a point before some later processing decisions. Therefore, seeing an incoming packet proves that it reached the host/interface, but it does not by itself prove that it reached the application socket.
Conclusion
Linux rp_filter is not simply an obscure sysctl that should be disabled whenever a second network interface stops working.
It is a security mechanism designed to validate incoming IPv4 source addresses against the kernel’s routing information.
The key difference is:
rp_filter = 1
↓
Strict reverse-path validation
rp_filter = 2
↓
Loose reverse-path validation
rp_filter = 0
↓
No rp_filter source validation
When a multi-homed Linux server drops legitimate traffic, the correct question is not:
What command disables rp_filter?
It is:
Why does Linux believe the reverse path for this source differs from the path on which the packet arrived?
Answer that with:
ip route
ip rule
ip route show table all
ip route get CLIENT_IP
sysctl -a 2>/dev/null | grep '\.rp_filter'
tcpdump
If Linux selects an incorrect interface, continue with CorgiNetwork’s <a href=”https://corginetwork.com/linux-traffic-uses-wrong-interface/“>Linux Traffic Uses the Wrong Interface</a> guide.
If different NICs require independent gateways, use the <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing Guide</a>.
If the problem occurs before IP routing because the wrong interface answers ARP requests, continue with <a href=”https://corginetwork.com/linux-arp-flux-multiple-nics-same-subnetpolicy-routing/“>Linux ARP Flux: Multiple NICs on the Same Subnet</a>.
Together, these articles create a focused troubleshooting path:
Wrong interface
↓
Policy routing
↓
ARP behavior
↓
Reverse-path filtering
↓
Packet-level verification
That is a much more reliable approach than disabling networking protections until the connection starts working.