Developers Club geek daily blog

2 years, 9 months ago
It is known that at connection to open Wi-Fi to networks your traffic can be easily listened. Of course, now more and more websites use HTTPS. Nevertheless, it is yet not 100%. There is a natural desire to secure the traffic at connection to such open Wi-Fi to networks.

Popular solution of this problem — connection through VPN. In that case your traffic is transferred in encrypted form to the VPN server, and already from there goes to the Internet.

Such solution has a small shortcoming: until VPN connection is not set yet, all applications on your computer (including open tabs of the browser) get Internet access bypassing VPN connection.

In this article I will tell how it is possible to avoid it.


How we will solve this problem?

In general, we want to block all access to a network to all applications with two exceptions:
  • To permit access through the network VPN interface.
  • To permit process of OpenVPN Internet access directly that that could set VPN connection.
We will do it by means of iptables.

If the first point is solved very simply, then the second raises questions. It is impossible to write rules which would compare the name of process to iptables.

It is possible to permit in iptables access to strictly prescribed IP VPN servers to all processes (in the assumption that no other connections on this IP are made). This solution is bad the fact that we will not be able to be connected to the server on a hostneyma. Besides, there are problems with captive portal. If any access point demands to come previously on the web page and to click there "Agrees", it is necessary to register an exception somehow manually. Therefore such solution is not ideal.

One of solutions is based on use of groups. iptables is able to compare packets on GID of process which sent these packets. Such solution is very simple and effective. But if some process suddenly wants to change the GID, he will at once lose Internet access.

The second possible option — to use cgroups. We can create special cgroup and place there processes which need free access in the Internet and all packets sent by such processes will be exposed by a tag on which it is possible to matchit them in iptables. The benefit of such approach consists that it is not necessary to change group of process which can be to be used for something. It is only required to assign to net_cls subsystem specific cgroup. Plus, unlike option with normal groups, process can be transferred from one cgroup to another "on the run", without restart. Method shortcomings: more difficult setup, is required recently left iptables v1.6.0 (which did not add to the majority of distribution kits yet).

I will in more detail consider option with normal groups, and at the end of a post in brief I will describe how it can be made with cgroups.


It is supposed that you already have VPN on the basis of OpenVPN and you are able to pass all traffic through it (for example, by means of the option redirect-gateway def1).

Also we will consider that you have rather fresh kernel with CONFIG_NETFILTER_XT_MATCH_OWNER and iptables.

Iptables setup

First of all it is necessary to create special group. Let's call it killswitch.
groupadd --system killswitch

Now we will add the rule iptables:
iptables -A OUTPUT -m owner --gid-owner killswitch -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited
What here in general occurs?
  1. The packets sent by processes with GID killswitch are passed in a network.
  2. Packets on the tun0 interface are passed certainly. It is that network interface which is implemented over VPN connection. If at you this network interface is called in a different way (the option dev in a config of OpenVPN allows to give it the fixed name instead of tunN), change it in the rules iptables above.
  3. Packets on the lo interface are in the same way passed. lo are a loopback-interface on which is located known (localhost). As some applications are used by localhost for communication between processes, it is undesirable to block it.
  4. All other packets are blocked. Blocking at the same time happens to sending an ICMP packet of "administratively prohibited" (the error code does not play an essential role). It is better, than just to flee packets as in that case programs will receive an error at once, but not to hang to a timeout.

If everything goes correctly, on this moment at you Internet access has to be gone.

To start some program with Internet access, it is possible to use the utility of sg (and if to add the user to this group, then it will be possible to cause it without sudo). I will remind that until this group does not become main (effective GID), process will not get Internet access without VPN. iptables does not check supplementary GIDs!
sg killswitch 'ping'
Now everything that remained - it is to start inside the client of OpenVPN by means of sg.
sg killswitch 'openvpn config.ovpn'
In total! From this time at you has to earn the Internet in all other programs.

Bonus: captive portals

What to do if for Internet access it is necessary to visit at first a page in brauzere to click there "agrees" how, for example, in the Moscow subway?

This problem is easily solved. In the same way as the OpenVPN-client is started, it is possible to start also any other application.

So, I on such cases have a special Firefox profile in the eternal private mode. If to start it through sg killswitch, he in the same way will get Internet access without VPN.
sg killswitch 'firefox -P my_special_profile_name -no-remote'

Bonus: cgroups

The solution on the basis of cgroups demands iptables v1.6.0, and a kernel with the option CONFIG_NETFILTER_XT_MATCH_CGROUP.
cgcreate -g net_cls:killswitch # создаем cgroup killswitch с подсистемой net_cls
echo 0x00100001 > /sys/fs/cgroup/net_cls/killswitch/net_cls.classid # настраиваем метку, которая будет присваиваться пакетам (10:1)
chmod 666 /sys/fs/cgroup/net_cls/killswitch/tasks # позволяет всем пользователям запускать процессы в этой cgroup

iptables -A OUTPUT -m cgroup --cgroup 0x00100001  -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited

cgexec -g net_cls:killswitch ping
cgexec -g net_cls:killswitch sudo openvpn config.ovpn
cgexec -g net_cls:killswitch firefox -P my_special_profile_name -no-remote
The following commands allow to issue Internet access without VPN Firefox, and then to take away it back:
pgrep -w firefox | xargs cgclassify -g net_cls:killswitch
pgrep -w firefox | xargs sudo cgclassify -g net_cls:/

Bonus: xtables-addons condition

To stay at home through VPN or at work can not be special need. -m condition --condition killswitch from xtables-addons, added to the last rule iptables (which with REJECT), can make killswitch which is easily switched through echo <0|1> > /proc/net/nf_condition/killswitch.


In article two approaches to implementation of killswitch by means of iptables were considered: through normal groups and through cgroups. Both options work very flexibly, allowing to issue as necessary to any processes Internet access without VPN. Both approaches are almost equivalent, but it is slightly more difficult to configure a method through cgroups, demands very fresh iptables, but allows to issue and take away access directly during process operating time.

This article is a translation of the original post at
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here:

We believe that the knowledge, which is available at the most popular Russian IT blog, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus