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.
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.
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:
What here in general occurs?
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
- The packets sent by processes with GID killswitch are passed in a network.
- 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.
- Packets on the lo interface are in the same way passed. lo are a loopback-interface on which is located known 127.0.0.1 (localhost). As some applications are used by localhost for communication between processes, it is undesirable to block it.
- 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!
Now everything that remained - it is to start inside the client of OpenVPN by means of sg.
sg killswitch 'ping ya.ru'
In total! From this time at you has to earn the Internet in all other programs.
sg killswitch 'openvpn config.ovpn'
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'
The solution on the basis of cgroups demands iptables v1.6.0, and a kernel with the option CONFIG_NETFILTER_XT_MATCH_CGROUP.
The following commands allow to issue Internet access without VPN Firefox, and then to take away it back:
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 ya.ru cgexec -g net_cls:killswitch sudo openvpn config.ovpn cgexec -g net_cls:killswitch firefox -P my_special_profile_name -no-remote
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 killswitchfrom 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 habrahabr.ru/post/274445/
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: firstname.lastname@example.org.
We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.