OpenVPN Port Forwarding – How to Forward Ports Through OpenVPN

iptablesopenvpnport-forwarding

Here's my scenario. I have three hosts.

1) GATEWAY running OpenVPN Server. It has 1 LAN IP (192.168.1.10) and 1 OpenVPN IP (10.8.0.1).

2) LOCAL-CLIENT, a machine within the same LAN as GATEWAY, with 1 LAN IP (192.168.1.12)

3) REMOTE-SERVER, a MySQL server which is a CLIENT of the OpenVPN Server. It has 1 public IP and 1 OpenVPN IP (10.8.0.51).

I want to be able to connect to MySQL on REMOTE-SERVER from LOCAL-CLIENT through the VPN.

So far I've enabled IP forwarding and added a port forward like this:

echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A OUTPUT -p tcp --dport 3306 -j DNAT --to 10.8.0.51

This works from GATEWAY, I can connect to MySQL using 192.168.1.10 as host. But when I try from LOCAL-CLIENT I get a "Connection refused" error (either using MySQL client or telnet to port 3306).

What am I missing here?

BTW, I've also tried forwarding HTTP port to test against the Apache which is also running on REMOTE-SERVER and I get the same results, so it's not a MySQL issue.

More information:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.8.0.2        0.0.0.0         255.255.255.255 UH    0      0        0 tun0
10.8.0.0        10.8.0.2        255.255.255.0   UG    0      0        0 tun0
192.168.1.0     0.0.0.0         255.255.255.0   U     1      0        0 eth1
5.5.0.0         0.0.0.0         255.255.252.0   U     0      0        0 as0t0
5.5.4.0         0.0.0.0         255.255.252.0   U     0      0        0 as0t1
5.5.8.0         0.0.0.0         255.255.252.0   U     0      0        0 as0t2
5.5.12.0        0.0.0.0         255.255.252.0   U     0      0        0 as0t3
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth1

Here's my iptables on GATEWAY (AFAIK, most of the rules are added by OpenVPN server).
This is after applying the changes suggested by @SmallClanger.

iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
AS0_ACCEPT  all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
AS0_ACCEPT  all  --  0.0.0.0/0            0.0.0.0/0           
AS0_IN_PRE  all  --  0.0.0.0/0            0.0.0.0/0           mark match 0x2000000/0x2000000 
AS0_ACCEPT  tcp  --  0.0.0.0/0            192.168.1.10        state NEW tcp dpt:915 
AS0_ACCEPT  tcp  --  0.0.0.0/0            192.168.1.10        state NEW tcp dpt:914 
AS0_ACCEPT  udp  --  0.0.0.0/0            192.168.1.10        state NEW udp dpt:917 
AS0_ACCEPT  udp  --  0.0.0.0/0            192.168.1.10        state NEW udp dpt:916 
AS0_WEBACCEPT  all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
AS0_WEBACCEPT  tcp  --  0.0.0.0/0            192.168.1.10        state NEW tcp dpt:943 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
AS0_ACCEPT  all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
AS0_IN_PRE  all  --  0.0.0.0/0            0.0.0.0/0           mark match 0x2000000/0x2000000 
AS0_OUT_S2C  all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  10.8.0.0/24          0.0.0.0/0           
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-port-unreachable 
ACCEPT     tcp  --  0.0.0.0/0            10.8.0.51           tcp dpt:3306 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
AS0_OUT_LOCAL  all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_ACCEPT (7 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_DNS (2 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            172.20.2.26         
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_IN (4 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            5.5.0.1             
ACCEPT     all  --  0.0.0.0/0            10.8.0.1            
ACCEPT     all  --  0.0.0.0/0            192.168.1.0/24      
AS0_IN_POST  all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_IN_POST (1 references)
target     prot opt source               destination         
AS0_OUT    all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_IN_PRE (2 references)
target     prot opt source               destination         
AS0_DNS    tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:53 
AS0_DNS    udp  --  0.0.0.0/0            0.0.0.0/0           state NEW udp dpt:53 
AS0_IN     all  --  0.0.0.0/0            5.5.0.0/20          
AS0_IN     all  --  0.0.0.0/0            192.168.0.0/16      
AS0_IN     all  --  0.0.0.0/0            172.16.0.0/12       
AS0_IN     all  --  0.0.0.0/0            10.0.0.0/8          
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_OUT (2 references)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_OUT_LOCAL (1 references)
target     prot opt source               destination         
DROP       icmp --  0.0.0.0/0            0.0.0.0/0           icmp type 5 
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_OUT_S2C (1 references)
target     prot opt source               destination         
AS0_OUT    all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_WEBACCEPT (2 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0 

Here's the NAT table

iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
AS0_NAT_PRE_REL_EST  all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
AS0_DPFWD_UDP  udp  --  0.0.0.0/0            192.168.1.10        udp dpt:1194 state NEW 
AS0_DPFWD_TCP  tcp  --  0.0.0.0/0            192.168.1.10        tcp dpt:443 state NEW 
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:3306 to:10.8.0.51 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
AS0_NAT_POST_REL_EST  all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
AS0_NAT_PRE  all  --  0.0.0.0/0            0.0.0.0/0           mark match 0x2000000/0x2000000 
MASQUERADE  all  --  10.8.0.0/24          0.0.0.0/0           

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain AS0_DPFWD_TCP (1 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           to:192.168.1.10:914 
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_DPFWD_UDP (1 references)
target     prot opt source               destination         
DNAT       udp  --  0.0.0.0/0            0.0.0.0/0           to:192.168.1.10:916 
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_NAT (2 references)
target     prot opt source               destination         
SNAT       all  --  0.0.0.0/0            0.0.0.0/0           to:192.168.1.10 
SNAT       all  --  0.0.0.0/0            0.0.0.0/0           to:10.8.0.1 
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_NAT_POST_REL_EST (1 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_NAT_PRE (1 references)
target     prot opt source               destination         
AS0_NAT_TEST  all  --  0.0.0.0/0            5.5.0.0/20          
AS0_NAT_TEST  all  --  0.0.0.0/0            192.168.0.0/16      
AS0_NAT_TEST  all  --  0.0.0.0/0            172.16.0.0/12       
AS0_NAT_TEST  all  --  0.0.0.0/0            10.0.0.0/8          
AS0_NAT    all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_NAT_PRE_REL_EST (1 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           

Chain AS0_NAT_TEST (4 references)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            5.5.0.0/20          
AS0_NAT    all  --  0.0.0.0/0            0.0.0.0/0 

Edit:

Based on @SmallClanger's comments I realized I didn't need to do any port forwarding or NAT. LOCAL-CLIENT is able to connect to REMOTE-SERVER through its VPN's IP. For this, since my VPN Gateway is not the default gateway, I had to add this static route on LOCAL-CLIENT:

ip route add 10.8.0.0/24 via 192.168.1.10 dev eth0

I also had to delete this FORWARD rule on iptables which was preventing LOCAL-CLIENT to connect to any VPN client:

REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable

Best Answer

It's because the OUTPUT chain only acts on packets originating from a local process. (See this useful image here.)

If you replace (or supplement if you still want to connect form the gateway) that rule with:

iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to 10.8.0.51

And, if you haven't already allowed for the traffic:

iptables -t filter -A FORWARD -p tcp -d 10.8.0.51 --dport 3306 -j ACCEPT

Then your connection should go through. Since it's already working form the gateway, you can be sure MySQL is listening correctly and that its server is accepting the connection.

However, I question whether you actually need NAT at all. Routing alone should handle this, with the appropriate FORWARD rule. That routing can be established manually or through the VPN server config, it depends on your requirements. If you want to look at this option, can you add your openvpn server configuration and the output of route -n to your post?

EDIT

To ensure the connection routes back over the VPN, you'll need a route to your LAN from the server. To add this manually on the MySQL Server:

route add -net 192.168.1.0/24 dev tun0 (if tun0 is your VPN client interface).

If it works, it's better to add this to your VPN client config: route 192.168.1.0/24 (This will automatically create the route on connection, regardless of the tunnel interface or the PPP endpoint addresses being used)

A useful debugging tip: tcpdump -i tun0 -qtln port 3306 on the server will show you the mysql traffic going through the VPN adaptors (client or server). You should be able to see where the connection handshaking is going awry.