I'm trying to test a network device (firewall) using a Linux box, with two network cards, one interface connected to the WAN zone and another interface to LAN zone.
The configuration is similar with that
|ETH0| <-> | FW | <-> ETH1
So from both interfaces I'm able to ping the respective firewall interface. But i'm not able to fire something like:
ping -I eth0 ip.from.eth1
and to get any answer.
Is that possible or should I use the linux network namespace solution or any user level tcp stacks (VMs are out of question)
Use the network namespace solution. Definitely. It's asking for it.
Trying to do anything else is bound to fail, unless you have the knowledge to mess around with the
local
table and policy routing to make it work. Sending arbitrary crap on an interface is one thing, having the other interface respond the way you want is the real problem here: the kernel will immediately recognize its own IP in thelocal
routing table, which is the first table to be consulted by default (seeip rule
). Note that the man pages say (or used to say) that this table cannot be modified and the rule cannot be changed, but it can be done, but you mileage may vary.So to make it work without namespaces, you need these ugly hacks, which are not guaranteed to work (and which i have not tested):
Move the local table to a higher priority. Note that the man pages says this is not possible.
Note that messing around with this rule is a quick way to break all network connectivity. If the local table isn't present, the kernel won't recognize any of its IP address, so you will not even ping 127.0.0.1.
Create two routing tables for your two interfaces. let's decide that table 10 is for eth0 and 11 eth1. Create a route to the other end.
Now add the rules for these tables. Anything that we send (
iif lo
, as an exception, means 'generated locally') from eth0's IP should use table 10. Make sure that the priority is less than thelookup local
's priority.This should be enough to do what you want to do, at least on an IP level.
Just to understand what happens:
iif lo
fails), then fallback on thelocal
table, which is the one which used to be first in the first place. Thatlocal
table tells us that eth0's IP actually belong to this host, so it can process it.from eth0's_IP iif lo
matches, thetable 10
is consulted, which says to route eth1's IP via eth0. Had our rule not existed, the kernel would have looked up thelocal
table, which says that eth1's IP belongs to this host, so the packet would have gone through the loopback interface instead.Reality is a bit more complicated than that. For example, the kernel is often configured to do reverse path filtering, so it would check, upon receiving the packet from eth0, that if we invert the source and destination address and perform routing, that the resulting packet should be routed via eth0, and if not, then the address are deemed forged and the packet is discarded. This is not a problem if your routes are symmetric, which, fortunately in this case, are. The kernel could also consult the
local
table directly without consulting the policy routing database (ip rule) as an optimization. If it does that at any point while processing the packet, then you are screwed.EDIT: if you are really trying to do this, you might want to activate the sysctl knob "accept_local". This is one case where the kernel looks up the
local
table directly without asking.So really, don't do this. Use the network namespace solution. It's guaranteed to work. Just move one of the interfaces to the other namespace, and configure each namespace like they were two separate hosts talking through that firewall.
The only way I can think of this possibly working is setting static routes to each network that have a lower metric than the default routes in order to get to the other adapter through the firewall. For example (I am on a Windows box though):
Still I'd be surprised if this works, as it seems like the OS would at some level know better than to do this or this just breaking all routing on the box...