7

On my ubuntu 16.04 laptop, I'm trying to setup the iptables rules so that internet access is denied to all applications by default, and allowed to only one group called internet. I won't add that group to my own login, but use sudo -g or sg to access internet whenever I want. For example:

sudo -g internet firefox

or

sg internet -c "firefox"

However, this approach isn't working. Following is the iptables rule that I've added:

/sbin/iptables -A OUTPUT -p tcp --dport 80  -m owner --gid-owner internet   -j ACCEPT
/sbin/iptables -A OUTPUT -p tcp --dport 443  -m owner --gid-owner internet   -j ACCEPT
/sbin/iptables -A OUTPUT -p udp --dport 53  -m owner --gid-owner internet   -j ACCEPT

I've tested the above rules, when I remove the owner module, it works perfectly and internet is allowed to all applications. But when I add the owner module and gid-owner filter, no app is able to access the internet (even using the mentioned sg and sudo -g commands).

What am I doing wrong?

7
  • Have you tried adding iptables -A OUTPUT -j LOG to log any dropped packet and compare it with your rule? You may also try using nc or telnet (i.e. "telnet 8.8.8.8 53") to check if it works.
    – user996142
    Jun 27, 2017 at 16:34
  • I've tried both telnet and ping - neither works with the gid filter set, but after removing that, both work. Don't think logging would be of any use as I already know its out right rejecting the packages. Jun 27, 2017 at 17:17
  • Logging may help you to investigate this issue. Your scenario worked for me (I just checked) so I think that logs along with iptables -L may help.
    – user996142
    Jun 27, 2017 at 17:30
  • btw, here is my scenario on virtualbox. I denied for anyone but root, and it works: pastebin.com/TVQTV2gP
    – user996142
    Jun 27, 2017 at 17:33
  • Did you try with ubuntu 16.04? Jun 27, 2017 at 19:13

4 Answers 4

7

Already marked solved, but for the sanity of anyone else running into this issue, I thought I'd elaborate here and explain the actual cause of the problem you discovered. The issue is with iptables. Specifically, it does not handle group ID filtering as us humans expect it to. I'm not sure if it's WAD or a bug. IMHO, it's a bug in the iptables -m owner extension code.

The issue is with the handling of --gid-owner. It appears the iptables extensions code does not filter the group id literally (i.e. is user in this group, yes or no?). It's apparent from the module's behavior that it digs deeper and examines the username settings, and then makes a decision based on primary group membership of the user. That is versus a literal examination of the list of group members (expected by myself and others who've had this problem). This behavior is not documented in any of the relevant man pages.

To wit, Ubuntu's implementation of iptables only examines the primary group of the owner of the current network packet. Let's say you wish to create a split VPN, where a specific user group vpn will have its traffic forced to the VPN interface.

If you were to specify each owner, the --uid-owner parameter under the -m owner extension will work as expected. Then let's say you have multiple usernames that you want to branch, and the user list may change over time. So, you decide it would be more efficient to use group id filtering instead (--gid-owner). You place all your VPN traffic users into a single group called vpn and change the iptables parameter to --gid-owner vpn. As you've seen, in many cases the filter fails to perform as expected. Why?

Only the primary/default group of the owner of the packet will be compared. Therefore, any username you added to your vpn group after the user was created will be in the vpn group as a secondary user, and they won't be branched even though they are a member of the group!

The reason the 'root' user didn't work for you is because its primary/default group is 'root'.

Illustrated Example

Say you have username vpn in primary group vpn and username testdummy in primary group test but testdummy is also a member of the vpn group. To testdummy, vpn is a secondary group.

This iptables rule will mark packets belonging to the vpn user but not the testdummy user, even though instinctively one would think packets from both users would be marked because they both belong to group vpn:

iptables -t mangle -A OUTPUT ! -d 192.168.1.1 -m owner --gid-owner vpn -j MARK --set-mark 0x1

To solve the problem, you will have to create another rule, such as this solution:

iptables -t mangle -A OUTPUT ! -d 192.168.1.1 -m owner --gid-owner vpn -j MARK --set-mark 0x1
iptables -t mangle -A OUTPUT ! -d 192.168.1.1 -m owner --uid-owner testdummy -j MARK --set-mark 0x1
1
5

After much trial and error, I was able to find the answer to my own question. The issue wasn't with iptables or with Ubuntu/Linux version I was using, but rather, the issue was with this third rule:

/sbin/iptables -A OUTPUT -p udp --dport 53  -m owner --gid-owner internet   -j ACCEPT

Since udp/53 port is used for DNS name resolution, background services like dnsmasq could be using them, hence name resolution wasn't happening when I tried to run a program with the internet group as these other services weren't in that group. However, ideally those services should still have had access to the port since they are running under root account (and root can do anything!), but the design of iptables owner module seems not to respect such root privileges.

As soon as I removed the owner module check from this last rule, the internet started working:

/sbin/iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

Edit

Another, not directly linked, but related issue is using the owner module for root group. We are inclined to assign the root group access to the internet (in addition to or instead of the internet group) like this:

/sbin/iptables -A OUTPUT -p tcp --dport 80  -m owner --gid-owner root   -j ACCEPT

However, this doesn't work in practice because a lot many apps don't use the root user to connect to the internet for security reasons. For example, the following command won't work even after doing the above:

sudo apt-get update

That's because apt program internally uses the _apt user to download packages for security reasons.

4
  • 2
    that's why I asked you to telnet to 8.8.8.8 by IP, not by name;)
    – user996142
    Jun 28, 2017 at 0:01
  • 1
    > That's because apt program internally uses the _apt user to download packages for security reasons. I owe you a huge beer! Please tell me how did you find out that?
    – tymik
    Jul 7, 2023 at 15:22
  • @tymik Glad you found this helpful! It has been many years since but from what I recall, it was netstat or similar unix command which gave me the PID of the apt process along with the user that was running it. Jul 7, 2023 at 16:32
  • Thanks! I digged a bit in the meantime and this is in the source code explicitly
    – tymik
    Jul 10, 2023 at 15:24
1

You can use --suppl-groups for this, added in ea6cc2fd. From iptables-extensions(8):

   --suppl-groups
          Causes group(s) specified with --gid-owner to be also checked in
          the supplementary groups of a process.

See also iptables group matching: modifying the primary group of a user

-2
/sbin/iptables -A OUTPUT -p tcp --dport 80  -m owner ! --gid-owner root -j DROP
1
  • welcome to U&L, can you please elaborate your answer ? like meaning of flags, etc ..
    – Archemar
    Dec 19, 2017 at 5:20

You must log in to answer this question.

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