1

I have set up an OpenVPN client on my home router. The moment the tunnel goes up, I can no longer ping my router from the internet using its WAN_IP. I would like to allow certain incoming connections (ping, ssh) through the WAN interface while the vpn tunnel is up. I read a little bit about this, and I understand I need source-based routing.

I tried to implement that, but it's not working. Here's what I did:

# ip rule list
0:      from all lookup local 
32765:  from all fwmark 0x1 lookup 128 
32766:  from all lookup main 
32767:  from all lookup default
# ip route list table 128
default via WAN_IP dev vlan2
# iptables -t mangle -nvL PREROUTING
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 CONNMARK   all  --  br0    *       0.0.0.0/0            0.0.0.0/0           CONNMARK restore 
    0     0 CONNMARK   all  --  vlan2  *       0.0.0.0/0            0.0.0.0/0           CONNMARK set 0x1
# iptables -t mangle -nvL OUTPUT
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 CONNMARK   all  --  *      *       0.0.0.0/0            0.0.0.0/0           CONNMARK restore

My thinking was the following. Please correct me if I misunderstood something:

  • When a packet arrives on vlan2 (the WAN iface), PREROUTING:2 sets a connection mark of 0x1
  • The packet has no packet mark at this point (is this right?)
  • The packet has the router as destination, so it will be received. If this was DNATed, the previous point would be crucial because table 128 is missing LAN stuff.
  • A reply packet is locally generated.
  • OUTPUT:1 will set a packet mark of 0x1 using the connection mark on the reply packet
  • PREROUTING:1 would do the same for DNATed connections on LAN (br0)
  • The reply packet with mark 0x1 will be routed using table 128.

Unfortunately this is not working, and I would like to understand why. From a remote server, if I ping the WAN_IP, I don't see any replies. I also turned on ssh remote access on the router, and I cannot open the port from the remote computer with telnet WAN_IP SSH_PORT, so this is not only an icmp issue. How does one debug these issues?

Update: I checked rp_filter and it was set to 1. I tried setting it to 0, and now everything works as expected (2 didn't work either). Since this is an internet facing router, I'm thinking that no RPF might not be a great idea. From the little I understand, when strict RPF runs on the initial packet, the kernel observes the route back to REMOTE_IP is through TUN_IF, while the packet arrived on WAN_IF, so it is dropped. Is this right? I tried MARK set 0x1 && CONNMARK save as mangle PREROUTING, hoping the kernel would see the mark during RPF, but it doesn't.

2 Answers 2

0

I cannot see why you need to use iptables for this. This is a straightforward case of PBR. Set up two routing tables, main setup by OpenVPN and theother which does not involve the VPN, then add the rule

  ip rule from IP.Of.Your.Router table theother

and you are done.

3
  • I suppose you mean WAN_IP? Q1: The router runs dnsmasq, wouldn't this cause DNS traffic to go out through the WAN? What SRC_IP would DNS traffic have, WAN_IP or TUN_IP? Q2: Eventually, I want to allow incoming ssh not just on the router but on my desktop as well (that's why I had PREROUTING:1). Could I do that as well without mangling? Commented Oct 1, 2014 at 15:49
  • @MateiDavid 1) Yes 2) Not if you use WANIP in answer one. 3) TUN_IP 4) Yes, but you will have in any case to use a different port for ssh to your pc. In this case, replies to ssh will apperar to be coming from the LAN, while those from dd-wrt from WAN_IP Commented Oct 1, 2014 at 16:38
  • I don't understand the last part. Clearly the forwarded ssh port will be different. Port forwarding on the router's UI will add a nat rule of the form -i vlan2 -p tcp --dport PC_SSH -j DNAT --to-dest PC_IP:PC_SSH. But how do I route replies back without mangling and marks? If I do ip rule from PC_IP table theother, then all pc traffic would go out on WAN_IF, defeating the purpose of having a vpn tunnel, isn't that right? Commented Oct 1, 2014 at 20:55
0

The problem is that the default gateway gets changed by OpenVPN, and that breaks any connection coming in on the non-VPN interface. Linux will send responses to packets that came in on the real interface out the VPN interface! You need to set up appropriate routes before you start OpenVPN.

What follows works for me. It uses iptables and ip (iproute2). Below, it is assumed that the default gateway interface before OpenVPN is started is "eth0". The idea is to ensure that when a connection to eth0 is made, even if eth0 is not the default gateway interface anymore, response packets for the connection go back on eth0 again.

You could use the same number for the connection mark, firewall mark and routing table. I used distinct numbers to make the diffences between them more apparent.

# set "connection" mark of connection from eth0 when first packet of connection arrives
sudo iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1234

# set "firewall" mark for response packets in connection with our connection mark
sudo iptables -t mangle -A OUTPUT -m connmark --mark 1234 -j MARK --set-mark 4321

# our routing table with eth0 as gateway interface
sudo ip route add default dev eth0 table 3412

# route packets with our firewall mark using our routing table
sudo ip rule add fwmark 4321 table 3412

===

UPDATE:

The above works fine for me on Debian Jessie. But on an older Wheezy system I have just found that I need to add "via" to the routing table entry:

# our routing table with eth0 as gateway interface
sudo ip route add default dev eth0 via 12.345.67.89 table 3412

There "12.345.67.89" must be the original non-VPN gateway.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .