How to Force Traffic to Specific Host Through Specific Network Interface in Linux


2 views

When working with multi-homed Linux systems, you might encounter a situation where traffic to a specific host doesn't take the expected network path. Here's a real-world case I recently dealt with:

# Current network configuration
NIC 1: eth0 - 10.0.1.253/8 (Class A)
NIC 2: eth1 - 10.0.1.1/24 (Class C)

# Routing table output
Destination  Gateway   Genmask        Flags Metric Ref Use Iface
10.0.1.0     *         255.255.255.0  U     0      0     0 eth1
link-local   *         255.255.0.0    U     1002   0     0 eth0
10.0.0.0     *         255.0.0.0      U     0      0     0 eth0
default      10.0.0.1  0.0.0.0        UG    0      0     0 eth0

The routing confusion occurs because of the more specific route for 10.0.1.0/24 via eth1. The Linux kernel's routing algorithm prefers more specific routes (longer prefix lengths) over less specific ones, even if both networks match the destination address.

To force traffic to 10.0.1.3 through eth0, we need to add a host-specific route with higher priority. Here's how to do it:

# Add a host route for 10.0.1.3 via eth0
sudo ip route add 10.0.1.3 dev eth0

# Make it persistent across reboots (RHEL/CentOS)
echo "10.0.1.3 dev eth0" | sudo tee -a /etc/sysconfig/network-scripts/route-eth0

# Alternative persistent method (Ubuntu/Debian)
echo "up ip route add 10.0.1.3 dev eth0" | sudo tee -a /etc/network/interfaces

After adding the route, verify it appears in your routing table:

ip route get 10.0.1.3
# Expected output: 10.0.1.3 dev eth0 src 10.0.1.253 uid 0

For more complex scenarios, consider these additional methods:

# Using routing tables with ip rule
sudo ip route add 10.0.1.3 dev eth0 table 100
sudo ip rule add from 10.0.1.253 table 100

# Using source-based routing
sudo ip route add 10.0.1.3 dev eth0 src 10.0.1.253

If you still experience routing issues:

# Check which interface is being used
tcpdump -i eth0 host 10.0.1.3
tcpdump -i eth1 host 10.0.1.3

# Verify ARP resolution
arp -an | grep 10.0.1.3

# Check route metrics
ip -d route show

I recently encountered an interesting routing challenge on a Red Hat Linux system with dual NICs. Here's the setup:

eth0 - 10.0.1.253/8 (Class A)
eth1 - 10.0.1.1/24 (Class C)

The routing table showed:

Destination  Gateway   Genmask        Flags Metric Ref Use Iface
10.0.1.0     *         255.255.255.0  U     0      0     0 eth1
link-local   *         255.255.0.0    U     1002   0     0 eth0
10.0.0.0     *         255.0.0.0      U     0      0     0 eth0
default      10.0.0.1  0.0.0.0        UG    0      0     0 eth0

When trying to reach host 10.0.1.3 (on the same Class A network as eth0), traffic was incorrectly routing through eth1. Disabling eth1 confirmed the issue - traffic would then properly flow through eth0.

The solution is to add an explicit route for this specific host through eth0. Here's the command that worked:

sudo ip route add 10.0.1.3/32 dev eth0

This creates a host-specific route (using /32) that forces all traffic to 10.0.1.3 through eth0.

After adding the route, verify with:

ip route get 10.0.1.3

You should see output indicating the traffic will use eth0.

To make this route persist across reboots, add it to your network configuration. On RHEL systems:

echo "10.0.1.3/32 dev eth0" | sudo tee -a /etc/sysconfig/network-scripts/route-eth0

For more complex scenarios, you might need source-based routing. Here's a basic example:

# Create a new routing table
echo "200 custom" >> /etc/iproute2/rt_tables

# Add a rule to use this table for packets from eth0
ip rule add from 10.0.1.253 lookup custom

# Add route to the custom table
ip route add 10.0.1.3/32 dev eth0 table custom
  • Use tcpdump -i eth0 host 10.0.1.3 to verify traffic flow
  • Check ARP resolution with arp -n
  • Test connectivity with ping -I eth0 10.0.1.3

The issue occurs because the more specific route (eth1's /24) takes precedence over the less specific route (eth0's /8). Linux routing always prefers the most specific matching route.