115

Is it possible to block the (outgoing) network access of a single process?

4
  • 7
    How do you intend to identify the process? PID, name, path?
    – Marco
    Commented Mar 24, 2013 at 0:14
  • 1
    What access do you want to block? Some programs use network access via localhost (to the same machine) to do their jobs.
    – vonbrand
    Commented Mar 24, 2013 at 2:13
  • See also LD_PRELOAD or similar to prevent network access, if the process is cooperating. Commented Sep 1, 2013 at 19:50
  • @Marco Using binary path for example that is what windows does exactly!
    – ortagon
    Commented Jul 10 at 10:18

11 Answers 11

120

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
20
  • 10
    unshare -n seems to throw "Operation not permitted" without root privileges, anything I missing about it?
    – baldrs
    Commented Dec 30, 2013 at 21:42
  • 1
    Maybe a stupid question...does this namespace also apply to child processes / called processes of the unshared application?
    – bonanza
    Commented Jan 27, 2015 at 20:50
  • 3
    Yes. It is inherited by all children spawned after switching the namespace. Commented Jan 28, 2015 at 5:00
  • 4
    I looks like any program that I'd like to unshare e.g. with sudo unshare -n inherits the root right. As I need the sudo to call unshare I'm wondering how I can make sure that the called program doesn't have the root rights.
    – bonanza
    Commented May 15, 2015 at 15:25
  • 11
    One liner to restrict process to a user. Just sudo twice: sudo unshare -n sudo -u dude bash -c 'echo Hello, my name is $USER' @ThorSummoner bbs.archlinux.org/viewtopic.php?id=205240 Commented Oct 10, 2017 at 20:33
38

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

1
  • Although I needed sudo ip to execute the ip commands, once I was into bash, I just executed su someuser to get an unprivileged shell for user 'someuser'.
    – sage
    Commented Jun 17, 2017 at 17:20
26

Solution 1: Unshare

Unshare from util-linux package can start an application on a different namesapece without network but this require root firejail's solution do almost exactly the same thing but does not require root

unshare -r -n app-command

Solution 2: Firejail:

Firejail can be used to block network access for an application this does not require root any user can benefit from it

firejail --noprofile --net=none app-command

Solution 3: Systemd

Since Systemd v235 there is also another very easy option:

systemd-run --scope -p IPAddressDeny=any -p IPAddressAllow=localhost app-command

Solution 4: Firewall:

We could use firewalls like Douane or Opensnitch BUT those applications are not 100% efficient or in an early stage of development (have a lot of bugs etc. as of 2019)

Solution 5: Kernel MAC:

Kernel MACs can be used as a firewall most known are Tomoyo, Selinux and Apparmor This solution is the best one when it come to stability and efficiency (firewall solution) but most of time setting this is somehow complicated.

Solution 6: Proxify:

One solution is to proxify the application to a null/fake proxy. We can use tsocks or proxybound. Here is some details about the setup

Solution 7: Iptables:

An other easy solution is iptables, it could be setup to block an application

  1. 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

  2. Create a script in your path and make it executable:
  • Create: nano /home/username/.local/bin/no-internet
  • Executable: chmod 755 /home/username/.local/bin/no-internet
  • Content: #!/bin/bash
                  sg no-internet "$@"

  1. Add iptables rule for dropping network activity for group no-internet:
    • iptables -I OUTPUT 1 -m owner --gid-owner no-internet -j DROP

      Note: Don't forget to make the changes permanent, so it would be applied automatically after reboot. Doing it, depends on your Linux distribution.

   4. Check it, for example on Firefox by running: * `no-internet "firefox"`

   5. 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

   6. Make it permanent

   One way to apply the iptables rule at boot is to add the rule as a service with systemd

cat /usr/lib/systemd/system/nonet.service
[Unit]
Description=Nonet group iptable update
After=network.target
After=xsession.target
After=iptables.service
After=shorewall.service

[Service]
Type=oneshot
RemainAfterExit=true
StandardOutput=journal
ExecStart=/bin/bash /home/user/Scripts/Nonet.iptables.sh
5
  • 2
    This is a seriously excellent guide. Thank you. Although, for me, my no-internet command never seemed to pass the parameter, so I'm using sg no-internet for now. Commented Feb 19, 2019 at 15:16
  • @Zach i updated my answer you may be interested in firejail ;)
    – intika
    Commented Apr 28, 2019 at 18:37
  • Thank you for the comprehensive overview, @intika. Note that unshare can be run without root, e.g., unshare -Un program. Tested in Mint 20.1/Linux 5.4.0-58/util-linux 2.34 and Debian 10.10/Linux 4.19.0-17/util-linux 2.33.1 (the latter required running /usr/sbin/sysctl kernel.unprivileged_userns_clone=1 to enable unprivileged user namespaces).
    – Miles
    Commented Jul 4, 2021 at 19:29
  • @intika thank you for the information! Is there also a solution as Node.js module to be installed if I use sharing hosting and don't have permission to set up any of solutions you described?
    – stckvrw
    Commented Sep 12, 2022 at 15:21
  • @MilesWolbe doing that is generally a bad idea as it makes your kernel exploitable: security.stackexchange.com/questions/209529/…
    – Tcll
    Commented Nov 11, 2023 at 20:17
22

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
2
  • 1
    how to remove the pid out of that tasks file its giving error when i m trying to remove or delete data from that file though i m with root user
    – pkm
    Commented Jul 13, 2017 at 5:15
  • 1
    @pkm to enable networking back, you only need to echo [pid] to /sys/fs/cgroup/net_cls/tasks (no 'block' in path)
    – Grief
    Commented Oct 22, 2018 at 13:17
12

Yes, with customized apparmor profile, i.e

/usr/bin/curl {
    ...

    # block ipv4 acces
    deny network inet,
    # ipv6 
    deny network inet6,
    # raw socket
    deny network raw,

}

But in that way, you will need to generate a list of allowed files to access as well, the whole procedure can be a bit of complicated. And see the help document here

1
  • This would prevent incoming network access as well as outgoing. Commented May 14, 2020 at 19:04
11

You can use firejail sandbox (should work on kernels with seccomp feature).

To use it just do

firejail --noprofile --net=none <path to executable>

--noprofile disables default sandbox --net=none disables networking

I do believe that most distros do provide package already but even if they don't firejail has virtually no dependencies other than build toolchain and namespace/seccomp enabled kernel.

There are some other nice features of firejail that can be shown with firejail --help with regards to networking (such as only providing loopback interface or blocking ip/dns etc) but this should do the job. Also, it doesn't require root.

2
  • This also prevents app from connecting to dbus
    – voldimot
    Commented Dec 16, 2020 at 13:55
  • 1
    To allow dbus, one can use something like this:- firejail --ignore=protocol --protocol=unix vlc
    – voldimot
    Commented Dec 16, 2020 at 14:27
6

You cannot do it with iptables alone. This feature briefly existed, but couldn't be made to work reliably and was abandoned.

If you can run the process as a dedicated user ID, iptables can do it with the owner module:

iptables -A OUTPUT -m owner --uid-owner 1234 -j DROP

See examples in Iptables: matching outgoing traffic with conntrack and owner. Works with strange drops, iptables/pf rule to only allow XY application/user?

If you can run the process in its own container, you can firewall that container independently (even make it completely disconnected from the network).

A security module can filter a process's access to networking features. warl0ck's answer gives an example with AppArmor.

3

You can use seccomp-bpf to block some system calls. For example might want to block the socket system call in order to prevent the process from creating sockets FD.

I wrote an example of this approcah which prevents the socket system call for working using libseccomp. The summary is (without error checking):

scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_arch_add(ctx, SCMP_ARCH_NATIVE);
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(socket), 1, SCMP_CMP(0, SCMP_CMP_EQ, pf));
seccomp_load(ctx);
execvp(argv[1], argv+1);

This does not need root privilegese.

A complete sandbox is much more complex however so you should not use this un order to block non-cooperative/malicious programs.

1
  • Could you give an example of how to use this? Does it require root privileges to work?
    – bonanza
    Commented Mar 18, 2017 at 15:38
2

It depends on what distro you're using but that's a feature usually included in the OS's MAC system. As stated previously Ubuntu or SuSE's AppArmor can do this. If you're using RHEL you can configure SELinux to either allow or deny access to a particular port number based on the executing process's label. This is all I could find after some fast googling but there are probably more in depth resources online if you look harder and it gives you the general idea.

2

Since Systemd v235 there is also another very easy option:

IP Accounting and Access Lists with systemd

TL;DR: systemd now can do per-service IP traffic accounting, as well as access control for IP address ranges.

-3

You could use a command line program called "proxychains" and try one of the following possibilities:

Set it up that it uses...

  • ...a proxy that does not exist? (I do not know if it will run it with an "invalid" proxy)
  • ...a local proxy (like "tinyproxy", "squid", "privoxy",...) that limits access to the internet? (Just use ACLs)

I have not tested it myself so I do not know if it works...

3
  • Posting untested solutions generally isn't a good idea.
    – Twirrim
    Commented Aug 16, 2016 at 18:32
  • 1
    proxychains with a nonexisting proxy (like localhost:1234 or the like) might actually be a solid approach, however
    – phil294
    Commented Oct 6, 2019 at 16:27
  • 1
    @Twirrim, I hate this culture that answers need to be chewed and digested to be acceptable. This is knowledge share. drkhsh is not payed to do op's job. proxychains is a solid approach and unless anybody found it not working, it is stupid to downvote IMO. If you don't want to try it and don't like the answer, leave it unvoted. Downvotes are for wrong and inadequate answers. Commented Jan 11, 2022 at 10:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .