When dealing with multi-homed systems (servers with multiple network interfaces), we often need to control which interface our transfers use. While scp
makes this straightforward with its -oBindAddress
parameter, rsync
presents a more complex scenario.
The --address
option in rsync doesn't actually bind to a local interface - it only specifies which IP address to advertise to the remote server. This explains why your traffic still goes through eth0 despite setting --address=192.168.100.1
.
1. Using SSH as Transport with BindAddress
Since rsync often uses SSH as transport, we can leverage SSH's binding capability:
rsync -e 'ssh -o BindAddress=192.168.100.1' source destination
2. Network Namespace Approach
For more complex scenarios, Linux network namespaces provide isolation:
# Create namespace
ip netns add rsync-ns
# Move interface to namespace
ip link set eth1 netns rsync-ns
# Execute rsync in namespace
ip netns exec rsync-ns rsync [options]
3. Route-based Solution
Add a specific route for your destination:
ip route add [remote-ip] dev eth1 src 192.168.100.1
Always verify your binding works:
tcpdump -i eth1 host [remote-ip] and port 873
When running rsync as a daemon, you can bind to specific interfaces:
rsync --daemon --address=192.168.100.1
This actually works because the daemon mode properly binds to the specified address.
When dealing with multi-homed systems (servers with multiple network interfaces), there are situations where you need to explicitly control which network interface a transfer uses. While scp
provides the convenient -oBindAddress
option, rsync
presents a more complex scenario.
The --address
parameter in rsync doesn't work the same way as scp's binding option. Rsync's --address
only specifies which IP to advertise to the remote server, not which local interface to bind to.
# This won't actually bind to the interface:
rsync --address=192.168.100.1 /local/path user@remote:/remote/path
Method 1: Using SSH as Transport with BindAddress
Since rsync often uses SSH as transport, you can leverage SSH's binding capability:
rsync -e "ssh -o BindAddress=192.168.100.1" /local/path user@remote:/remote/path
Method 2: Network Namespace Approach
For more advanced control, create a network namespace that only sees your desired interface:
# Create namespace
sudo ip netns add rsync-ns
# Move interface to namespace
sudo ip link set eth1 netns rsync-ns
# Execute rsync within namespace
sudo ip netns exec rsync-ns rsync /local/path user@remote:/remote/path
Method 3: Routing Table Manipulation
Add specific routes to force traffic through your desired interface:
# Add route for remote server
sudo ip route add remote.server.ip via 192.168.100.1 dev eth1
# Then run normal rsync
rsync /local/path user@remote:/remote/path
Verify your binding with tcpdump on both interfaces:
# On interface you want to use
sudo tcpdump -i eth1 host remote.server.ip
# On interface you want to avoid
sudo tcpdump -i eth0 host remote.server.ip
For direct rsync connections (not over SSH), create a wrapper:
#!/bin/bash
socat TCP4-LISTEN:873,bind=192.168.100.1,fork TCP4:remote.server.ip:873
Then point rsync to your local wrapper:
rsync --port=873 localhost::module/path /local/destination