1

I am trying to share a vpn clients with other nodes on the lan. I have an ubuntu server running a openvpn client on my LAN. The following is my network diagram:

enter image description here

The server is also running some web services which need to be accessible on WAN - when I turn the VPN on, this setup works, but the services are no longer accessible. As per this question, I added the following to my openvpn config:

route-nopull
route 192.168.4.50 255.255.255.255

When I run ip route list:

default via 192.168.4.1 dev enp1s0 proto static metric 100
10.175.0.69 dev tun0 proto kernel scope link src 10.175.0.70
169.254.0.0/16 dev enp1s0 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-616f4053c28b proto kernel scope link src 172.18.0.1
192.168.4.0/24 dev enp1s0 proto kernel scope link src 192.168.4.199 metric 100
192.168.4.50 via 10.175.0.69 dev tun0

With route-nopull, the node has internet access, but not through the VPN

full openvpn config (without the keys):

dev tun
fast-io
persist-key
persist-tun
nobind
remote XXXXXXX 1195
#script-security 2
#up /etc/openvpn/up.sh

remote-random
pull
comp-lzo no
tls-client
verify-x509-name Server name-prefix
ns-cert-type server
key-direction 1
route-method exe
route-delay 2
tun-mtu 1500
fragment 1300
mssfix 1200
verb 3
cipher AES-256-CBC
keysize 256
auth SHA512
sndbuf 524288
rcvbuf 524288
auth-user-pass /etc/openvpn/login

route-nopull
route 192.168.4.50 255.255.255.255

UPDATE: This script is run when the VPN is enabled. In the last 2 lines, I am attempting to allow data on specific ports to bypass the vpn - but this breaks it.

#!/bin/sh
INTIF=enp1s0  # internal interface (your LAN)
EXTIF=tun0    # external interface (WAN via OpenVPN)

#iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE

iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

iptables -A FORWARD -i $EXTIF -o $EXTIF -p tcp --sport 7878 --dport 7878 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $EXTIF -o $EXTIF -p tcp --sport 7878 --dport 7878 -j ACCEPT

1 Answers1

1

First, let's have a look at the options you tried. Your route just tells OpenVPN to add a route to 192.168.4.50/32 via the OpenVPN connection after that connection is established. route-nopull tells OpenVPN to ignore routes it gets from the server. That's why you get

192.168.4.50 via 10.175.0.69 dev tun0

So on the server, any packets to 192.168.4.50 will go through the VPN. Which is not what you want. OTOH,

default via 192.168.4.1 dev enp1s0 proto static metric 100

says to send any packets to the internet (for examples those coming from 192.168.4.0) to the router. And any responses coming from the internet will go via the router directly to the client.

This is why your client gets internet access (outgoing packets get first to the server, then to the router; incoming packets go directly from the router to the client, never seeing the route you set on the server), but not via OpenVPN.


What you really want is to not ignore routes from the server (because those routes, usually for 0.0.0.0/1 and 128.0.0.0/1 to be able to keep the default route) will tell the server to access the internet via the OpenVPN server on the other end. So you need to let OpenVPN set those routes, because the gateway will not be a static IP address.

Once you have those routes, packets coming from the client will go out to the OpenVPN connection just fine.

But what about the answers? The ExpressVPN server at the other end runs in multiple client mode, and assumes that you have a single IP address (your server) it should send packets to. To tell the server that you have a whole subnet behind that address (including the client you need the answers for), you need the --iroute option. Here you can read an explanation why this is needed, and here are the OpenVPN instructions on what exactly to do. As you can see, you need client config directory to set the iroute option.

But you don't control the server, so you can't do that. So routing via OpenVPN is out.


So the whole setup with ExpressVPN only works for a single IP address on your end. But there is a way to pretend you just use this single IP address: Network Address Translation (NAT).

There's plenty of information about NAT on the internet. A very condensed version of what you need is

INTIF=enp1s0  # internal interface (your LAN)
EXTIF=tun0    # external interface (WAN via OpenVPN)

iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE

This rule says that all packets that go out the external OpenVPN interface get "masqueraded" by rewriting the source address to the address on this interface. A connection tracker remembers this, and makes sure the answers get rewritten on the opposite way.

You can additional make sure only outgoing connections (or answers) get forwarded by rules like

iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

assuming the only services exposed to the WAN are on the server.

There are various ways to make this permanent, but your Docker installation complicates this a bit, as Docker usually has lots of iptables rules as well, and you must be careful not to throw them out accidentally. Also, ideally this should only happen when the OpenVPN connection gets established, and should get torn down when it ends, so the best way are probably appropriate scripts set in the OpenVPN configuration file.

Have a look at --up and --down and the other scripts in the OpenVPN documentation.

dirkt
  • 17,461