handle xt_recent from syslog-ng 2


The solution from Block outdated clients won´t work with syslog-ng 3.4.2, because syslog-ng syslog-ng uses “lseek()” to get the end of /proc/net/xt_recent/something while the program() destination just starts the program.

Withe the destination file you get log-entries like:
Aug 29 00:00:44 mx03.schaal-24.de syslog-ng[20351]: Error suspend timeout has elapsed, attempting to write again; fd='24'

Aug 29 00:00:44 mx03.schaal-24.de syslog-ng[20351]: I/O error occurred while writing; fd='24', error='Input/output error (5)'

Aug 29 00:00:44 mx03.schaal-24.de syslog-ng[20351]: Suspending write operation because of an I/O error; fd='24', time_reopen='10
'

So you have to change the destination from file to program and create a shell-script.

destination deny-mirror {
  program("/root/scripts/syslog/ban-recent.sh"
  template("+${APACHE.SRC-IP} clamav-403\n"));
};

The shell-script may looks like:
#!/bin/bash
IP=`echo $1|cut -d" " -f1`
JAIL=`echo $1|cut -d" " -f2`
echo +$IP > /proc/net/xt_recent/$JAIL

Basically
#!/bin/sh
echo +$1 > /proc/net/xt_recent/$2

would do the job.

With the first solution you can also use a whitelist or store the data in an database.:
#!/bin/bash
WHITELIST_MX_02="1.2.3.4 4.5.6.7"
WHITELIST_MX_03="10.11.12.13 14.15.16.17"

WHITELIST=$WHITELIST_MX_02" "$WHITELIST_MX_03"

SQLBIN=`which mysql`
DB="system-log"
TAB=iptables

IP=`echo $1|cut -d" " -f1`
JAIL=`echo $1|cut -d" " -f2`

for IP_WL in $(echo $WHITELIST); do
  if [ $IP != $IP_WL ]; then
    echo +$IP > /proc/net/xt_recent/$JAIL
    $SQLBIN $DB -e "INSERT INTO $TAB VALUES(INET_ATON('$IP'),INET_ATON('0.0.0.0'),80,'$JAIL',1,now(),DEFAULT) ON DUPLICATE KEY UPDATE hits=hits+1,remote=DEFAULT;"
  fi
done;


Leave a comment

Your email address will not be published. Required fields are marked *

I confirm

2 thoughts on “handle xt_recent from syslog-ng

  • Jan

    Thanks for hinting at the lseek() issue! I’ve been wondering for a while why my rules stopped working after the upgrade.
    Some hints, though …

    If you’re using bash anyway,

    IP=`echo $1|cut -d” ” -f1`
    JAIL=`echo $1|cut -d” ” -f2`

    is better written as

    IP=${1%% *}
    JAIL=${1#* }

    to avoid creating two new processes.

    Also I don’t think your whitelist loop works like that … Did you really intend to jail the source ip if you find one ip in the whitelist that doesn’t match? If your whitelist has two different ips, this will jail all candidates. I think what you want is to check all ips in the whitelist, and jail the candidate if it doesn’t match any of them.

    Finally, syslog-ng (at least for version 3.5 that I’m looking at) keeps the script running and expects it to read further input through stdin. This is kind of obscurely implied in the documentation here:
    https://syslog-ng.com/documents/html/syslog-ng-ose-3.5-guides/en/syslog-ng-ose-guide-admin/html/reference-destination-program.html

    You’ll notice if you add logging to the script: The log output is written many times per second, because when the script exits, syslog-ng restarts it immediately, even before there’s anything to log.

    Thus you want to wrap the script in an endless loop, like so:

    while true ; do
    {
    read ip target
    [ -z “$ip” ] && continue
    echo +$ip > /proc/net/xt_recent/$target
    date +”%F %T $ip $target”
    } 2>&1 >> /var/log/ban.log
    done

    The `read` will block until input is available.

    I’m still seeing empty output every 20 minutes … guessing syslog-ng still restarts the script regularly even if nothing has happened. That’s what the “empty parameter – continue” shortcut is for.

    I’ve also wrapped the echo-to-proc in with the logging so that next time this throws errors, I’ll see them in the ban.log.

    HTH! Jan