Linux Traffic Uses Wrong Interface: Routing Troubleshooting Guide
Linux Route Looks Correct but Traffic Uses the Wrong Interface: Complete Troubleshooting Guide
A Linux routing table can look completely correct while real traffic still leaves through an unexpected network interface.
You run:
ip route
The default gateway looks right. The destination network exists. Both interfaces are up. There are no obvious configuration errors.
Yet an SSH connection replies through the wrong NIC, curl uses an unexpected source address, packets disappear when a second interface is enabled, or traffic captured with tcpdump proves that Linux is not using the path you expected.
This happens because ip route alone does not describe every decision Linux makes when routing a packet.
Modern Linux networking can involve multiple routing tables, policy-routing rules, source-address selection, route metrics, DHCP routes, VPNs, container networks, reverse-path filtering and asymmetric routing.
This guide provides a systematic way to determine exactly why Linux chooses the wrong interface—and how to fix the underlying configuration instead of randomly deleting routes.
Why Can Linux Use the Wrong Interface When ip route Looks Correct?
Consider this server:
enp1s0
192.168.10.20/24
Gateway: 192.168.10.1
enp2s0
10.20.30.20/24
Gateway: 10.20.30.1
You run:
ip route
and receive:
default via 192.168.10.1 dev enp1s0 metric 100
10.20.30.0/24 dev enp2s0 proto kernel scope link src 10.20.30.20
192.168.10.0/24 dev enp1s0 proto kernel scope link src 192.168.10.20
At first glance, everything appears reasonable.
But suppose an application using 10.20.30.20 attempts to reach an external destination.
Which interface will Linux use?
Looking only at the output above does not necessarily answer the entire question because routing can also depend on the source address and Linux Routing Policy Database.
The ip utility supports both routing-table management and policy-routing rules, while ip route get resolves a route as the kernel sees it rather than simply listing existing entries.
If you need the networking fundamentals behind gateways and route selection first, read CorgiNetwork’s <a href=”https://corginetwork.com/computer-networking-explained/“>Computer Networking Explained</a> and <a href=”https://corginetwork.com/tcp-ip-explained-a-complete-guide-to-tcp-ip-model/“>TCP/IP Explained</a> guides.
The First Mistake: Treating ip route as the Final Answer
Running:
ip route
is an excellent starting point.
It is not always the final diagnostic test.
The command normally shows routes in the main routing table. Linux, however, supports multiple routing tables, and those additional tables become particularly important when policy routing is configured.
Check all tables:
ip route show table all
You may discover something such as:
default via 192.168.10.1 dev enp1s0 table 100
default via 10.20.30.1 dev enp2s0 table 200
that was not obvious from an ordinary:
ip route
command.
This is especially important on multi-homed servers.
CorgiNetwork’s <a href=”https://corginetwork.com/linux-network-tools-guide/“>Linux Network Tools Guide</a> covers the broader collection of Linux commands useful for this type of investigation.
Use ip route get Instead
One of the most valuable Linux routing troubleshooting commands is:
ip route get DESTINATION
For example:
ip route get 8.8.8.8
Possible output:
8.8.8.8 via 192.168.10.1 dev enp1s0 src 192.168.10.20
This tells us several things:
Destination → 8.8.8.8
Gateway → 192.168.10.1
Interface → enp1s0
Source IP → 192.168.10.20
This is significantly more useful than merely seeing two routes in a routing table.
The ip-route manual describes ip route get as resolving a single route and displaying it as the kernel sees it. It can also incorporate properties such as source address, incoming interface, output interface and packet marks.
Reference: <a href=”https://man7.org/linux/man-pages/man8/ip-route.8.html” target=”_blank” rel=”noopener”>Linux ip-route(8) manual</a>.
Test Route Selection with a Specific Source Address
This is where multi-interface troubleshooting becomes more interesting.
Run:
ip route get 8.8.8.8 from 192.168.10.20
Then:
ip route get 8.8.8.8 from 10.20.30.20
Suppose both commands return:
via 192.168.10.1 dev enp1s0
You have found an important clue.
Traffic using the second address is still being routed according to a path that exits through the first interface.
That may be perfectly correct for your architecture.
Or it may be exactly the problem you are trying to solve.
If the desired architecture is:
192.168.10.20
↓
enp1s0
↓
192.168.10.1
and:
10.20.30.20
↓
enp2s0
↓
10.20.30.1
you probably need to inspect the policy-routing design rather than adding random static routes.
CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing Guide</a> explains how to build this architecture persistently on Ubuntu.
Source Address Selection Matters
Administrators often focus entirely on the destination:
Where is the packet going?
But the selected source address can also be critical.
Check the addresses:
ip -br addr
Example:
enp1s0 UP 192.168.10.20/24
enp2s0 UP 10.20.30.20/24
Now ask Linux:
ip route get 8.8.8.8
The output may include:
src 192.168.10.20
That tells you which source address the kernel expects to use for that route.
This becomes particularly important when:
- a service is bound to a specific address;
- firewall rules depend on source IP;
- upstream routers expect a particular subnet;
- policy routing matches source addresses;
- multiple Internet connections exist;
- NAT is involved.
Applications Can Bind to a Specific Interface or Address
Sometimes the routing table is not the real problem.
An application may explicitly bind its traffic to an address or interface.
For example, curl allows testing through a particular local interface/address:
curl --interface 192.168.10.20 https://example.com/
Compare it with:
curl --interface 10.20.30.20 https://example.com/
If the first succeeds and the second fails, you now have evidence that the two source paths behave differently.
Do not immediately conclude that the second NIC itself is broken.
Investigate:
Source selection
↓
Policy rules
↓
Routing table
↓
Gateway
↓
Firewall
↓
Upstream routing
Inspect Linux Policy Routing
Run:
ip rule
A simple system might resemble:
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
But a multi-homed server might contain:
1000: from 192.168.10.20 lookup 100
1100: from 10.20.30.20 lookup 200
Now inspect those tables:
ip route show table 100
and:
ip route show table 200
For example:
Table 100
192.168.10.0/24 dev enp1s0
default via 192.168.10.1 dev enp1s0
while:
Table 200
10.20.30.0/24 dev enp2s0
default via 10.20.30.1 dev enp2s0
This explains a routing decision that might be impossible to understand by looking only at the main table.
The Linux ip manual explicitly exposes rule as the object for managing the routing policy database.
A Practical Policy-Routing Example
Suppose the desired behavior is:
Traffic sourced from 192.168.10.20
↓
Table 100
↓
enp1s0
Traffic sourced from 10.20.30.20
↓
Table 200
↓
enp2s0
The runtime configuration conceptually involves routes such as:
ip route add 192.168.10.0/24 dev enp1s0 table 100
ip route add default via 192.168.10.1 dev enp1s0 table 100
and:
ip route add 10.20.30.0/24 dev enp2s0 table 200
ip route add default via 10.20.30.1 dev enp2s0 table 200
with policies such as:
ip rule add from 192.168.10.20/32 table 100
ip rule add from 10.20.30.20/32 table 200
These commands illustrate the underlying Linux routing concept. Do not blindly execute them on a production machine; persistent configuration should be designed using the networking system that manages your server.
For Ubuntu using Netplan, use the dedicated <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>CorgiNetwork Netplan policy-routing guide</a> instead of relying on temporary runtime commands.
Check Route Metrics
Now consider a simpler situation.
Run:
ip route
and find:
default via 192.168.10.1 dev enp1s0 metric 100
default via 10.20.30.1 dev enp2s0 metric 500
The first route has the lower metric.
If you expected ordinary traffic to use enp2s0, your expectation and the actual route preference do not match.
But be careful:
changing the metric is not automatically the correct solution.
First decide what the architecture should be.
If the requirement is:
Primary connection
+
Backup connection
metrics can be useful.
If the requirement is:
Source A → Gateway A
Source B → Gateway B
you should investigate policy routing.
Check for Multiple Default Routes
Run:
ip route | grep default
You might discover:
default via 192.168.10.1 dev enp1s0 proto static metric 100
default via 10.20.30.1 dev enp2s0 proto dhcp metric 100
This is a major clue.
One route may have been configured manually while another arrived through DHCP.
Before deleting either route, determine where it came from.
Possible sources include:
- Netplan;
- NetworkManager;
- systemd-networkd;
- DHCP;
- cloud-init;
- VPN software;
- virtualization tools.
If DHCP behavior is unfamiliar, CorgiNetwork’s <a href=”https://corginetwork.com/dhcp-explained/“>DHCP Explained</a> guide explains how clients obtain network configuration, including gateway information.
The Classic Problem: Asymmetric Routing
Consider this topology:
Internet
|
+----------+----------+
| |
Gateway A Gateway B
| |
enp1s0 enp2s0
\ /
\ /
Linux Server
A client connects to the address associated with enp2s0.
The request enters:
Client
↓
Gateway B
↓
enp2s0
But the server’s preferred default route points to Gateway A.
The response becomes:
Server
↓
enp1s0
↓
Gateway A
This is asymmetric routing.
Depending on the topology, it can interact badly with:
- stateful firewalls;
- NAT;
- reverse-path filtering;
- provider anti-spoofing;
- upstream routers;
- VPNs.
Symptoms can be particularly confusing:
Ping works
SSH sometimes works
TCP connections hang
One server IP works
Second server IP fails
If a specific TCP service is failing, use CorgiNetwork’s <a href=”https://corginetwork.com/netcat-explained/“>Netcat Explained</a> guide to test the port directly.
For example:
nc -vz SERVER_IP 443
Reverse Path Filtering Can Drop Unexpected Traffic
Linux also provides reverse-path filtering through rp_filter.
Check:
sysctl net.ipv4.conf.all.rp_filter
Then inspect the relevant interfaces:
sysctl net.ipv4.conf.enp1s0.rp_filter
sysctl net.ipv4.conf.enp2s0.rp_filter
The Linux kernel documentation defines the main modes as:
0 → no source validation
1 → strict reverse-path validation
2 → loose reverse-path validation
In strict mode, an incoming packet can fail validation if its incoming interface is not considered the best reverse path. The kernel documentation specifically notes that loose mode is relevant to asymmetric or otherwise complicated routing environments.
Read the authoritative reference at the <a href=”https://docs.kernel.org/networking/ip-sysctl.html” target=”_blank” rel=”noopener”>Linux Kernel IP sysctl documentation</a>.
However, do not immediately run:
sysctl -w net.ipv4.conf.all.rp_filter=0
just because connectivity is broken.
That can mask a routing-design problem and weaken source validation.
First establish:
- which interface receives the packet;
- which reverse path Linux expects;
- whether
rp_filteris actually responsible.
Check the Firewall Before Blaming Routing
Suppose:
ip route get DESTINATION
shows the correct interface.
Packets can still be blocked.
Check UFW:
sudo ufw status verbose
or nftables:
sudo nft list ruleset
A firewall can distinguish between:
Interface
Source IP
Destination IP
Protocol
Port
Connection state
So a service can work through enp1s0 but fail through enp2s0 even when both routes are correct.
See CorgiNetwork’s <a href=”https://corginetwork.com/firewalls-explained/“>Firewalls Explained</a> and <a href=”https://corginetwork.com/network-security-basics/“>Network Security Basics</a> for the filtering and security concepts behind these rules.
DHCP Can Silently Change Your Routing Table
Imagine that everything works after configuration.
Then the DHCP lease renews.
Suddenly:
ip route
contains a new default route.
This can happen because a DHCP-managed interface may receive routing information dynamically.
Look for:
proto dhcp
in the routing table.
Example:
default via 10.20.30.1 dev enp2s0 proto dhcp metric 100
If you were expecting only the manually configured default gateway on enp1s0, you have identified a likely source of the unexpected behavior.
Do not repeatedly delete the route manually.
Fix the component generating it.
VPNs Can Change Route Selection
VPN clients frequently install routes.
Before connecting:
default via 192.168.1.1 dev wlan0
After connecting, you may discover:
0.0.0.0/1 via 10.8.0.1 dev tun0
128.0.0.0/1 via 10.8.0.1 dev tun0
At first glance, the original default route still exists.
Yet most IPv4 destinations now match the two /1 routes because they are more specific than /0.
Traffic therefore goes through:
tun0
instead of the original interface.
This is an excellent example of why:
ip route | grep default
is not sufficient.
Always test the actual destination:
ip route get DESTINATION_IP
Containers Can Add Networking Complexity
Docker and other container platforms commonly create additional interfaces and networks.
For example:
docker0
br-xxxxxxxx
vethxxxx
Inspect:
ip -br link
and:
ip route
Container networking may also involve NAT and firewall rules.
If the problem affects only containers but not the host, separate the investigation into:
Container
↓
Container route
↓
Bridge
↓
Host networking
↓
NAT / firewall
↓
Physical interface
Do not assume the host’s route selection and a container’s network namespace are identical.
Cloud Routing Can Override Your Expectations
Cloud servers add another important layer.
A Linux VM may correctly select:
eth1
but the virtual network may not provide the expected path beyond that interface.
A simplified cloud path is:
Application
↓
Linux routing
↓
Virtual NIC
↓
Cloud subnet
↓
Cloud route table
↓
Security controls
↓
NAT / Internet gateway
Therefore:
ip route get 8.8.8.8
can tell you what Linux intends to do.
It cannot by itself prove that the provider’s virtual network will successfully carry that traffic.
CorgiNetwork’s <a href=”https://corginetwork.com/cloud-networking-explained/“>Cloud Networking Explained</a> provides a deeper explanation of this additional network layer.
Use tcpdump to See the Truth
Eventually, routing troubleshooting should move from configuration to actual packets.
Suppose you expect traffic to leave through enp2s0.
Run:
sudo tcpdump -ni enp2s0 host 203.0.113.20
In another terminal:
sudo tcpdump -ni enp1s0 host 203.0.113.20
Then generate traffic:
curl https://203.0.113.20/
Now observe which interface actually sees the packets.
An even broader capture is:
sudo tcpdump -ni any host 203.0.113.20
This can answer:
Did Linux actually send the packet?
Which interface carried it?
Did a reply return?
Did TCP retransmit?
For deeper packet inspection, see CorgiNetwork’s <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a>.
Example: SYN Leaves the Wrong Interface
Suppose you expect HTTPS traffic through enp2s0.
You run:
curl https://example.com/
and capture:
enp1s0 → SYN → server:443
This proves the problem occurs before the external network.
Linux itself selected enp1s0.
Investigate:
ip route get SERVER_IP
ip rule
ip route show table all
Example: SYN Leaves Correctly but No Reply Returns
You capture:
enp2s0 → SYN → server:443
enp2s0 → SYN → server:443
enp2s0 → SYN → server:443
but receive no SYN-ACK.
Linux appears to be sending through the intended interface.
Now investigate:
- upstream routing;
- gateway;
- NAT;
- cloud security rules;
- remote firewall;
- return path.
The local route may not be the problem.
Example: Reply Arrives but the Connection Still Fails
Suppose tcpdump shows:
SYN →
← SYN-ACK
ACK →
The TCP handshake completed.
If the application still fails, move higher in the stack.
Do not continue modifying routes simply because the application does not work.
This is why CorgiNetwork’s broader <a href=”https://corginetwork.com/tcp-ip-explained-a-complete-guide-to-tcp-ip-model/“>TCP/IP guide</a> is useful: troubleshooting becomes much easier when each test is associated with the layer it actually verifies.
Check Interface Statistics
Packet loss or interface errors can also look like routing problems.
Run:
ip -s link show enp1s0
and:
ip -s link show enp2s0
Look for unusual increases in:
errors
dropped
overruns
You can also use:
ethtool -S enp2s0
when supported by the driver.
If Linux selects the correct route and sends through the correct interface but the NIC or link is dropping traffic, changing routing policies will not solve the problem.
Check the Neighbor Table
When the gateway is on the local Ethernet network, Linux must resolve its Layer-2 neighbor information.
Run:
ip neigh
You might see:
192.168.10.1 dev enp1s0 lladdr 00:11:22:33:44:55 REACHABLE
But problematic states may include:
FAILED
or prolonged:
INCOMPLETE
If the gateway cannot be resolved at Layer 2, having a correct default route will not make the gateway reachable.
This is another reason a routing table can look perfect while traffic still fails.
A Complete End-to-End Diagnostic Workflow
When Linux appears to use the wrong interface, use this order.
Step 1 — Identify every interface
ip -br link
Step 2 — Identify every address
ip -br addr
Step 3 — Inspect the main table
ip route
Step 4 — Inspect all tables
ip route show table all
Step 5 — Inspect policy rules
ip rule
Step 6 — Ask the kernel for the actual route
ip route get DESTINATION_IP
Step 7 — Repeat with the expected source
ip route get DESTINATION_IP from SOURCE_IP
Step 8 — Inspect the neighbor
ip neigh
Step 9 — Test basic connectivity
ping -I SOURCE_IP DESTINATION_IP
Step 10 — Test the actual TCP service
nc -vz DESTINATION_IP PORT
Step 11 — Test the application
curl --interface SOURCE_IP https://example.com/
Step 12 — Inspect firewall rules
sudo nft list ruleset
or the firewall framework actually used by the system.
Step 13 — Check reverse-path filtering
sysctl net.ipv4.conf.all.rp_filter
Step 14 — Observe real packets
sudo tcpdump -ni any host DESTINATION_IP
At this point, you should be able to say where the failure occurs, rather than simply saying that “Linux routing is broken.”
Diagnostic Decision Tree
Traffic uses unexpected interface
|
v
ip route get DESTINATION
|
+------+------+
| |
Wrong interface Correct interface
| |
v v
Check: Capture packets
ip rule |
all tables +---+---+
metrics | |
source IP Leaves Doesn't leave
DHCP routes correctly |
VPN routes | v
| | Firewall /
v | local stack
Fix routing v
Does reply return?
|
+-----+-----+
| |
NO YES
| |
upstream / TCP/TLS/
firewall / application
return path
The goal is to progressively narrow the problem.
Common Mistakes
Mistake 1: Deleting the Wrong Default Route
Administrators see two defaults and immediately run:
ip route del default
without identifying which component created the route.
The route may return after:
- reboot;
- DHCP renewal;
- VPN reconnect;
- NetworkManager restart.
Find the configuration source first.
Mistake 2: Adding Static Routes Until the Problem Disappears
This often creates a more complicated routing table without addressing the real issue.
Ask the kernel:
ip route get DESTINATION from SOURCE
before adding anything.
Mistake 3: Disabling rp_filter Immediately
Reverse-path filtering can matter in asymmetric environments, but disabling it globally without evidence is poor troubleshooting.
The kernel documents strict and loose reverse-path validation specifically so administrators can understand the behavior rather than blindly disabling it.
Mistake 4: Looking Only at Default Routes
A more-specific route always deserves attention.
A VPN, for example, may install routes that match a destination more specifically than the visible /0 default.
Mistake 5: Ignoring the Source Address
Routing behavior may differ depending on the source.
Always compare:
ip route get DESTINATION from SOURCE_A
with:
ip route get DESTINATION from SOURCE_B
on multi-homed systems.
Mistake 6: Assuming Ping Proves the Route Is Correct
Ping proves only what that specific ICMP test demonstrates.
Your application may:
- use another source address;
- use IPv6;
- connect to another destination IP;
- use TCP through a firewall;
- be bound to another interface.
Test the real application path.
Frequently Asked Questions
Why does Linux use the wrong network interface?
Common causes include a more-preferred route, policy-routing rule, unexpected source address, DHCP-installed route, VPN route, multiple default gateways or application-specific binding.
How can I see which interface Linux will actually use?
Run:
ip route get DESTINATION_IP
The Linux ip-route documentation states that this resolves the route as the kernel sees it rather than simply displaying the routing-table contents.
How can I test routing from a particular source IP?
Use:
ip route get DESTINATION_IP from SOURCE_IP
This is especially valuable on servers with multiple NICs.
Why is ip route different from ip route get?
ip route displays routing-table entries, while ip route get performs a route lookup for a specific destination and can account for parameters such as the source address.
How do I see every Linux routing table?
Run:
ip route show table all
Linux supports multiple routing tables, particularly for policy-routing configurations.
How do I check policy-routing rules?
Run:
ip rule
Then inspect the tables referenced by the returned rules.
Can DHCP cause Linux to use another interface?
Yes. DHCP can install routes, including a default gateway. Inspect ip route for routes associated with DHCP and identify which network manager generated them.
Can a VPN change the route without replacing my default route?
Yes. A VPN can install more-specific routes that take precedence for particular destination ranges even while the original default route remains visible.
What is asymmetric routing?
It occurs when traffic takes different paths in opposite directions—for example, a request enters through one interface while the response leaves through another.
Can rp_filter cause multi-NIC connectivity problems?
It can matter in asymmetric or complex routing configurations. The Linux kernel documents strict mode as validating whether the incoming interface is the best reverse path and identifies loose mode as relevant to asymmetric or complicated routing.
Conclusion
When Linux traffic uses the wrong interface even though the routing table looks correct, resist the temptation to immediately add or delete routes.
The first question should be:
What route does the Linux kernel actually select for this packet?
Answer it with:
ip route get DESTINATION
Then make the test more specific:
ip route get DESTINATION from SOURCE
If the result is unexpected, inspect:
ip rule
ip route show table all
If the kernel selects the correct route, move to packet-level verification:
sudo tcpdump -ni any host DESTINATION
From there, investigate the gateway, firewall, reverse path, upstream network or application instead of continuing to modify a routing table that may already be correct.
For Ubuntu servers where the real requirement is to make each NIC consistently use its own gateway, continue with CorgiNetwork’s <a href=”https://corginetwork.com/netplan-multiple-default-routes-policy-routing/“>Netplan Multiple Default Routes and Policy Routing Guide</a>. For the diagnostic tools used throughout this process, see the <a href=”https://corginetwork.com/linux-network-tools-guide/“>Linux Network Tools Guide</a>, <a href=”https://corginetwork.com/netcat-explained/“>Netcat Explained</a>, and <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a>.