Linux – How to use iptables as a per-user whitelist web filter on Linux

iptableslinuxwebfilterwhitelist

I'm trying to use iptables to create a web filter on a local machine that whitelists a list of websites and blacklists everything else on a per-user basis. So one user would have full web access while another would be restricted only to the whitelist.

I am able to block all outgoing web traffic on a per-user basis, but I cannot seem to whitelist certain websites. My current FILTER table is setup as:

Chain INPUT (policy ACCEPT 778 packets, 95768 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 777 packets, 95647 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       176.32.98.166        0.0.0.0/0            owner UID match 1000
    0     0 ACCEPT     all  --  *      *       176.32.103.205       0.0.0.0/0            owner UID match 1000
    0     0 ACCEPT     all  --  *      *       205.251.242.103      0.0.0.0/0            owner UID match 1000
  677 73766 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1000 reject-with icmp-port-unreachable

This was created with the following commands:

sudo iptables -A OUTPUT -s amazon.com -m owner --uid-owner <USERNAME> -j ACCEPT
sudo iptables -A OUTPUT -m owner --uid-owner <USERNAME> -j REJECT

My understanding was that iptables would use the first rule that matches to a packet but it seems that is not the case here. All web traffic is being blocked for the user while being allowed for all other users. Is there another way to set this up?

Best Answer

Okay I figured it out thanks to @MichaelHampton 's question. Whitelisted websites should be added like so:

sudo iptables -A OUTPUT -d amazon.com -m owner --uid-owner <USERNAME> -j ACCEPT

You will also have to open UDP port 53 to allow DNS hosts to resolve:

sudo iptables -A OUTPUT -p udp --dport 53 -m owner --uid-owner <USERNAME> -j ACCEPT

And the final rule should be:

sudo iptables -A OUTPUT -m owner --uid-owner <USERNAME> -j REJECT