[CentOS] iptables - Forwarding with port translation thru an OpenVPN tunnel

Mon Oct 19 23:23:27 UTC 2009
Chuck Munro <chuckm at rmtcentral.net>

Thanks to those who responded.  The use of Apache's reverse proxy was
something I would never have though of (it's the mind-numbing cold
medication I'm on, LOL)

However, I did manage to get things rolling thru the tunnel by configuring
strong-end routing at the remote server.  Requests were indeed arriving at
the remote, but because the request's origin IP address was that of the
outside user's browser, the remote server was simply trying to return
responses via its default route, which is not the tunnel.

I *have* to ask ... why is strong-end routing not the default behavior in
Linux?  Anyway ...

Adding 'ip route ....' and 'ip rule ....' commands when establishing the
tunnel did the trick.


On the remote server, here are the commands run in a script launched by
rc.local:
---------------------------

#!/bin/sh

# NOTE: To allow VPNs under OpenVPN, IPv4 Forwarding
# must be enabled in the /etc/sysctl.conf file!

# Enable NAT for the OpenVPN tunnel from the main server:
WAN=eth0        # The primary public IP interface
iptables -t nat -A POSTROUTING -s 172.17.xxx.0/24  -o ${WAN} -j MASQUERADE

# Enable strong-end routing for traffic coming in thru the VPN tunnel:
## Table 200 - In/Out traffic via tun0:
ip route add table 200 172.17.xxx.0/24 via 172.17.xxx.yy dev tun0
ip route add table 200 default via 172.17.xxx.yy dev tun0

## Engage! ...
ip rule add from 172.17.xxx.0/24 lookup 200

service openvpn start

---------------------------

In the example above, xxx.yy is tun0's 'P-t-P' IP address (usually it's inet
IP address minus 1).

  -- and --

On the main server, here are the commands run in a script launched by
rc.local:
---------------------------

#!/bin/sh

# NOTE: To allow VPNs under OpenVPN, IPv4 Forwarding
# must be enabled in the /etc/sysctl.conf file!

# Enable NAT for the OpenVPN tunnels:
WAN=eth0        # the public IP interface
/sbin/iptables -t nat -A POSTROUTING -s 172.17.xxx.0/24  -o ${WAN} -j
MASQUERADE

TunnelRemoteIP="172.17.xxx.zz"   # The inet IP address of the remote server
thru the VPN.

# Force any HTTP/HTTPS requests on eth0:1's secondary IP address
(64.aaa.bbb.ccc)
# to be forwarded to the remote server, with port translation.
# HTTP:
/sbin/iptables -t nat -A PREROUTING -i eth0 -d 64.aaa.bbb.ccc -p tcp --dport
80 -j DNAT --to ${TunnelRemoteIP}:29080
/sbin/iptables -A FORWARD -p tcp -m tcp -i eth0 -o tun0 -d ${TunnelRemoteIP}
--dport 29080 -j ACCEPT
#
# HTTPS:
/sbin/iptables -A PREROUTING -t nat -i eth0 -d 64.aaa.bbb.ccc -p tcp --dport
443 -j DNAT --to ${TunnelRemoteIP}:29443
/sbin/iptables -A FORWARD -p tcp -m tcp -i eth0 -o tun0 -d ${TunnelRemoteIP}
--dport 29443 -j ACCEPT

service openvpn start
sleep 2    # Be polite.

/sbin/iptables -A FORWARD -p tcp -m tcp --dport 80 -j ACCEPT
/sbin/iptables -A FORWARD -p tcp -m tcp --dport 443 -j ACCEPT

---------------------------

Obviously the above iptables entries could simply be added to the recipe in
/etc/sysconfig/iptables, but I chose to put them in this script so that if I
don't want tunnels to be started I don't run the scripts.  There may be
redundant commands in all of this, but at least it works flawlessly for me.
I didn't use any SNAT statements on the rash assumption POSTROUTING does the
same thing.

I hope this may be useful to anyone else out there who encounters this
issue.

Cheers,
Chuck