I wrote a simple blacklisting script with port scan detection.
Requires:
microperl
Recommended to have:
ipt_limit module (unless you want to log EVERY packet)
package includes:
blacklistd.pl - the daemon that reads logread -f output and analyzes it for dropped packets
blacklist.pl - script to read firewall.blacklist_addresses file when the firewall starts
blacklistd_ctl.sh - script to control blacklistd.pl (can be symlinked to /etc/init.d/)
http://lappi.skai.fi/~mikkoko/misc/blac … 1.1.tar.gz
I'm probably going to rewrite it for ash because microperl is quite big for a 2MB writable partition. Also, the logging does not currently seem to work.
Note that the daemon script will think EVERY packet it receives is a dropped one, so log just the dropped packets or use some --log-prefix & grep it (modify blacklistd_ctl.sh if needed). blacklistd.pl contains some settings too if you want to adjust the sensitivity:
#sensitivity settings
my $max_points = 2000; #points needed for host to be blacklisted
my $new_port_points = 200; #points for trying to access an untried port/proto combination
my $old_port_points = 30; #points for trying to access a port/proto combination that was tried already
INSTALL:
blacklist script 0.1.1 quick installation guide - try at your own risk!!
1. Extract the tarball in /tmp/
2. cp /tmp/blacklistd-0.1.1/*blacklist* /etc/
3. cp /tmp/blacklistd-0.1.1/firewall.blacklist-addresses /etc/
4. cp /etc/init.d/S45firewall /etc/firewall.test
5. Make necessary changes to your test firewall.
By default, the blacklist script will use the chain blacklist_check_in for
INPUT checking, blacklist_check_fw for FORWARD checking and blacklist_check_out
for OUTPUT checking. You must set your firewall to FIRST move all packets to the
blacklist_check chains for checking of blacklisted hosts. You also must set
correct logging for the script to work. Check firewall.example for more information.
6. TEST your new firewall setup BEFORE adding it to /etc/init.d, in case you
screw up and can't connect to the router (so you can always just reboot it)
by running /etc/init.d/S45firewall
7. /etc/blacklistd_ctl.sh start
8. Try simulating dropped packets somehow (telnetting to forbidden ports
from WAN etc) - if the script receives a syslog
line, a file should appear to /tmp/blacklistd.data (file name = ip address).
When the host has enough counts, it should be automatically blacklisted with
iptables -A blacklist_check_xx -s IP_ADDR -j blacklist_end, and the IP will
be added to /etc/firewall.blacklist-addresses
9. ln -s /etc/blacklistd_ctl.sh /etc/init.d/S46blacklistd
10. cp /etc/init.d/S45firewall /etc/firewall.old
11. mv /etc/firewall.test /etc/init.d/S45firewallfirewall.example:
#!/bin/sh
## Please make changes in /etc/firewall.user
${FAILSAFE:+exit}
. /etc/functions.sh
WAN=$(nvram get wan_ifname)
LAN=$(nvram get lan_ifname)
echo -n "Loading iptables modules... "
insmod ipt_limit
echo "Flushing tables... "
for T in filter nat mangle; do
iptables -t $T -F
iptables -t $T -X
done
iptables -N u_in
iptables -N u_out
iptables -N u_fw
iptables -t nat -N u_pre
iptables -t nat -N u_post
iptables -N log_warn
iptables -A log_warn -m limit --limit 5/minute -j LOG --log-level warn
#this is where the packets from blacklisted addresses will end to
iptables -N blacklist_end
iptables -F blacklist_end
iptables -A blacklist_end -j DROP
echo "Reading blacklisted addresses from /etc/firewall.blacklist-addresses..."
/etc/blacklist.pl \
--read=/etc/firewall.blacklist-addresses \
--end-chain=blacklist_end\
--check-chain-prefix=blacklist_check_\
--apply
echo -n "INPUT... "
iptables -P INPUT DROP
# checking for blacklisted addresses
iptables -A INPUT -i $WAN -j blacklist_check_in
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i \! $WAN -m state --state INVALID -m limit --limit 5/second -j LOG --log-level crit --log-prefix "invalid-input-lan"
iptables -A INPUT -i $WAN -m state --state INVALID -m limit --limit 5/second -j LOG --log-level crit --log-prefix "invalid-input-wan"
iptables -A INPUT -m state --state INVALID -m limit --limit 5/second -j DROP
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --tcp-flags SYN SYN --tcp-option \! 2 -j DROP
# user rules - should be placed in firewall.user (to keep the firewall more readable)
iptables -A INPUT -j u_in
# allow
iptables -A INPUT -i \! $WAN -j ACCEPT
iptables -A INPUT -j log_warn
iptables -A INPUT -j DROP
echo -n "OUTPUT... "
iptables -P OUTPUT DROP
iptables -A OUTPUT -o lo -j ACCEPT
#everything going out on wan -> checking for blacklisted addresses
iptables -A OUTPUT -o $WAN -j blacklist_check_out
iptables -A OUTPUT -m state --state INVALID -m limit --limit 5/second -j LOG --log-level crit --log-prefix "invalid-output"
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
#user rules
iptables -A OUTPUT -j u_out
# allow
iptables -A OUTPUT -j ACCEPT #allow everything out
echo -n "FORWARD... "
iptables -P FORWARD DROP
#everything coming in from WAN trying to access other networks -> checking for blacklisted addresses
iptables -A FORWARD -i $WAN -j blacklist_check_fw
#wan invalid
iptables -A FORWARD -i $WAN -m state --state INVALID -m limit --limit 5/second -j LOG --log-level crit --log-prefix "invalid-fw-wan"
iptables -A FORWARD -i \! $WAN -m state --state INVALID -m limit --limit 5/second -j LOG --log-level crit --log-prefix "invalid-fw-lan"
iptables -A FORWARD -m state --state INVALID -j DROP
# known connections / return traffic
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
# user rules
iptables -A FORWARD -j u_fw
#trying to access lan from wan
iptables -A FORWARD -i $WAN -o $LAN -m limit --limit 5/second -j LOG --log-level crit --log-prefix "wan-to-lan"
iptables -A FORWARD -i $WAN -o $LAN -j DROP
# allow
iptables -A FORWARD -i br0 -o br0 -j ACCEPT
iptables -A FORWARD -i $LAN -o $WAN -j ACCEPT
iptables -A FORWARD -j log_warn
iptables -A FORWARD -j DROP
echo -n "NAT... "
iptables -t nat -A PREROUTING -j u_pre
iptables -t nat -A POSTROUTING -j u_post
iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE
echo -n "User rules... "
[ -f /etc/firewall.user ] && . /etc/firewall.user
echo "Done."Seems to work for me. Hope someone else finds it useful too.
