Iptables – Except some IPs from rule to not allow internet through openwrt + openvpn when vpn is disconnected

iptablesopenvpnopenwrtpolicy-routingrouting

I have the following working setup on my network:

A. ISP-Router (connected to inet, internal ip 192.168.0.1 ) <—-> B. eth0 – OpenWrt Router (OpenVPN client running) br-lan (bridge eth1 + wlan0, ip 192.168.1.0) <—-> C. Multiple Clients

The idea is that all client connections go through B. B routes everything through the VPN. If the VPN connection breaks down, clients have no internet access anymore. Thus, I prevent clients from exposing themselves in case there is a problem with the vpn connection.

My setup of the OpenWrt router is taken from here: https://blog.ipredator.se/howto/openwrt/configuring-openvpn-on-openwrt.html

Summing it up:

1 relevant devices:

root@OpenWrt:~# ifconfig
br-lan    Link encap:Ethernet  
          inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
eth0      Link encap:Ethernet  
          inet addr:192.168.0.16  Bcast:192.168.0.255  Mask:255.255.255.0
tun0      Link encap:UNSPEC  
          inet addr:10.33.197.41  P-t-P:10.33.197.41  Mask:255.255.0.0

2 relevant Firewall Zones:

config zone
option name 'lan'
option network 'lan'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'REJECT'

config zone
option name 'wan'
option output 'ACCEPT'
option forward 'REJECT'
option network 'wan'
option input 'ACCEPT'

config zone
option name 'vpn'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'
option network 'vpn'

config forwarding
option dest 'vpn'
option src 'lan'

3 routing table looks like this:

root@OpenWrt:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.33.0.1       128.0.0.0       UG    0      0        0 tun0
0.0.0.0         192.168.0.1     0.0.0.0         UG    0      0        0 eth0
10.33.0.0       0.0.0.0         255.255.0.0     U     0      0        0 tun0
46.122.122.89   192.168.0.1     255.255.255.255 UGH   0      0        0 eth0
128.0.0.0       10.33.0.1       128.0.0.0       UG    0      0        0 tun0
192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.0.1     0.0.0.0         255.255.255.255 UH    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br-lan

Everything with this setup works fine so far. However, now I want to bypass the vpn for specific IPs/Hosts. Hence, making them available even when the vpn is disconnected.
My idea was to add a route for these IPs going directly through A (ip rule add …) . This does not work because it seems that i additionally have to adjust my firewall settings as well. Unfortunately, reading about the basics of iptables has not yet made me understand which changes are to be done.

/edit:
Trying around and further researching, I come to think that theoretically there are two solutions. However, I dont know how to make them work:

  1. Keeping the above concept in place I need to:

    • Add MASQUERADE for my wan_zone (I did this)
    • Add FORWARD rules from lan to wan and from wan to lan (I can do this, but then I lose my "vpn-breakdown protection") that are conditional on the IP i want to access (I don't know if and how that works)
  2. Changing the concept and getting rid of iptables and instead using iproute2 and policy based routing (http://www.linupedia.org/opensuse/Policy_Based_Routing)

    • By default route everything only through vpn
    • conditionally route specific IPs through A. directly

However, this seems to be even more complicated, at least for me because I have never used this.

Best Answer

/edit: Ok, I have found a solution which works rather nice for my needs.

I have managed to improve upon the first working idea below. Especially, now I can manage a list of ips to be routed / forwarded directly to A in an external list. I have added the following to /etc/firewall.user

# If connection was established before, accept it (so we dont have to deal with inbound connections)
iptables -A forwarding_rule -m state --state ESTABLISHED,RELATED -j ACCEPT
# Read ips from file
FORWARDIPS=$(egrep -v -E "^#|^$" /etc/forward_ip)

# create new iptables and route table entries for each ip in the file
# allow forward if packet matches destination and route it through "table admin", for which we set a default gateway below 
for ipblock in $FORWARDIPS
do
   iptables -A forwarding_rule -d $ipblock -j ACCEPT -p all
   ip rule add to $ipblock table admin
done
~

root@OpenWrt:~# cat /etc/forward_ip 
54.164.36.0/24
8.31.8.0/22     

I needed to call the following command from another file at startup (I put it into /etc/rc.local):

# Route everything in table admin by default through ISP-Router
ip route add default via 192.168.0.1 dev eth0 table admin  

also edit /etc/iproute2/rt_tables and add the line:

10     admin

/edit, this was my first solution:

I have found a solution. However, it can be improved on greatly. The idea follows my intuition in /edit 1. I enable masquerading for my wan zone and also enable conditional forwarding between my lan and wan zone for a specific destination ip. I can't add more than one "option dest_ip" for the config rule, though. So it would be nice to have what I do in the uci firewall config as a iptables rule which i then add to /etc/firewall.user

I edited /etc/config/firewall and changed config zone & added config rule

config zone
        option input 'ACCEPT'
        option output 'ACCEPT'
        option name 'wan'
        option network 'wan'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'

config rule
        option target 'ACCEPT'
        option src 'lan'
        option dest 'wan'
        option name 'Lan to Wan'
        option proto 'all'
        option dest_ip '54.164.36.190'
        option enabled '0'

I've discarded my idea in /edit 2 after some trying, because there were many unforeseen hurdles. For example without a default gateway from B to A i cannot establish my vpn connection in the first place. Nonetheless, I suppose that it can be done if you have a better understanding of routing then me.