Block network access of a process?
With Linux 2.6.24+ (considered experimental until 2.6.29), you can use network namespaces for that. You need to have the 'network namespaces' enabled in your kernel (CONFIG_NET_NS=y
) and util-linux with the unshare
tool.
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 127.0.0.1
connect: Network is unreachable
If your app needs a network interface you can set a new one up:
$ unshare -n -- sh -c 'ip link set dev lo up; ping 127.0.0.1'
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=32 time=0.066 ms
Note that this will create a new, local loopback. That is, the spawned process won't be able to access open ports of the host's 127.0.0.1
.
If you need to gain access to the original networking inside the namespace, you can use nsenter
to enter the other namespace.
The following example runs ping
with network namespace that is used by PID 1 (it is specified through -t 1
):
$ nsenter -n -t 1 -- ping -c4 example.com
PING example.com (93.184.216.119) 56(84) bytes of data.
64 bytes from 93.184.216.119: icmp_seq=1 ttl=50 time=134 ms
64 bytes from 93.184.216.119: icmp_seq=2 ttl=50 time=134 ms
64 bytes from 93.184.216.119: icmp_seq=3 ttl=50 time=134 ms
64 bytes from 93.184.216.119: icmp_seq=4 ttl=50 time=139 ms
--- example.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 134.621/136.028/139.848/2.252 ms
Linux has a feature called network namespaces which allow you to essentially have multiple network stacks on the same machine, and assign one to a program when running it. This is a feature typically used for containers, but you can also use it to accomplish what you want.
The ip netns
subcommands manage it. Creating a new network namespace with no access to anything is easy, it's the default state of a new namespace:
root@host:~# ip netns add jail
Now, if you switch in to that namespace, you can configure it fairly easily. You'll probably want to bring up lo in it, and that's it:
root@host:~# ip netns exec jail /bin/bash
root@host:~# ip addr add 127.0.0.1/8 dev lo
root@host:~# ip link set dev lo up
root@host:~# exit
Now when you want to run your command with no network, you just run it in that jail:
root@host:~# ip netns exec jail su user -c 'ping 8.8.8.8'
connect: Network is unreachable
The network is, as desired, unreachable. (You can do all kinds of interesting things as a separate network stack includes iptables
rules, etc.)
You could use iptables and move that process into a cgroup:
mkdir /sys/fs/cgroup/net_cls/block
echo 42 > /sys/fs/cgroup/net_cls/block/net_cls.classid
iptables -A OUTPUT -m cgroup --cgroup 42 -j DROP
echo [pid] > /sys/fs/cgroup/net_cls/block/tasks