David Madore's WebLog: Linux double network interface µHOWTO

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]

↓Entry #0901 [older| permalink|newer] / ↓Entrée #0901 [précédente| permalien|suivante] ↓

(Wednesday)

Linux double network interface µHOWTO

This took me a while to figure out, so I might as well post it here in case it's of use to anyone. Assume you have two network interfaces, say eth0 and ppp0, with two totally unrelated IP addresses, say 257.42.0.18 for eth0 (yes, I know, 257 is impossible, I'm just choosing this to represent a totally arbitrary address) and 333.64.17.29 for ppp0. You wish to use one interface for certain connections and the other for others (there can be plenty of different reasons for that: maybe one connection is faster but has a stupid firewall so it can't be used always). Now if you can decide which connection goes where in function of the destination host('s IP address or network), then it's easy: just configure your routing tables appropriately. But what happens if you wish, for example, all outbound connections to TCP port 80 to go through eth0 and all others to go through ppp0? We need a little more work there, and a little magic, but thanks to the mutant features of the Linux network stack, using iptables and iproute2, it is possible. Here's a sample of the command lines that might be useful (just a guideline, of course: don't ever copy them blindly, please learn about the programs and understand what each line does), at least if the host is not a router:

# Ordinary route is via ppp0 (this should probably be done as pppd starts):
route add defaut gw 333.64.17.1 dev ppp0
# Routing table 201 (say) is through eth0 (gateway is 257.42.0.1, say):
ip route add 257.42.0.0/24 dev eth0 scope link src 257.42.0.18 table 201
ip route add default via 257.42.0.1 dev eth0 table 201
# Use routing table 201 for marked packets:
ip rule add fwmark 1 table 201
# Now set up iptable rule to mark packets destined for eth0:
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 80 -j MARK --set-mark 1
# Lastly, we need to do some self-masquerading:
iptables -t nat -A POSTROUTING -s 333.64.17.29 -o eth0 -j SNAT --to-source 257.42.0.18

The last line probably deserves extra comments, because it is not at all obvious: it is needed because otherwise an outbound connection from the local host on port 80 will have local address 333.64.17.29 (as it appears on the ordinary routing table) whereas it is sent through the eth0 device, and this can't work (any router down the stream will reject it as not being meant for this route, or at best the return packets will come through the wrong interface).

If you're also trying to open listening (server) sockets on the eth0 interface, you also need something probably like this:

# Turn off entry route verification on incoming packets:
sysctl -w net.ipv4.conf.eth0.rp_filter=0
# Also mark local packets destined for eth0:
iptables -t mangle -A OUTPUT -s 257.42.0.18 -j MARK --set-mark 1

If your box also acts as a router (through some third interface eth1, say), then at the very least you need to duplicate the OUTPUT rules (for the mangle table) as PREROUTING ones and broaden the source address match on the rules that have one, but more complicated are probably desirable (of course, it all depends on what kind of addresses you have on eth1; I'll leave as an exercise for the interested reader the case where eth1 has private addresses and you wish to masquerade on forwarding…).

↑Entry #0901 [older| permalink|newer] / ↑Entrée #0901 [précédente| permalien|suivante] ↑

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]