How to block internet access to certain programs on Linux
Recently, I have encountered a problem of limiting Internet Access to specific programs. Could anybody recommend a good way of doing that, without using any particular software?
4 Answers 4
The solution for me happened to be straight forward.
- Create, validate new group; add required users to this group:
- Create: groupadd no-internet
- Validate: grep no-internet /etc/group
- Add user: useradd -g no-internet username
Note: If you’re modifying already existing user you should run: usermod -a -G no-internet userName check with : sudo groups userName
- Create: nano /home/username/.local/bin/no-internet
- Executable: chmod 755 /home/username/.local/bin/no-internet
- Content:
- Add iptables rule for dropping network activity for group no-internet:
- iptables -I OUTPUT 1 -m owner —gid-owner no-internet -j DROP
In case you would want to make an exception and allow a program to access local network:
- iptables -A OUTPUT -m owner —gid-owner no-internet -d 192.168.1.0/24 -j ACCEPT
- iptables -A OUTPUT -m owner —gid-owner no-internet -d 127.0.0.0/8 -j ACCEPT
- iptables -A OUTPUT -m owner —gid-owner no-internet -j DROP
NOTE: In case of spawning the rules will be maintained. For example, if you run a program with no-internet rule and that program will open browser window, still the rules will be applied.
A few notes Ilia: Ad 1: — to modify existing user: usermod -a -G groupName userName — check with : sudo groups userName Ad 3: — I already have a lot of rules in iptables, The position of the new rule is crucial. should be the first rule in chain OUTPUT. Therefore I use insert : iptables -I OUTPUT 1 -m owner —gid-owner no-internet -j DROP To allow access to LAN: make sure the ACCEPT rules are above the DENY rule. Works like a charm. Use it for example on Wifiguard. Prog checks wlan for unknown devices, but «phones home» on every start.
The script will only pass the command. If you try launching a programm with parameters, you should use «$@» instead of «$1″. For some reason, I had to temporarily store it in a variable for bash to process it correctly: cmd=»$@»; sg no-internet «$
use «nointernet» instead of «no-internet». For whatever reason Ubuntu 14.04 can’t handle the dash when you try to use sg or chgrp (it prompts for a password, then fails).
I tried it like described but for me, after adding me to «no-internet» and set the ip-tables I cannot connect to the internet anymore (with and without the bash script no-internet).
A more straightforward possibility: use firejail. It runs the application inside sandbox. At the sandbox, you can control the access of the application to any network or folder in your computer.
To execute a certain application without network access do following:
In that case, «The sandbox looks like a computer without any network interfaces.» (See Network Section in documentation)
For example, firejail —net=none firefox will start firefox without any network connection.
Installation
See the Installation documentation. You should install from the package system in your distribution, or better get the latest version LTS. (For example, this latest LTS version, 9.56.2 , works also in Ubuntu 16.04.)
I am getting following warning message: Warning: an existing sandbox was detected. ping will run without any additional sandboxing features
Then, starting a process without network access is as simple as:
unshare -n program .
This creates an empty network namespace for the process. That is, it is run with no network interfaces, including no loopback. In below example we add -r to run the program only after the current effective user and group IDs have been mapped to the superuser ones (avoid sudo):
unshare -r -n ping google.com
nftables can set firewall rules based on cgroups (it can be bound to each program), the syntax:
socket cgroupv2 level NUM PATH
‘PATH’ is the one in /sys/fs/cgroup , note that the ‘PATH’ is relative, so you should exclude /sys/fs/cgroup/ from the absolute path. For example, /sys/fs/cgroup/system.slice/nginx.service is the cgroup for nginx and its ‘PATH’ should be system.slice/nginx.service .
Most systemd services are confined in cgroups. Use systemd-cgls to view the cgroup tree and use systemd-cgls -u XXX.service to get the cgroup for a specific service. For example, systemd-cgls -u nginx.service returns /system.slice/nginx.service .
Note that you should remove the first / , so the ‘PATH’ should be system.slice/nginx.service . If your path contains the symbol ‘@’ please use nft —interactive to set up your firewall rules, other wise, the symbol would be misinterpreted.
Although cgroups will be setup for every systemd unit automatically, you can modify or create systemd unit files to fine tune the cgroup settings if you have special needs. Theoretically, you can set up rules for all programs in a systemd enabled operating system. See systemd.unit(5) and systemd.slice(5) for more information.
Even the most basic systemd unit is attached to a cgroup:
[Unit] Description="My Program" [Service] ExecStart="/usr/bin/my_program"
If your do not use systemd, you can also add program to cgroups manually. See cgroups kernel documentation for more info.
‘NUM’ indicates the level of cgroups that will be matched in the firewall rule. In our previous example, socket cgroupv2 level 2 «system.slice/nginx.service» matches exactly the nginx service. While socket cgroupv2 level 1 «system.slice/nginx.service» matches all the cgroups under «system.slice/», thus not only nginx but other programs in that directory will also be matched, such as «snapd.service».
A very basic example:
To prevent nginx from accessing the Internet (assume you already have a inet table named ‘filter’ and a chain named ‘output’):
nft add rule inet filter output socket cgroupv2 level 2 "system.slice/nginx.service" drop
iptables script to block all internet access except for desired applications
CONTEXT: I wanted to have a shell script that would block all Inbound/Outbound traffic to my computer, UNLESS I decide I want to use the browser or some other application, in which case I would summon it and only those applications would run. I have researched previous scripts made by smart individuals (links to sources at the end), as well as invested the time to learn to use iptables myself (still working on this front). Here is the result of the work done: RESULTS: before the shell script is run, a group called internet is created: sudo groupadd internet Shell Script:
#!/bin/sh #only allow apps run from "internet" group to run # clear previous rules sudo iptables -F # accept packets for internet group sudo iptables -A OUTPUT -p tcp -m owner --gid-owner internet -j ACCEPT sudo iptables -A OUTPUT -p udp -m owner --gid-owner internet -j ACCEPT # also allow local connections sudo iptables -A OUTPUT -p tcp -d 127.0.0.1 -j ACCEPT sudo iptables -A OUTPUT -p tcp -d 192.168.0.1/24 -j ACCEPT # reject packets for other users sudo iptables -A OUTPUT -j REJECT # same process for IPv6: sudo ip6tables -A OUTPUT -p tcp -m owner --gid-owner internet -j ACCEPT sudo ip6tables -A OUTPUT -p udp -m owner --gid-owner internet -j ACCEPT sudo ip6tables -A OUTPUT -p tcp -d 127.0.0.1 -j ACCEPT sudo ip6tables -A OUTPUT -p tcp -d 192.168.0.1/24 -j ACCEPT sudo ip6tables -A OUTPUT -j REJECT
#DROPS ALL INPUT and FORWARD sudo iptables -A INPUT -j DROP sudo iptables -A FORWARD -j DROP #ONLY ACCEPTS INPUT THAT WAS INITIATED BY SOME OUTPUT sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #SAME REPEATED FOR IPv6 sudo ip6tables -A INPUT -j DROP sudo ip6tables -A FORWARD -j DROP sudo ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
after the whole script above is executed, the following command would open a terminal that would be part of the internet group, and hence any application (like firefox for instance) that were open by that terminal would have internet access, while all other INPUT/OUTPUT would be stopped
QUESTION: Is the previous logic in order? Currently I am working on testing out all the features, by installing network monitoring software (nethogs), testing each line of code and seeing if the result is as expected, BUT at the same time, I only started learning about iptables 2 days ago, so even though the sources of the original code is done by experienced coders, I am not 100% confident in my ability to put it all together to produced the desired result. Thanks to anyone who took the time to read all this and participate in the discussion . sources: https://plus.google.com/+TobyKurien/posts/YZhZJCZmGgm https://serverfault.com/questions/429400/iptables-rule-to-allow-all-outbound-locally-originating-traffic P.S.: Thanks to @dirkt for previously helping me understand a lot of the fundamental concepts of iptables as well as answering some of my questions regarding the source code. UPDATE: So after having run the code, there seems to be something wrong. What happens is as follows. I run the shell script:
ip6tables v1.6.0: host/network 127.0.0.1 not found Try `ip6tables -h’ or ‘ip6tables —help’ for more information. ip6tables v1.6.0: host/network 198.168.0.1 not found Try `ip6tables -h’ or ‘ip6tables —help’ for more information.
- Run firefox by manually double-clicking the icon. The result was as expected, right away I got a Server not found error, which was a good sign
- After that I ran the command sudo -g internet -s in the terminal, and then firefox . NOW. when I tried loading a website, it didn’t show me Server not found, but it keep loading for a long period of time, very long. This leads me to believe that maybe the output response was sent, BUT the input was being blocked.
If anyone knows why this might be happening, I would love to know your feedback!
Block internet access and keep LAN access — Firewall
I want to update my firewall, so I want to create my own chain that block the access of the internet but keep accessing the LAN network. How can I do that?
Mmmm.. I would say that this should be done with the firewall from your access point unless you use one computer as a local server to filter the traffic from the connected clients. Could you be more precise? Which firewall do you use? Basically in linux you have iptables that is the command used to create traffic rules.
@Noux Edit your question with ifconfig by issuing in the firewall (assuming you use linux pc for firewall) and let us know, which is WAN and which is LAN interface.
1 Answer 1
Assuming doesn’t matter how many interfaces do you have, you can block all except traffic to and from your LAN network address subnet by using:
iptables -A INPUT -s $NETWORK_ADDRESS/$MASK -j ACCEPT iptables -A INPUT -s $ANOTHER_NETWORK_ADDRESS/$MASK -j ACCEPT iptables -A INPUT -j DROP
iptables -A OUTPUT -d $NETWORK_ADDRESS/$MASK -j ACCEPT iptables -A OUTPUT -d $ANOTHER_NETWORK_ADDRESS/$MASK -j ACCEPT iptables -A OUTPUT -j DROP
You can find the network addresses and the network mask directly connected to your interfaces by typing:
ip r l | grep -v "default" | grep "proto kernel" | awk ''
Replace $NETWORK_ADDRESS/$MASK from the iptables commands with those provided by the ip r l command.
Assuming that you may have a DHCP Server on the LAN, you may want to allow this specific traffic in order to obtain an IP Address from the server.
In order to accomplish that you need to add more rules to IPTABLES:
iptables -I INPUT 1 -p udp --dport 67:68 --sport 67:68 -j ACCEPT
You need to accept incoming and outgoing traffic from your network address space and after that, you can DROP everything else.
The rule for DHCP Client will be inserted above all even if it is executed at the end because of the -I (insert) INPUT «1» . In this way, you make sure that you will get an IP Address from your DHCP Server.