Logo Peer-to-peer VPN

Tutorial: Tunneled Internet Access with NAT

Scenario

Scenario

One node acts as server and shares its access to the Internet with another node which acts as client and directs all its network traffic via the VPN tunnel. The client node might be behind a very restricted or untrusted network and wants to establish a secure tunnel through this network to the server.

Note

Warning: The setup is somewhat complicated and you need to replace some placeholders with the correct values for your environment. If thinks go wrong, the Internet connectivity might be lost (not permanently, a reboot should solve it). I might add some functionality to VpnCloud to setup such scenarios on its own in the future.

To be able to set up the VPN, the gateway node needs be reachable by an unchanging address. A lot of virtual servers on the Internet can be used for this. It is only important that the virtualization does not restrict virtual networks on the server. E.g. KVM works fine, Amazon Web-Services (AWS) works fine, but simple Containers like LXC might cause problems.

Setup

A new network config in /etc/vpncloud has to be created on each node. There is an example file in /etc/vpncloud/example.net.disabled that explains all the parameters.

$> sudo cp /etc/vpncloud/example.net.disabled /etc/vpncloud/mynet.net

Now that file has to edited to change a few values:

$> sudo nano /etc/vpncloud/mynet.net

Here are the full configuration files for the nodes:

Server

device:
  type: tun
ip: 10.76.76.1
claims:
  - 0.0.0.0/0
ifup: >-
  sysctl -w net.ipv4.ip_forward=1 &&
  iptables -t nat -A POSTROUTING -o $(ip route show default | awk '/default/ {print $5}') -j MASQUERADE
crypto:
  password: "my secret key"

Client

device:
  type: tun
peers:
  - SERVER-IP:3210
ip: 10.76.76.2
ifup: >-
  GATEWAY=$(ip route show default | awk '/default/ {print $3}') &&
  ip route add SERVER-IP/32 gw $GATEWAY &&
  echo "$GATEWAY" > /tmp/vpncloud.$IFNAME.old-gateway &&
  ip route del default gw &&
  ip route add default gw 10.76.76.1
ifdown: >-
  ip route del default gw; ip route add default gw $(cat /tmp/vpncloud.$IFNAME.old-gateway)
crypto:
  password: "my secret key"

Note: the placeholder SERVER-IP needs to be substituted. SERVER-IP is the static IP address of your server, a hostname will not work here. Your server needs a static IP address as this command is only run at the startup and changes in IPs like with a DynDNS service will be missed.

Explanation

Ok let's go through this setup. Server and client run VpnCloud and the client connects to the server using the static IP address, nothing special so far.

Since the device type is "tun", all nodes need to claim address ranges. The server and client claim 10.76.76.1 and 10.76.76.2 respectively (via auto claim feature). The subnet 10.76.76.0/24 is chosen to minimize conflicts with existing local networks, you can change it. The server also claims 0.0.0.0/0 which means "everything", so that it can later receive all traffic from the client. Since "/0" is the least specific claim, it will only catch addresses not claimed otherwise.

The server enables IP forwarding, i.e. it will forward packets to their proper destination on the Internet instead of just ignoring anything that is for foreign addresses. Also the server adds an iptables rule to apply NAT masquerading on packets that are forwarded to the Internet. This is where the NAT magic happens: Whenever a packet gets forwarded by IP forward, the server replaces the original source IP and port with its local IP and a random port and stores the relation between original IP and port and replacement port. On each packet it later receives on that chosen port, it will lookup the relation, replace the destination with the original IP and port and then forward the packet to that destination. This happens all in the Linux kernel and is not implemented in VpnCloud.

On the client side, the routing needs to be modified to send all packets via the VPN tunnel instead of via the normal external interface. Therefore the address of the server 10.76.76.1 is configured to be the new default gateway. The only packets that must not be send through the tunnel are the packets of the VpnCloud connection because somehow the traffic needs to reach the server. To guarantee that, an additional routing rule is configured to send packets to the server via the normal external gateway. On tear-down the client restores the original routing settings in the ifdown command. During execution VpnCloud stores the normal gateway IP in a temporary file.

After the config file has been set up correctly, VpnCloud needs to be started:

$> sudo service vpncloud@mynet start

Testing the network

When everything has been setup properly, the connection can be checked using the ping command:

$client> ping 10.76.76.1              # check connection to server
$client> ip route -n                  # verify that the default route "default" is via vpncloud0
$client> ping 8.8.8.8                 # check connection to an external address