My Iptables script limits which DNS servers can be used and also restricts which user accounts on my Linux server can do lookups.

I don’t see firewall scripts utilising iptables owner matching posted that often so I hope this is a sane way of doing things.. . If I’m taking the time to hand craft each rule then I want my firewall to be as limiting as is possible. Without this malicious users on my system could download files over DNS queries.

Here are the relative excerpts from said bash script in an example (those are google’s dns servers):

SERVER_IP="xx.xx.xx.xx"
DNSSERVER="8.8.4.4 8.8.8.8"
DNSUSERS="root postfix httpd userperson"
IPTABLES=/usr/local/sbin/iptables

### DNS rules
# outgoing requests for these users
for dnsip in $DNSSERVER
  do
   for dnsuser in $DNSUSERS
    do
$IPTABLES -A OUTPUT -p udp -m udp -d $dnsip --dport 53 \
--sport 1024:65535 -s $SERVER_IP -m conntrack \
--ctstate NEW,ESTABLISHED --match owner --uid-owner \
$dnsuser -j ACCEPT -m comment --comment "DNS out for $dnsuser "
     done
   done
# incoming established
for dnsip in $DNSSERVER
  do
$IPTABLES -A INPUT -p udp -m udp -s $dnsip --sport 53 \
--dport 1024:65535 -d $SERVER_IP \
-m conntrack --ctstate ESTABLISHED -j ACCEPT \
-m comment --comment "DNS in "
done
# Deny all other DNS and log the UID
$IPTABLES -A OUTPUT -p udp --sport 53 -j LOG --log-prefix "NO DNS for user " --log-uid
$IPTABLES -A OUTPUT -p tcp --sport 53 -j LOG --log-prefix "NO DNS for user " --log-uid
$IPTABLES -A OUTPUT -p udp --dport 53 -j DROP
$IPTABLES -A OUTPUT -p tcp --dport 53 -j DROP

Note that in order to use this matching feature of iptables you must have “owner” match support enabled under the Core Netfilter Configuration options of your kernel. Also during my testing I found I needed separate rules for tcp and udp for reliability, this may have been the old version of iptables that was with debian?

I created a user account with a UID of 12346 for testing the outgoing blocking rules, here is what shows up in my syslog when that user tries to make a request:

kernel: NO DNS for user IN= OUT=eth0 SRC=X.X.X.X DST=8.8.8.8 LEN=75 TOS=0x00 PREC=0x00 TTL=64 ID=28882 DF PROTO=UDP SPT=44654 DPT=53 LEN=55 UID=12346 GID=12346

Thanks to the –log-uid option you can figure out which users are making the requests. This is another option I don’t see used all that often (I add –log-uidall to all outgoing log+drop type rules).