Page 1 of 1

Solution for connecting to VPN server host, using IP namespaces

Posted: Tue Jul 02, 2019 6:02 pm
by riny
If you run SoftEther on a Linux server and set up a local bridge, you'll find that you can connect to any host on your network EXCEPT the VPN server itself. The bridge does not allow connections to the local interface. This is documented (see 3.6.11) but it still results in forum posts (old and new) and issues reported.

The suggested solutions are to (a) add a dedicated physical interface, which is usually impractical; or (b) create a TAP device, but there are no good instructions on how to do this, and personally I wasn't able to get it working.

I do have a solution though, using IP namespaces. This should be supported on any modern Linux variant. The PRO of this approach is that the VPN server runs in its own IP space and you have full control of what traffic goes in and out. The CON is that you don't get direct L2 connectivity to your LAN; your VPN clients get private IP addresses, and all traffic is NATed by the server.

The concepts are explained well in this article. I got a lot of the inspiration from there, and adapted it to work with SoftEther.

To start, you'll need to choose addresses for the VPN's private network. Personally, I use:
  • 10.1.1.0/24: Private network for VPN server and clients
  • 10.1.1.1: Address for the server from inside the private network
  • 10.1.1.2: Address that SoftEther listens on inside the private network
  • 10.1.1.3: Address that SoftEther uses for its own NAT with VPN clients
  • 10.1.1.10-10.1.1.200: DHCP range for VPN clients
Then I use this wrapper script to start SoftEther. This assumes the addresses above, and also assumes that your server's main interface is called eth0. Make sure to update the first iptables line if your main interface is called something else.

Code: Select all

ip netns add vpn
ip link add vpneth0 type veth peer name br-vpneth0
ip link set vpneth0 netns vpn
ip netns exec vpn ip addr add 10.1.1.2/24 dev vpneth0
ip link add name vpnbr type bridge
ip link set vpnbr up
ip link set br-vpneth0 up
ip netns exec vpn ip link set vpneth0 up
ip link set br-vpneth0 master vpnbr
ip addr add 10.1.1.1/24 brd + dev vpnbr
ip netns exec vpn ip route add default via 10.1.1.1

sysctl -qw net.ipv4.ip_forward=1
iptables -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.1.1.2:443
iptables -A POSTROUTING -s 10.1.1.0/24 -j MASQUERADE

ip netns exec vpn vpnserver start
It looks like a lot of steps but here's what's going on here:
  1. Create a new namespace called "vpn"
  2. Create a virtual ethernet pair and move one virtual interface into the vpn namespace
  3. Add an IP address to the virtual interface in the vpn namespace
  4. Create a bridge allowing traffic to flow between the namespaces
  5. Add an IP address to the virtual interface in the root namespace
  6. Add a default route from within the vpn namespace, going out over the bridge
  7. Set up iptables to forward inbound connections on port 443 into the vpn namespace
  8. Set up iptables to do NAT on all outbound connections originating from the vpn namespace
  9. Start SoftEther running inside the vpn namespace
I'm only forwarding port 443, but if you have SoftEther listening on any other ports (5555, etc.) you can add them here.

You can verify that everything is working correctly by looking at the addresses in both namespaces and attempting an external connection from inside the vpn namespace:

Code: Select all

# ip a
# ...
90: br-vpneth0@if91: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vpnbr state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netns vpn
92: vpnbr: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 10.1.1.1/24 brd 10.1.1.255 scope global vpnbr
       valid_lft forever preferred_lft forever

# ip netns exec vpn ip a
# ...
91: vpneth0@if90: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1986 qdisc noqueue state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.1.2/24 scope global vpneth0
       valid_lft forever preferred_lft forever
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link
       valid_lft forever preferred_lft forever

# ip netns exec vpn ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=53 time=17.8 ms
...
At this point you should have the SoftEther server running in its own namespace, and connections to your server on port 443 should be forwarded to SoftEther. The last step is to configure SoftEther. Follow the normal process for this, and when you get to the Local Bridge settings, you'll want to choose "Bridge with Physical Existing Network Adapter" and choose "vpneth0" as your LAN adapter. Bridge this with your virtual hub.

Then in your Virtual Hub setup, go to Virtual NAT and Virtual DHCP Server. Enable SecureNAT and use the following settings:

Code: Select all

Virtual Host's Network Interface Settings:
  IP Address: 10.1.1.3
  Subnet Mask: 255.255.255.0

Virtual DHCP Server Settings:
  Use Virtual DHCP Server Functions: checked
  Distributes IP Addresses: 10.1.1.10 to 10.1.1.200
  Subnet Mask: 255.255.255.0

Options Applied to Clients:
  Default Gateway Address: 10.1.1.1
  DNS Server Address: (set to your desired DNS server)
That's it! Your VPN clients should get addresses in the 10.1.1.10-10.1.1.200 range and have full connectivity to your LAN, including the server SoftEther is running on. You won't be able to connect to 10.1.1.1, but you will be able to connect to your server on its normal LAN IP address.

To shut down SoftEther, use this script to stop the server and clean up:

Code: Select all

ip netns exec vpn vpnserver stop

ip link del vpnbr
ip netns del vpn

Re: Solution for connecting to VPN server host, using IP namespaces

Posted: Wed Jul 03, 2019 5:11 pm
by fenice
Thanks for posting this detailed explanation and that was good research. :) I've recently run into this problem myself, my answer to this was to run two SoftEther servers on my LAN (one was for testing anyway) so if I need to connect to the main VPN server I could always use the test VPN on a different server. That worked well until I was recently out of the country and needed to connect and do some maintenance on the main VPN server, oops, of course I couldn't do that. :( Try the test server, that decided to not work either so the maintenance had to wait a couple of weeks until I returned. I guess I'll be trying your solution in the not-too-distant future.

Thanks again for your post