[sentinix-list] Creative Netfilter (iptables) rules
Michel Blomgren <[email protected]>
| Newsgroups | gmane.linux.sentinix |
|---|---|
| Message-ID | <[email protected]> |
If someone finds this interesting: here's my rc.firewall script for my router. It's configured to log and drop spoofs, log excessive new connections, log sysflood attempts and drop anything not already connected or related to a connection. It uses -m state and -m limit, and the filter table, the mangle table and the nat table. Michel _______________________________________________ SENTINIX mailing list [email protected] http://elevenprospect.com/mailman/listinfo/sentinix
michels_rc_firewall
(text/plain, 13.1 KB)
#!/bin/sh # # /etc/rc.d/rc.firewall # # Michel's creative Netfilter firewall rules. # Written by Michel Blomgren <[email protected]> # # I use this setup on my gateway (which is a NAT router/firewall). # The box has 2 NICs, one for Inet, one for the private LAN. # # My ISP only provide me with dynamic IPs, so I restart this script in # /etc/dhcpc/dhcpcd.exe when getting a new address. # # # Basic scheme: # # The internal net (eth1) is fully allowed out, without filtering. Anything # coming from 192.168.0.1/24 from the internal network is NATed (masquearded) # to eth0's IP. Traffic coming into eth0 is filtered _before_ any routing takes # place (the PREROUTING chain). All incoming traffic on eth0 is being checked # for source address spoofing, excessive new connections, etc. Anything # suspicious coming in on eth0 is logged by Netfilter using regular printk(), # which is usually taken up by klogd and archived in /var/log/syslog. # ipt=/usr/sbin/iptables [ ! -e $ipt ] && echo "$ipt not found!" && exit 1 echo -n "setting up netfilter (using iptables) . . . " # there should be a better way to do this: eth0ip=`/sbin/ifconfig eth0 | grep -o "inet addr:[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+" | sed "s/inet addr://g"` # flush all chains down the drain.. $ipt -F # delete user-defined chains.. $ipt -X # reset the packet/byte counters.. $ipt -Z # # set up policy defaults for the "filter" table # $ipt -P INPUT DROP $ipt -P FORWARD DROP $ipt -P OUTPUT ACCEPT # # we use the mangle table to capture anything coming in, especially # _before_ NATing anything! # $ipt -t mangle -F $ipt -t mangle -X $ipt -t mangle -Z $ipt -t mangle -P PREROUTING DROP $ipt -t mangle -P POSTROUTING ACCEPT $ipt -t mangle -P OUTPUT ACCEPT # # we use the NAT table to NAT internal traffic going out. # $ipt -t nat -F $ipt -t nat -X $ipt -t nat -Z # # default policies for the NAT table # $ipt -t nat -P PREROUTING ACCEPT $ipt -t nat -P POSTROUTING ACCEPT $ipt -t nat -P OUTPUT ACCEPT # # I have a few user defined rules that are "called" from rules further below. # #$ipt -t mangle -N dummy # create a dummy chain for testing $ipt -t mangle -N antispoof # anti-spoof rules # # basically, we only need source address spoof checking, but I don't trust # my ISP, so I'll do destination address spoofing too. # # I also do logging of any spoof attacks on this box, but only from eth0. # Why not eth1 too? Well... erhhmm... *cough* I do spoof attacks from my box through eth1. ;) # Logging is limited, not every packet is logged, only a few each minute are # logged, that prevents any incoming resource DoS attacks. # # traffic on eth0 from eth0's address to eth0's address, good one, but I don't think so! # I have actually logged some of these, very interesting :^) $ipt -t mangle -A antispoof -i eth0 -s ${eth0ip} -d ${eth0ip} -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcdst_spoof: ' $ipt -t mangle -A antispoof -i eth0 -s ${eth0ip} -d ${eth0ip} -j DROP # traffic on eth0 from localhost? no way... $ipt -t mangle -A antispoof -i eth0 -s 127.0.0.1/8 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 127.0.0.1/8 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 127.0.0.1/8 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 127.0.0.1/8 -j DROP # traffic on eth0 from RFC1918 private (10.) class A net? drop 'em dead... # my ISP's gateway generates HSRP protocol traffic from 10. #$ipt -t mangle -A antispoof -i eth0 -s 10.0.0.0/8 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 10.0.0.0/8 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 10.0.0.0/8 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 10.0.0.0/8 -j DROP # traffic on eth0 from RFC1928 private (172.16 - 172.31) class B net? drop! $ipt -t mangle -A antispoof -i eth0 -s 172.16.0.0/12 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 172.16.0.0/12 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 172.16.0.0/12 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 172.16.0.0/12 -j DROP # drop traffic on eth0 from RFC1918 private (192.168.) class C net... $ipt -t mangle -A antispoof -i eth0 -s 192.168.0.0/16 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 192.168.0.0/16 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 192.168.0.0/16 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 192.168.0.0/16 -j DROP # drop traffic on eth0 from class D multicast... $ipt -t mangle -A antispoof -i eth0 -s 224.0.0.0/4 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 224.0.0.0/4 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 224.0.0.0/4 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 224.0.0.0/4 -j DROP # drop traffic on eth0 from class E 'reserved net'... $ipt -t mangle -A antispoof -i eth0 -s 240.0.0.0/5 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'srcspoof: ' $ipt -t mangle -A antispoof -i eth0 -s 240.0.0.0/5 -j DROP $ipt -t mangle -A antispoof -i eth0 -d 240.0.0.0/5 -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'dstspoof: ' $ipt -t mangle -A antispoof -i eth0 -d 240.0.0.0/5 -j DROP # other spoofed IPs are not dropped or logged (out of very obvious reasons # of course), but that's OK, I don't have any internal addresses of that # nature anyway and I have no trust rules for my own IP range either. # # I have commented out the first -p \! tcp rows, I call these chains using -p # tcp below, so the result is the same. # # attempt to capture synfloods for statistic reasons # # I don't have that much traffic on this box, so I keep quite short timings # here, you may need to increase these a lot or logging itself will be # excessive. $ipt -t mangle -N synflood # $ipt -t mangle -A synflood -p \! tcp -j RETURN $ipt -t mangle -A synflood -p tcp --tcp-flags SYN,ACK,RST,FIN SYN -m limit --limit 10/sec --limit-burst 1 -j RETURN $ipt -t mangle -A synflood -p tcp --tcp-flags SYN,ACK,RST,FIN SYN -m limit --limit 15/min --limit-burst 1 -j LOG --log-prefix 'possible synflood: ' # uncomment to drop synflood attempts, NOT RECOMMENDED! # $ipt -t mangle -A synflood -i eth0 -p tcp --tcp-flags SYN,ACK,RST,FIN SYN -j DROP # capture excessive NEW connection states # see the synflood comment above $ipt -t mangle -N exnew # # not NEW states are skipped # $ipt -t mangle -A exnew -m state --state \! NEW -j RETURN # only 10 new connections per second, otherwise log it $ipt -t mangle -A exnew -m state --state NEW -m limit --limit 10/sec --limit-burst 1 -j RETURN $ipt -t mangle -A exnew -m limit --limit 15/min --limit-burst 1 -j LOG --log-prefix 'excessive NEW: ' # attempt to capture Nmap xmastree packets (FIN, URG, PSH). # Hping2 --xmas and --ymas generates a ECE (or ECNE, ECN-Echo) and CWR # respectively, which we can't match directly, but the Nullscan rule # below will take care of those anyway. :) $ipt -t mangle -N xmas # $ipt -t mangle -A xmas -p \! tcp -j RETURN $ipt -t mangle -A xmas -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'xmastree: ' # capture FIN packets (FIN) $ipt -t mangle -N finscan # $ipt -t mangle -A finscan -p \! tcp -j RETURN $ipt -t mangle -A finscan -p tcp --tcp-flags ALL FIN -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'finscan: ' # attempt to capture NULL scans $ipt -t mangle -N nullscan # $ipt -t mangle -A nullscan -p \! tcp -j RETURN $ipt -t mangle -A nullscan -p tcp --tcp-flags ALL NONE -m limit --limit 30/min --limit-burst 1 -j LOG --log-prefix 'nullscan: ' # create a chain for icmp ECHO request logging, # then do some limiting, only 5 icmp ECHO request (type 8) packets per second, # the others (excessive) we drop. $ipt -t mangle -N icmpchk $ipt -t mangle -A icmpchk -p icmp --icmp-type 8 -m limit --limit 5/sec --limit-burst 1 -j ACCEPT $ipt -t mangle -A icmpchk -p icmp --icmp-type 8 -m limit --limit 15/min --limit-burst 1 -j LOG --log-prefix 'excessive icmp echo: ' $ipt -t mangle -A icmpchk -p icmp --icmp-type 8 -j DROP ################################################################ # the mangle table # # We'll be using the PREROUTING target to capture spoofs and other # mal-traffic. PREROUTING is packets coming in, can be designated to # anywhere, unlike FORWARD. We'll use PREROUTING to detect spoofs and # scans. PREROUTING is checked before INPUT and FORWARD, etc., so we can # use it for both INPUT (traffic coming into the box itself) and FORWARD # (the NAT traffic we need to check, before even NATing it). # # Worth noting: _all_ interfaces go through (naturally) the PREROUTING chain, # including lo, so we need to allow lo through explicitly. # # let packets in to loopback $ipt -t mangle -A PREROUTING -i lo -j ACCEPT # let packets in on eth1 $ipt -t mangle -A PREROUTING -i eth1 -j ACCEPT # the synflood test chain is called first in the PREROUTING chain for incoming traffic on eth0 $ipt -t mangle -A PREROUTING -i eth0 -p tcp -j synflood # log excessive NEW connection states (any protocol but icmp) $ipt -t mangle -A PREROUTING -i eth0 -p \! icmp -m state --state NEW -j exnew # log xmastree packets (Nmap) $ipt -t mangle -A PREROUTING -i eth0 -p tcp -j xmas # log FIN-only packets $ipt -t mangle -A PREROUTING -i eth0 -p tcp -j finscan # log NULL packets (will log nmap -sN, hping2 --xmas and/or --ymas, e.g.) $ipt -t mangle -A PREROUTING -i eth0 -p tcp -j nullscan # log and drop any spoof attempts to and through this box $ipt -t mangle -A PREROUTING -i eth0 -j antispoof # # after spoof filtering, allow all already ESTABLISHED and RELATED traffic through. # $ipt -t mangle -A PREROUTING -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT # icmp: # log and drop excessive ICMP Echo Requests $ipt -t mangle -A PREROUTING -i eth0 -p icmp -j icmpchk # # allow ICMP destination unreachable (type 3) # allow host-unreachable (type 3, code 1) $ipt -t mangle -A PREROUTING -i eth0 -p icmp --icmp-type 3/1 -j ACCEPT # allow port-unreachable (type 3, code 3) $ipt -t mangle -A PREROUTING -i eth0 -p icmp --icmp-type 3/3 -j ACCEPT # fragmentation-needed (type 3, code 4) must be allowed through, or we're not RFC compliant $ipt -t mangle -A PREROUTING -i eth0 -p icmp --icmp-type 3/4 -j ACCEPT # icmp source quench (type 4). bad idea to filter out. $ipt -t mangle -A PREROUTING -i eth0 -p icmp --icmp-type 4 -j ACCEPT # # final check, don't allow any internal addresses in packets coming into eth0 # $ipt -t mangle -A PREROUTING -i eth0 -s \! 192.168.0.0/24 -d \! 192.168.0.0/24 -j ACCEPT # policy kicks in here (DROP) ############################################################################## # INPUT chain - traffic coming in to the box (designated for the box) # # This is in the "filter" table, it could've probably been better to have # what's below in the mangle table above and have the "filter" table all open, # or change the mangle table's PREROUTING policy to ACCEPT. It's all up to you # how to solve it. # # You have to open up any traffic you want in both here _and_ in the mangle # table above! # # trust loopback $ipt -A INPUT -i lo -j ACCEPT # accept already established/related traffic to the box $ipt -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT # only allow incoming traffic on port 53 from the windoze box $ipt -A INPUT -i eth1 -s 192.168.0.203 -p udp --dport 53 -j ACCEPT # drop packets from windoze box, spoofed packets (from the windoze box) # are still allowed through though! $ipt -A INPUT -i eth1 -s 192.168.0.203 -j DROP # otherwise trust whatever eth1 is connected to (backend) $ipt -A INPUT -i eth1 -j ACCEPT # accept all ICMP, it's been filtered in the PREROUTING chain above. $ipt -A INPUT -p icmp -j ACCEPT ## open http #$ipt -A INPUT -p tcp --dport http -j ACCEPT #$ipt -A INPUT -p tcp --dport https -j ACCEPT ## open ftp #$ipt -A INPUT -p tcp --dport ftp -j ACCEPT # policy kicks in here (DROP) ################################################################################################# # NAT from "backend" (eth1) to "frontend" (eth0) # # Allow forwarding between eth1 and eth0, we are light on security here, # since we've already (hopefully) captured any spoofs. We do allow spoofs # coming from the private net though. $ipt -A FORWARD -i eth1 -o eth0 -s 192.168.0.0/24 -j ACCEPT $ipt -A FORWARD -i eth0 -o eth1 -d 192.168.0.0/24 -j ACCEPT # Source NAT altering #$ipt -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j SNAT --to ${eth0ip} # MASQUERADE instead, since I have dynamic IPs. $ipt -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE # # end of NAT # echo "done!"