69

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

  • 6
    How do you intend to identify the process? PID, name, path? – Marco Mar 24 '13 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 Mar 24 '13 at 2:13
  • See also LD_PRELOAD or similar to prevent network access, if the process is cooperating. – Gilles Sep 1 '13 at 19:50

10 Answers 10

75

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
  • 4
    unshare -n seems to throw "Operation not permitted" without root privileges, anything I missing about it? – baldrs Dec 30 '13 at 21:42
  • 1
    Maybe a stupid question...does this namespace also apply to child processes / called processes of the unshared application? – bonanza Jan 27 '15 at 20:50
  • 3
    Yes. It is inherited by all children spawned after switching the namespace. – Michał Górny Jan 28 '15 at 5:00
  • 2
    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 May 15 '15 at 15:25
  • 3
    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 – Jakub Bochenski Oct 10 '17 at 20:33
20

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

  • 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 Jun 17 '17 at 17:20
10

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

10

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
  • 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 Jul 13 '17 at 5:15
  • @pkm to enable networking back, you only need to echo [pid] to /sys/fs/cgroup/net_cls/tasks (no 'block' in path) – Grief Oct 22 '18 at 13:17
7

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.

5

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.

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

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.

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

Solution 1: 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 2: 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 3: 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 command-application

Solution 4: Unshare

Unshare 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 application-comand

Solution 5: 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 6: 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 "$@"

  3. 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
  • 1
    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. – Zach Bloomquist Feb 19 at 15:16
  • @Zach i updated my answer you may be interested in firejail ;) – intika Apr 28 at 18:37
-4

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

  • Posting untested solutions generally isn't a good idea. – Twirrim Aug 16 '16 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.