4

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.

user126715
  • 163
  • 1
  • 1
  • 4

4 Answers4

3

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 final DROP 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).

iptables --append OUTPUT --destination 1.2.3.4 --protocol tcp --dport 1723 --jump ACCEPT
iptables --append OUTPUT --destination 1.2.3.4 --protocol gre --jump ACCEPT
mgorven
  • 30,036
  • 7
  • 76
  • 121
2

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:

10.23.11.0/24 dev eth0
default via 10.23.11.1

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):

10.23.11.0/24 dev eth0
1.2.3.4 via 10.23.11.1
default via 10.8.0.1

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:

10.23.11.0/24 dev eth0
1.2.3.4 via 10.23.11.1

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:

auto eth0
iface eth0 inet static
    address 10.23.11.10
    netmask 255.255.255.0
    up ip route add 1.2.3.4 via 10.23.11.1

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.

default via 127.255.255.255

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:

iptables --append OUTPUT --out-interface eth0 --destination 10.23.11.0/24 --jump ACCEPT
iptables --append OUTPUT --out-interface eth0 --destination 1.2.3.4 --protocol tcp --dport 1723 --jump ACCEPT
iptables --append OUTPUT --out-interface eth0 --destination 1.2.3.4 --protocol gre --jump ACCEPT
iptables --append OUTPUT --out-interface eth0 --jump REJECT

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.

iptables --append OUTPUT --out-interface eth0 --destination 8.8.8.8 --protocol udp --dport 53 --jump ACCEPT
mgorven
  • 30,036
  • 7
  • 76
  • 121
  • this approach to routing would be very fragile. A default route can be added very easily automatically or by mistake. Better to have an implicit rule blackholing the ip range. – JamesRyan Jul 02 '12 at 09:01
  • @JamesRyan It doesn't seem possible to add it in addition to the normal default route because it already uses metric 0. It can be added after removing the normal default route to try to prevent it being added though. Edited. – mgorven Jul 02 '12 at 14:03
1

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

JamesRyan
  • 8,138
  • 2
  • 24
  • 36
0

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.

mulaz
  • 10,472
  • 1
  • 30
  • 37