I have a server running Linux Mint 12 that I want to keep connected to a PPTP VPN all the time. The VPN server is pretty reliable, but it drops on occasion so I just want to make it so all internet activity is disabled if the VPN connection is broken.
I'd also like to figure out a way to restart it automatically, but that's not as big of an issue since this happens pretty rarely.
I also want to always be able to connect to the box from my lan, regardless of whether the VPN is up or not.
Here's what my ifconfig looks like with the VPN connected properly:
eth0 Link encap:Ethernet HWaddr 00:22:15:21:59:9a
inet addr:192.168.0.171 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::222:15ff:fe21:599a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:37389 errors:0 dropped:0 overruns:0 frame:0
TX packets:29028 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:37781384 (37.7 MB) TX bytes:19281394 (19.2 MB)
Interrupt:41 Base address:0x8000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:1446 errors:0 dropped:0 overruns:0 frame:0
TX packets:1446 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:472178 (472.1 KB) TX bytes:472178 (472.1 KB)
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.10.11.10 P-t-P:10.10.11.9 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:23 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:1368 (1.3 KB) TX bytes:1812 (1.8 KB)
Here's an iptables script I found elsewhere that seemed to be for the problem I'm trying to solve, but it wound up blocking all access, but I'm not sure what I need to change:
#!/bin/bash
#Set variables
IPT=/sbin/iptables
VPN=`ifconfig|perl -nE'/dr:(\S+)/&&say$1'|grep 10.`
LAN=192.168.0.0/24
#Flush rules
$IPT -F
$IPT -X
#Default policies and define chains
$IPT -P OUTPUT DROP
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
#Allow input from LAN and tun0 ONLY
$IPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -i tun0 -m conntrack --ctstate NEW -j ACCEPT
$IPT -A INPUT -s $LAN -m conntrack --ctstate NEW -j ACCEPT
$IPT -A INPUT -j DROP
#Allow output from lo and tun0 ONLY
$IPT -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
$IPT -A OUTPUT -o tun0 -m conntrack --ctstate NEW -j ACCEPT
$IPT -A OUTPUT -d $VPN -m conntrack --ctstate NEW -j ACCEPT
$IPT -A OUTPUT -j DROP
exit 0
Thanks for your help.
Those iptables rules don't allow traffic to the VPN server, so the VPN can't be established. You need the following rules in the
OUTPUT
chain before the finalDROP
rule, where 1.2.3.4 is the IP address of the VPN server. These allow TCP connections to port 1723 (the PPTP control channel) and GRE packets (the data channel).There are two approaches to this, routing based and firewall based.
Routing approach
The typical routing table of a machine not connected to a VPN looks something like this:
The first route is to hosts on the LAN, and the second route sends everything else to the default gateway. When connected to a VPN the routing table looks something like this (where 1.2.3.4 is the VPN server's public IP, and 10.8.0.1 is the VPN server's private IP):
The first route is the same, and the third route is what sends everything over the VPN. Note the second rule however: it says that to reach the VPN server's public IP packets should be sent via the default gateway. This is so that the tunnelled packets created by the VPN client actually reach the server; if this route is not in place the packets created by the VPN client would be sent over the VPN again, and would never get to the server.
Now, if the third route is removed, then packets destined for anywhere on the Internet apart from the VPN server would not have a matching route, and so the host would never send them out. Therefore we want the routing table to look like this when the VPN is not connected:
Hosts on the LAN can still be reached, and the VPN server can still be reached (since we need to be able to start the VPN), but everything else will not be routed out. Getting this setup can be a bit tricky though, especially if you're using DHCP. A static configuration on Debian would involve the following in
/etc/network/interfaces
however:Note that there is no
gateway
statement, since this is what installs the default route.The downside to this approach is that non-VPN traffic to the VPN server is still allowed out unencrypted. If you run other services on the VPN server and need to ensure that they are protected then you'll have to use the firewall approach.
Edit: @JamesRyan suggests that this approach is fragile because a default route could be added automatically or accidentally. Another approach is to add a blackhole route, which sends the traffic somewhere which will not route it any further. This won't work with an automatically added default route however, because it already uses the highest priority metric 0. The default route still needs to be removed, but something like the following can then be added.
Firewall approach
The idea here is to block all outgoing traffic on the physical interface apart from the tunnelled traffic created by the VPN client and traffic destined for the LAN. The traffic to allow for the VPN depends on the protocol being used. PPTP uses TCP port 1723 as a control channel, and GRE as the actual tunnel. OpenVPN uses UDP port 1194. The firewall rules would look something like this:
The first rule accepts traffic for the LAN. The second and third rules accept VPN traffic to the VPN server. The fourth rule rejects all other traffic exiting the physical interface.
The one other thing you may need to accept is DNS if you use a DNS server not on the LAN, because the VPN client probably needs to do a DNS lookup in order to find the VPN server. The following rule inserted before the
REJECT
would allow DNS traffic to Google's public DNS service.Add another default route with a higher metric pointing to a null interface. When the VPN is unavailable the 2nd route will kick in and blackhole the traffic
This is not an iptables queston - you dont need iptables for that.
Just set the default route to go over the VPN, and you're done.
You can also add another default route with a worse metric to use, when the VPN is down.Your LAN is directly connected, so it has priority over the default gateway.