Like many other people I have a network behind a NAT. The router providing the NAT has a real world routable IP (and a domain name using DynDNS). The router can forward ports to machines inside. So, I installed a VPN server (poptop) on a local machine. My setup:
gateway: 192.168.0.3 vpnserver: 192.168.0.2
I configure poptop to use the following IPs:
#options.pptpd localip 192.168.0.240 remoteip 192.168.0.241-242
As I now connect, from the internet, to the VPN server, I get IP 192.168.0.241 (or 242), and the VPN server itself holds IP 192.168.0.240 on its ppp-device.
The VPN client can now connect to the VPN server, and the other way around. What doesnt work though is:
- VPN client can not connect to other local machines
- VPN client can especially not connect to the local gateway, and thus not access the internet via VPN
What is the problem? The other machines on the network:
- does not know who has IP 192.168.0.241 and can not reply to it directly
- does not have the VPN server (but the gateway) as default gateway
Fixing routing table
One way to fix this is to add a host entry on a local machine. On Linux that would be:
# route add -host 192.168.0.241 gw 192.168.0.2
(route is similar but the details are different in every OS).
Well, this works, but it sucks because you have to do it on every local host. It sucks even more if you have a NAT-machine that you cannot run the route command on, because then you can anyway not access the internet via VPN anyway.
I found a solution I liked better. There is a command called arpspoof. Chances are you dont have it . What it does is that it sends out pings to machine A, pretending it is machine B. That way, machine A will send its packages to you, instead of to machine B. Normally, that is not such a legitimate thing to do.
However, there is another program that you might have on your VPN server; arping. This program does what arpspoof does, but it doesn’t lie if you ask it to. But it doesn’t need to know it lies, does it? I wrote this little script (works on linux – requires bridge-utils – run it on the VPN server):
#!/bin/sh brctl addbr tmpbr ifconfig tmpbr 192.168.0.241 arping -c 1 -U -I eth0 -s 192.168.0.241 192.168.0.3 ifconfig tmpbr down brctl delbr tmpbr
So we bring up a temporary virtual network interface (tmpbr). We assign it the IP we would want other computers to believe us to have. We send an arp-ping through our normal network interface (eth0), but from the IP of the VPN-client, to the default gateway. Then we bring down tmpbr.
Now, our gateway (192.168.0.3) believes the vpn server has IP 192.168.0.241 (which is actually true). And beyond my knowledge, it seems the other computers on the network learn this thing too But they forget quickly if they dont use the information, so you need to run the above script often (like every minute).
You can run the arping command with slightly different switches and still be successful. This worked and made sense to me.
My VPN server happens to run OpenWRT. Both arping and bridge-utils are included by default. If you let the VPN-server be installed on your NAT-router everything is easier. You can also make some things work fairly well setting up a NAT-server on the VPN-server as well, making double NAT to the internet.