Linux – OpenVPN bypass on some ports

debianiptableslinuxopenvpnvpn

I have a server running Debian 7 and I would like to connect to a VPN and let all the traffic pass via the VPN except for some ports (SSH, hosted websites, etc).

I've searched for some time now in the Internet, but nothing seems to work as expected.

I'm not an iptables/network expert, so maybe I'm missing something…

Here are my scripts :

Before VPN script

Here is the script started before the VPN, it is used to block all traffic going out/in without passing via the VPN, except for some ports (SSH here).

If I start only this script, it does his job. I can connect to my server via SSH, but all other ports are blocked and the server can't go in the Internet (because the VPN is not launched).

#!/bin/bash

# Flush iptables
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

# Default policy
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# Accept packets through VPN
iptables -A INPUT -i tun+ -j ACCEPT
iptables -A OUTPUT -o tun+ -j ACCEPT

# Accept local connections
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Accept connection to/from VPN servers
iptables -A INPUT -s xxx.xxx.xxx.xxx -j ACCEPT
iptables -A OUTPUT -d xxx.xxx.xxx.xxx -j ACCEPT

# Disable Reverse Path Filtering on all network interfaces
for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
    echo 0 > $i
done

# Open ports on iptable
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT

Route-up OpenVPN script

Here is the script called via the "route-up" OpenVPN's option. This is the script that should make the ports bypass the VPN.

#!/bin/bash

WAN_GATEWAY="xxx.xxx.xxx.xxx"

echo 1 > /proc/sys/net/ipv4/ip_forward

# Delete table 100 and flush all existing rules
ip route flush table 100
ip route flush cache
iptables -t mangle -F PREROUTING

# Table 100 will route all traffic with mark 1 to WAN (no VPN)
ip route add default table 100 via $WAN_GATEWAY dev eth0
ip rule add fwmark 1 table 100
ip route flush cache

# Mark packets on port 22
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 1

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

OpenVPN config file

Here is the OpenVPN client config file.

client
dev tun
proto udp
resolv-retry infinite
nobind
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
persist-key
persist-tun
comp-lzo
verb 3
redirect-gateway def1
user nobody
group nogroup
script-security 2
auth-user-pass /path/to/config/login.conf
route-up /path/to/scripts/vpn_up.sh
remote xxx.xxx.xxx.xxx 443
ca /path/to/config/certs/ch.crt

My problem is that when the VPN goes up, I can't access my server anymore.

What am I doing wrong?

Thanks a lot for your help !

Best Answer

After a little more searching, I've found this thread : https://web.archive.org/web/20170315080843/https://forum.linode.com/viewtopic.php?p=50114&sid=b440414422596bb7dbc96cf7c9ee511f

I've now modified my "route-up" OpenVPN script as follow, and it's finally working ! I've removed all the others messy rules (iptable PREROUTING, MASQUERADE, etc).

Here is my final "route-up" script :

ip route flush table 100
ip route flush cache

ip rule add from x.x.x.x table 100
ip route add table 100 to y.y.y.y/y dev ethX
ip route add table 100 default via z.z.z.z

Where x.x.x.x is my server's public IP, y.y.y.y/y is the subnet of my server's public IP address, ethX is my server's public Ethernet interface, and z.z.z.z is the default gateway.

Hope this may help someone else.

Related Topic