Hi list, For a week or so, I'm gathering the building blocks for a sort of low-tech intrusion detection/prevention system. My "itch": having a system that acts "real time" on the log messages that various daemons produce; having it low profile; easy to get it to act (i.e. no scripts that call scripts that call other scripts). For example, if sshd says "invalid user", I'd like the firewall to act on this, with as little steps in between as possible. Luckily, syslog-ng is able to find patterns all by itself, so I'm able to "skip the middle man", i.e. I can use syslog-ng directly on the firewalling rules. And what is better: I'm not even using the program() call! I'm currently running such a system in pre-production and I'm delighted. It's really easy to build. It works like a charm. Here's how: 0) Install syslog-ng. 1) To get started, get the sshd pattern from the Balabit git web frontend: http://git.balabit.hu/?p=bazsi/syslog-ng-patterndb.git;a=blob;f=access/sshd.... and put it in /etc/syslog-ng/patterndb.d/, run pdbtool merge -D . -p /var/lib/syslog-ng/patterndb.xml 2) Setup your syslog-ng.conf file. Add, in the appropriate sections: # a destination; we have a dual destination here, a file to see the # blocked hosts, and an iptables-destination in /proc to block them. destination d_syslogblock { file("/proc/net/xt_recent/syslogblock" template("+${usracct.device}\n")); file("/var/log/syslogblock"); }; # a parser for the pattern-DB we made in step 1 parser pattern_db { db_parser( file("/var/lib/syslog-ng/patterndb.xml")); }; # a filter to filter the parser results filter f_syslogblock { tags("secevt") and match("REJECT" value("secevt.verdict")); }; # and finally, the log itself: log { source(s_src); parser(pattern_db); filter(f_syslogblock); destination(d_syslogblock); }; 3) Now set up your firewalling. A minimalistic firewall would look like: ip6tables -N block ip6tables -A INPUT -i lo -j ACCEPT ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT ip6tables -A INPUT -m state --state INVALID -j DROP ip6tables -A INPUT -m recent --rcheck --name block \ --seconds 3600 -j DROP # see note (1) below ip6tables -A INPUT -m recent --rcheck --name syslogblock \ --seconds 900 --hitcount 15 -j block ip6tables -A block -m recent --rcheck --name block --set 4) Repeat step 3, but with "iptables" instead of "ip6tables". (I used ip6tables on purpose, because it's time you get ready for IPv6 if you aren't). Ready. Not too hard, isn't it? It works as follows. syslog-ng will put the IP-address of any wrong password or username into the /proc/net/xt_recent/syslogblock file, with a "+" in front of the address. This is the iptables way of telling the "recent" module it should add a certain address. Now the IPtables rules tell, that if someone is seen in this "syslogblock" list more that 15 times within 15 minutes, then (s)he will be added to the "block" list. And if someone is in the "block" list, (s)he will be blocked for an hour. Note (1): if you replace the "--rcheck" here with an "--update" statement, the block will last even longer: "--rcheck" says: were you blocked less than an hour ago? Then we can't let you in. While "--update" says: were you blocked less than an hour ago, but you're here *again*? We'll block you for *another* hour, starting now. So the latter means that you actually need to be quiet for 60 minutes to be able to log in again. There is only one caveat in this whole setup: if you (or syslog-ng) inadvertedly send garbage to the /proc/net/xt_recent/syslogblock file, then this file will be closed. Syslog-ng will reopen it after the "reopen" timeout, so your message will probably come through; but should something change in the working of syslog-ng, like should syslog-ng try to *re-send* such a broken message, then this will, effectively, block the rest of the blocking messages. (I don't think this will happen, because "fprintf" is not a reliable transport, so to say, but you'll never know). I'll be implementing this solution for a couple of other servers in the next weeks or so, and I'll report if there is more to say about it. Oh, BTW: I think that these two lines: ip6tables -A INPUT -m recent --rcheck --name syslogblock --seconds 900 --hitcount 15 -j block ip6tables -A block -m recent --rcheck --name block --set can be concatenated so that you don't need a separate "block" chain anymore, as follows: ip6tables -A INPUT -m recent --rcheck --name syslogblock --seconds 900 --hitcount 15 -m recent --rcheck --name block --set But I'm not sure, I'll have to check. Best regards, Valentijn -- http://www.openoffice.nl/ Open Office - Linux Office Solutions Valentijn Sessink v.sessink#openoffice.nl +31(0)20-4214059