3

The network in quesiton looks basically like this:

                     /----Inet1
                    /
H1---[111.0/24]---GW1---[99.0/24]
                                 \----GW2-----Inet2

Device explaination

  • H1: Host with IP 192.168.111.47
  • GW1: Linux box with IPs 192.168.111.1 and 192.168.99.2, as well as its own route to the internet.
  • GW2: Generic wireless router with IP 192.168.99.1 and its own route to the internet.
  • Inet1 & Inet2: Two possible routes to the internet

In short: H has more than one possible route to the internet.

H is supposed to only access the internet via GW2 when that link is up, so GW1 has some policy based routing special just for H1:

ip rule add from 192.168.111.47 table 991
ip route add default via 192.168.99.1 table 991

While this works as long as GW2 has a direct link to the internet, the problem occurs when that link is down. What then happens is that GW2 forwards the packet back to GW1, which again forwards back to GW2, creating an endless loop of TCP-pingpong. The preferred result would be that the packet was just dropped.

Is there something that can be done with iptables on GW1 to prevent this? Basically, an iptables-friendly version of "If packet comes from GW2, but originated from H1, drop it"

  • Note1: It is preferable not to change anything on GW2.
  • Note2: H1 needs to be able to talk to both GW1 and GW2, and vice versa, but only GW2 should lead to the internet

TLDR; H1 should only be allowed internet access via GW2, but still needs to be able to talk to both GW1 and GW2.

EDIT: The interfaces for GW1 are br0.105 for the '99' network, and br0.111 for the '111' network. The sollution may or may not be obnoxiously simple, but i have not been able to produce the proper iptables syntax myself, so help would be most appreciated.


PS: This is a follow-up question from this question

Jarmund
  • 535
  • 2
  • 6
  • 17
  • 1
    This seems absurdly simple. The rule is "if the source IP address is the IP address assigned to H1 but the packet was received over the interface that links to GW2, drop it". – David Schwartz Oct 12 '12 at 16:38
  • @DavidSchwartz The interface on GW1 is the same for both networks. Unless you count the fact that they're divided into, for example, br0.105:2 because of virtual interfaces and VLANs. – Jarmund Oct 12 '12 at 16:41
  • Ick. Then you may have to match on source hardware address. Yucky. – David Schwartz Oct 12 '12 at 22:50

2 Answers2

3

You really should be fixing your routing on GW2 instead, if by any means possible. If it is not, you can set up a workaround.

Let:

br0.105 = interface at GW1 in the 99.0/24 network facing GW2
<mac-gw2> = the MAC address of GW2's interface in the 99.0/24 network facing GW1
<ip-h1> = IP address of H1 from the 111.0/24 network

Then adding the rule

iptables -A FORWARD -i br0.105 -s <ip-h1> -m mac --mac-source <mac-gw2> -j REJECT

would result in an ICMP destination unreachable message sent to <ip-h1> in the case the packet from <ip-h1> is ever returned from GW2 to GW1. The idea here is to filter by the MAC address since you seem to have several routes to different routers through this interface and you need to differentiate between the originating routers.

You can get the MAC address of GW2 by either looking at its interface configuration, or, if you don't have access to it, by looking at the ARP cache table of GW1 - just run arp -n to see current entries in the cache.

Note that if GW1 is doing NAT for traffic leaving through <int2> then <ip-h1> would need to be the IP address of <int2>, not the one of H1.

As you asked for a way to wildcard the MAC address - there is none, the iptables mac module requires an exact match. But you obviously could script that (quick & dirty, add checks meeting your level of paranoia before putting in production):

#!/bin/bash

# variables
# the IP address of GW2
IP_GW2=192.168.99.1
# the IP address of H1
IP_H1=192.168.111.47
# the configuration file containing GW2's MAC address
CONFIG_MAC_GW2="/etc/default/iptables-mac-gw2"
# the "arping" utility (used to resolve an IP address to a MAC address)
ARPING=/usr/sbin/arping

# include $CONFIG_MAC_GW2, if exists
test -f $CONFIG_MAC_GW2 && source $CONFIG_MAC_GW2
# test if $MAC_GW2 is empty or undefined
if [ ! -n "$MAC_GW2" ]; then
  MAC_GW2=`$ARPING $IP_GW2 -c 1 -r`
  if [ $? == 1 ]; then
     echo \$MAC_GW2 has not been configured and could not be detected using "$ARPING $IP_GW2 -c 1 -r"
     exit 1
  fi
  # write the discovered MAC address into $CONFIG-MAC-GW2 so we don't have 
  # to resolve it on succeeding runs
  echo MAC_GW2=${MAC_GW2} > $CONFIG_MAC_GW2
fi
# [...]
iptables -A FORWARD -i br0.105 -s $IP_H1 -m mac --mac-source $MAC_GW2 -j REJECT
the-wabbit
  • 40,737
  • 13
  • 111
  • 174
  • Thanks for a great reply. I believe this is the way to go, and i'll be testing it tomorrow. And yes, i really wish i could fix the issue on GW2, but unfortunately, that opens a huge can of worms. On a related note: Does iptables support wildcards in MAC addresses? I have ~50 setups exactly like this one, and it'd be nice to just upload the same firewall-script to all of them. (All of the GW2s in these setups are from the same vendor, so it's enough to only match the first half of the MAC) – Jarmund Oct 12 '12 at 18:05
  • @jarmund no, it does not. But you could script it, of course. I've updated my answer with a coding example. – the-wabbit Oct 12 '12 at 21:23
0

Since G1 is a linux box, why not just test G2's external interface with a ping test and change the default route when it isn't responding? And heck, if you do it right you could auto-unfail back up when the pings start working again.

Mark
  • 2,248
  • 12
  • 15