In my iptables script I have been experimenting with writing as finely grained rules as possible. I limit which users are allowed to use which services, partly for security and partly as a learning exercise.
Using iptables v220.127.116.11 on Debian 6.0.6 running the 3.6.2 kernel.
However I've hit an issue I don't quite understand yet.. .
outgoing ports for all users
This works perfectly fine. I do not have any generic state tracking rules.
## Outgoing port 81 $IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT $IPTABLES -A INPUT -p tcp --sport 81 -s $MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT
outgoing ports with user matching
## outgoing port 80 for useraccount $IPTABLES -A OUTPUT --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED --sport 1024:65535 -j ACCEPT $IPTABLES -A INPUT -p tcp --sport 80 --dport 1024:65535 -d $MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT
This allows port 80 out only for the account "useraccount", but rules like this for TCP traffic have issues.
## Default outgoing log + block rules $IPTABLES -A OUTPUT -j LOG --log-prefix "BAD OUTGOING " --log-ip-options --log-tcp-options --log-uid $IPTABLES -A OUTPUT -j DROP
The above works, the user "useraccount" can get files perfectly fine. No other users on the system can make outgoing connections to port 80.
useraccount@host:$ wget http://cachefly.cachefly.net/10mb.test
But the wget above leaves x7 dropped entries in my syslog:
Oct 18 02:00:35 xxxx kernel: BAD OUTGOING IN= OUT=eth0 SRC=xx.xx.xx.xx DST=18.104.22.168 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=12170 DF PROTO=TCP SPT=37792 DPT=80 SEQ=164520678 ACK=3997126942 WINDOW=979 RES=0x00 ACK URGP=0
I don't get these drops for similar rules with UDP traffic. I already have rules in place that limit which users can make DNS requests.
The dropped outgoing ACK packets seem to be coming from the root account (URGP=0) which I don't understand. Even when I swap useraccount for root.
I believe that ACK packets are categorised as new because conntrack starts tracking connections after the 3rd step of the 3 way handshake, but why are the being dropped?
Can these drops be safely ignored?
So I often see rules like these, which work fine for me:
$IPTABLES -A OUTPUT -s $MYIP -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT $IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $MYIP -m state --state ESTABLISHED -j ACCEPT
I swapped "-m state --state" for "-m conntrack --ctstate" as state match is apparently obsolete.
Is it best practice to have generic state tracking rules? Are the rules above not considered correct?
For tight control over outgoing users connections would something like this be better?
$IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -p tcp --dport 80 -s $SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT $IPTABLES -A OUTPUT -p tcp --dport 80 -s $SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT