Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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)

share|improve this question
3  
If you have a second computer available, use that. Keep it simple. –  dunxd Sep 28 '12 at 13:47
    
i don't have it. its a test solution that should control how much traffic and how fast the device under test is –  VP. Sep 28 '12 at 13:59
    
What does "try any kind of "network namespace" solution or user level tcp stacks" mean, exactly? –  joeqwerty Sep 28 '12 at 15:34
    
@joeqwerty i just updated my answer –  VP. Sep 28 '12 at 15:57
add comment

2 Answers

up vote 2 down vote accepted

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 the local routing table, which is the first table to be consulted by default (see ip 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):

  1. Move the local table to a higher priority. Note that the man pages says this is not possible.

    ip rule add prio 100 lookup local
    ip rule del prio 0
    

    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.

  2. 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.

    ip route add eth1's ip dev eth0 table 10
    ip route add eth0's ip dev eth1 table 11
    
  3. 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 the lookup local's priority.

    ip rule add from eth0's_ip iif lo lookup 10 prio 10
    ip rule add from eth1's_ip iif lo lookup 11 prio 11
    

This should be enough to do what you want to do, at least on an IP level.

Just to understand what happens:

  • When the kernel receives a icmp echo packet from the eth0 interface from eth1's IP to eth0's IP, it will first lookup the destination address to decide if this destination IP is its own (or, if not, where the packet should be forwarded). So it looks into our two rules, see that they don't match (the packets are not being sent, they are being received, so iif lo fails), then fallback on the local table, which is the one which used to be first in the first place. That local table tells us that eth0's IP actually belong to this host, so it can process it.
  • The kernel generates a response, then proceed to route this response. The response is an icmp echo reply packet that is generated locally, with eth0's IP as the source address and eth1's IP as the destination address. So our rule from eth0's_IP iif lo matches, the table 10 is consulted, which says to route eth1's IP via eth0. Had our rule not existed, the kernel would have looked up the local 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.

share|improve this answer
add comment

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):

ROUTE ADD <eth0 network> MASK <eth0 mask> <eth1 gateway> METRIC <low value> IF <eth1>
ROUTE ADD <eth1 network> MASK <eth1 mask> <eth0 gateway> METRIC <low value> IF <eth0>

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...

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.