Настройка fail2ban для wowza и icecast

Кто сталкивался с Wowza Media Server знает, что Wowza пишет логи (по умолчанию) в папку /usr/local/WowzaMediaServer/logs и каждый элемент логов разделяется символом табуляции. Это можно исправить в настройках логирования Wowza. Но, иногда, попадается ситуация, когда логи менять нежелательно, по скольку они уже используются для собрания статистики другой утилитой (к примеру, Windows тулза), и замена символа Табуляции(tab) на, скажем, Пробел(space) приведет к неверной обработки логов.
И тогда возникает проблема. Утилита Fail2ban не имеет timestam-а, который разделен символом табуляции ( %Y-%m-%d %H:%M:%S — разделен пробелом).
В связи с этим, мы можем не вносить никаких изменений в настройки логирования wowz-а, а просто добавить свой timestam для Fail2ban, скачав исходники.

Приступим. Для начала нужно скачать последний архив Fail2ban-а

root@bai-08:~#wget https://codeload.github.com/fail2ban/fail2ban/tar.gz/0.8.10
root@bai-08:~#tar xzvf fail2ban-0.8.10.tar.gz
root@bai-08:~#cd fail2ban-0.8.10

Теперь нужно отредактировать файлик, который содержит шаблоны timestamp-ов и добавить свой. И скомпилировать fail2ban.

root@bai-08:~/fail2ban-0.8.10#vim server/datedetector.py
...
template.setPattern("%m/%d/%Y:%H:%M:%S")
self.__templates.append(template)
# Wowza 2012-11-12 06:43:20
template = DateStrptime()
template.setName("Year-Month-Day Hour:Minute:Second")
template.setRegex("\d{4}-\d{2}-\d{2}\s*\d{2}:\d{2}:\d{2}")
template.setPattern("%Y-%m-%d %H:%M:%S")
self.__templates.append(template)
# Exim 2006-12-21 06:43:20
template = DateStrptime()
...

root@bai-08:~/fail2ban-0.8.10#./setup.py install

Теперь добавим фильтры для icecast и wowza.

root@bai-08:~/fail2ban-0.8.10#cat /etc/fail2ban/filter.d/wowza.conf
[Definition]
failregex = connect-pending.*rtmp://.*:1935.*\- \-\s  .* rtmp
connect-pending.*rtmp://.*:8080.*\-.*\-\s*.*rtmp
connect-pending.*rtmp://.*:554.*\-.*\-\s*.*rtmp
connect-pending.*rtmp://.*:1935.*\-.*\-\s*.*rtmp
ignoreregex =

root@bai-08:~/fail2ban-0.8.10#cat /etc/fail2ban/filter.d/icecast.conf
[Definition]
failregex = ^\s-\s-\s.*"GET\s/[^(admin)]
ignoreregex =

После настройки фильтров для wowza и icecast нужно добавить конфигурации для обоих фильтров.

root@bai-08:~/fail2ban-0.8.10#cat /etc/fail2ban/filter.d/jail.conf
# Fail2Ban configuration file.
#
# This file was composed for Debian systems from the original one
#  provided now under /usr/share/doc/fail2ban/examples/jail.conf
#  for additional examples.
#
# To avoid merges during upgrades DO NOT MODIFY THIS FILE
# and rather provide your changes in /etc/fail2ban/jail.local
#
# Author: Yaroslav O. Halchenko
#
# $Revision: 281 $
#

# The DEFAULT allows a global definition of the options. They can be override
# in each jail afterwards.

[DEFAULT]

# "ignoreip" can be an IP address, a CIDR mask or a DNS host
ignoreip = 127.0.0.1 82.80.142.5 82.80.193.4
bantime  = 600
maxretry = 3

# "backend" specifies the backend used to get files modification. Available
# options are "gamin", "polling" and "auto".
# yoh: For some reason Debian shipped python-gamin didn't work as expected
#      This issue left ToDo, so polling is default backend for now
backend = polling

#
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
destemail = root@localhost

#
# ACTIONS
#

# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overriden globally or per
# section within jail.local file
banaction = iptables-multiport

# email action. Since 0.8.1 upstream fail2ban uses sendmail
# MTA for the mailing. Change mta configuration parameter to mail
# if you want to revert to conventional 'mail'.
mta = sendmail

# Default protocol
protocol = tcp

#
# Action shortcuts. To be used to define action parameter

# The simplest action to take: ban only
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]

# ban & send an e-mail with whois report to the destemail.
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s]

# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s]

# Choose default action.  To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g.  action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
action = %(action_)s

#
# JAILS
#

# Next jails corresponds to the standard configuration in Fail2ban 0.6 which
# was shipped in Debian. Enable any defined here jail by including
#
# [SECTION_NAME]
# enabled = true

#
# in /etc/fail2ban/jail.local.
#
# Optionally you may override any other parameter (e.g. banaction,
# action, port, logpath, etc) in that section within jail.local
[icecast]
enabled  = true
port     = 8000
filter   = icecast
logpath  = /var/log/icecast2/access.log
bantime  = 300
maxretry = 100

[wowza]
enabled  = true
port     = 1935,8080,554
filter   = wowza
logpath  = /usr/local/WowzaMediaServer/logs/wowzamediaserver_stats.log
bantime  = 300
maxretry = 100

[ssh]
enabled = true
port    = ssh
filter  = sshd
logpath  = /var/log/auth.log
maxretry = 6
[…]

Далее нужно сделать рестарт для fail2ban и посмотреть правила iptables.
Если используется дистрибутив Ubuntu или Debian нужно вручную добавить ротацию логов и init script (https://github.com/fail2ban/fail2ban/blob/debian/debian/fail2ban.init). Добавляем init.d скрипт. Для этого нужно узнать где находиться fail2ban-client и добавить путь в скрипте.

root@bai-08:# whereis fail2ban-client
fail2ban-client: /usr/local/bin/fail2ban-client
root@bai-08:# cat /etc/init.d/fail2ban

#! /bin/sh
### BEGIN INIT INFO
# Provides:          fail2ban
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Should-Start:      $time $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm
# Should-Stop:       $network $syslog iptables firehol shorewall ipmasq arno-iptables-firewall iptables-persistent ferm
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop fail2ban
# Description:       Start/stop fail2ban, a daemon scanning the log files and
#                    banning potential attackers.
### END INIT INFO

# Author: Aaron Isotton <aaron@isotton.com>
# Modified: by Yaroslav Halchenko <debian@onerussian.com>
#  reindented + minor corrections + to work on sarge without modifications
# Modified: by Glenn Aaldering <glenn@openvideo.nl>
#  added exit codes for status command
#
PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin
DESC="authentication failure monitor"
NAME=fail2ban

# fail2ban-client is not a daemon itself but starts a daemon and
# loads its with configuration
DAEMON=/usr/local/bin/$NAME-client
SCRIPTNAME=/etc/init.d/$NAME

# Ad-hoc way to parse out socket file name
SOCKFILE=`grep -h '^[^#]*socket *=' /etc/$NAME/$NAME.conf /etc/$NAME/$NAME.local 2>/dev/null \
          | tail -n 1 | sed -e 's/.*socket *= *//g' -e 's/ *$//g'`
[ -z "$SOCKFILE" ] && SOCKFILE='/tmp/fail2ban.sock'

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Run as root by default.
FAIL2BAN_USER=root

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
DAEMON_ARGS="$FAIL2BAN_OPTS"

# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS

# Predefine what can be missing from lsb source later on -- necessary to run
# on sarge. Just present it in a bit more compact way from what was shipped
log_daemon_msg () {
        [ -z "$1" ] && return 1
        echo -n "$1:"
        [ -z "$2" ] || echo -n " $2"
}

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
# Actually has to (>=2.0-7) present in sarge. log_daemon_msg is predefined
#  so we must be ok
. /lib/lsb/init-functions

#
# Shortcut function for abnormal init script interruption
#
report_bug()
{
        echo $*
        echo "Please submit a bug report to Debian BTS (reportbug fail2ban)"
        exit 1
}

#
# Helper function to check if socket is present, which is often left after
# abnormal exit of fail2ban and needs to be removed
#
check_socket()
{
        # Return
        #        0 if socket is present and readable
        #        1 if socket file is not present
        #        2 if socket file is present but not readable
        #        3 if socket file is present but is not a socket
        [ -e "$SOCKFILE" ] || return 1
        [ -r "$SOCKFILE" ] || return 2
        [ -S "$SOCKFILE" ] || return 3
        return 0
}

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #        0 if daemon has been started
        #        1 if daemon was already running
        #        2 if daemon could not be started
        do_status && return 1

        if [ -e "$SOCKFILE" ]; then
                log_failure_msg "Socket file $SOCKFILE is present"
                [ "$1" = "force-start" ] \
                        && log_success_msg "Starting anyway as requested" \
                        || return 2
                DAEMON_ARGS="$DAEMON_ARGS -x"
        fi

        # Assure that /var/run/fail2ban exists
        [ -d /var/run/fail2ban ] || mkdir -p /var/run/fail2ban

        if [ "$FAIL2BAN_USER" != "root" ]; then
                # Make the socket directory, IP lists and fail2ban log
                # files writable by fail2ban
                chown "$FAIL2BAN_USER" /var/run/fail2ban
                # Create the logfile if it doesn't exist
                touch /var/log/fail2ban.log
                chown "$FAIL2BAN_USER" /var/log/fail2ban.log
                find /proc/net/xt_recent -name 'fail2ban-*' -exec chown "$FAIL2BAN_USER" {} \;
        fi

        start-stop-daemon --start --quiet --chuid "$FAIL2BAN_USER" --exec $DAEMON -- \
                $DAEMON_ARGS start > /dev/null\
                || return 2

        return 0
}

#
# Function that checks the status of fail2ban and returns
# corresponding code
#
do_status()
{
        $DAEMON ping > /dev/null 2>&1
        return $?
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #        0 if daemon has been stopped
        #        1 if daemon was already stopped
        #        2 if daemon could not be stopped
        #        other if a failure occurred
        $DAEMON status > /dev/null 2>&1 || return 1
        $DAEMON stop > /dev/null || return 2

        # now we need actually to wait a bit since it might take time
        # for server to react on client's stop request. Especially
        # important for restart command on slow boxes
        count=1
        while do_status && [ $count -lt 60 ]; do
                sleep 1
                count=$(($count+1))
        done
        [ $count -lt 60 ] || return 3 # failed to stop

        return 0
}

#
# Function to reload configuration
#
do_reload() {
        $DAEMON reload > /dev/null && return 0 || return 1
        return 0
}

# yoh:
# shortcut function to don't duplicate case statements and to don't use
# bashisms (arrays). Fixes #368218
#
log_end_msg_wrapper()
{
        if [ "$3" != "no" ]; then
                [ $1 -lt $2 ] && value=0 || value=1
                log_end_msg $value
        fi
}

command="$1"
case "$command" in
        start|force-start)
                [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
                do_start "$command"
                log_end_msg_wrapper $? 2 "$VERBOSE"
                ;;

        stop)
                [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
                do_stop
                log_end_msg_wrapper $? 2 "$VERBOSE"
                ;;

        restart|force-reload)
                log_daemon_msg "Restarting $DESC" "$NAME"
                do_stop
                case "$?" in
                        0|1)
                                do_start
                                log_end_msg_wrapper $? 1 "always"
                                ;;
                        *)
                                # Failed to stop
                                log_end_msg 1
                                ;;
                 esac
                ;;

        reload|force-reload)
        log_daemon_msg "Reloading $DESC" "$NAME"
        do_reload
        log_end_msg $?
        ;;

        status)
                log_daemon_msg "Status of $DESC"
                do_status
                case $? in
                        0)  log_success_msg " $NAME is running" ;;
                        255)
                                check_socket
                                case $? in
                                        1)  log_failure_msg " $NAME is not running" && exit 3 ;;
                                        0)  log_failure_msg " $NAME is not running but $SOCKFILE exists" && exit 3 ;;
                                        2)  log_failure_msg " $SOCKFILE not readable, status of $NAME is unknown" && exit 3 ;;
                                        3)  log_failure_msg " $SOCKFILE exists but not a socket, status of $NAME is unknown" && exit 3 ;;
                                        *)  report_bug "Unknown return code from $NAME:check_socket." && exit 4 ;;
                                esac
                                ;;
                        *)  report_bug "Unknown $NAME status code" && exit 4
                esac
                ;;
        *)
                echo "Usage: $SCRIPTNAME {start|force-start|stop|restart|force-reload|status}" >&2
                exit 3
                ;;
esac

*Оригинал можно найти здесь
После добавления скрипта нужно добавить ротацию логов:

root@bai-08:#cat /etc/logrotate.d/fail2ban
/var/log/fail2ban.log {
    weekly
    rotate 4
    compress
    delaycompress
    missingok
    postrotate
    fail2ban-client set logtarget /var/log/fail2ban.log >/dev/null
    endscript

    # If fail2ban runs as non-root it still needs to have write access
    # to logfiles.
    # create 640 fail2ban adm
    #create 640 root adm
}

И добавить скрипт в автозагрузку

root@bai-08:# update-rc.d fail2ban defaults

Теперь рестартуем и проверяем

root@bai-08:~/fail2ban-0.8.10#/etc/init.d/fail2ban restart
root@bai-08:~/fail2ban-0.8.10#/etc/init.d/fail2ban status
* Status of authentication failure monitor
*  fail2ban is running
root@bai-08:~/fail2ban-0.8.10#iptables -L -n
...
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
fail2ban-ssh  tcp  --  0.0.0.0/0         0.0.0.0/0         multiport dports 22
fail2ban-icecast  tcp  --  0.0.0.0/0     0.0.0.0/0         multiport dports 8000
fail2ban-wowza  tcp  --  0.0.0.0/0       0.0.0.0/0         multiport dports 1935,8080,554
DROP       all  --  195.69.65.130        0.0.0.0/0

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain fail2ban-icecast (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

Chain fail2ban-ssh (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

Chain fail2ban-wowza (1 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

Теперь можно проверить работу утилиты

root@bai-08:~/fail2ban-0.8.10#less /var/log/fail2ban.log
…
2012-11-11 08:06:20,939 fail2ban.actions: WARNING [wowza] Ban 125.76.230.107
2012-11-11 08:16:21,861 fail2ban.actions: WARNING [wowza] Unban 125.76.230.107
…

Чтобы вручную разлочит ІР можно использовать несколько подходов. К примеру возьмём другой хост, проверим какие на нем есть jail и разлочим один ІР.

root@ldap:~# fail2ban-client status
Status
|- Number of jail:      1
`- Jail list:           ssh-iptables
root@ldap:~# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
fail2ban-SSH  tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain fail2ban-SSH (1 references)
target     prot opt source               destination
REJECT     all  --  192.168.2.100      0.0.0.0/0      reject-with icmp-port-unreachable
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

root@ldap:~#fail2ban-client set [JAIL] unbanip [xx.xx.xx.xx]
root@ldap:~#fail2ban-client set ssh-iptables unbanip 192.168.2.100
ИЛИ
root@ldap:~#iptables -D fail2ban-SSH -s XXX.XXX.XXX.XXX -j REJECT
root@ldap:~#iptables -D fail2ban-SSH -s 192.168.2.100 -j REJECT
ИЛИ
root@ldap:~#iptables -L --line-numbers
root@ldap:~#iptables -D fail2ban-SSH 1
root@ldap:~#iptables -D <chain> <chain number>

Для проверки работы фильтра, можно использовать команду fail2ban-regex

root@bai-08:~# fail2ban-regex wowzamediaserver_stats.log /etc/fail2ban/filter.d/wowza.conf

Running tests
=============

Use regex file : /etc/fail2ban/filter.d/wowza.conf
Use log file : wowzamediaserver_stats.log

Results
=======

Failregex: 1 total
|- #) [# of hits] regular expression
|  4) [1] connect-pending.*rtmp://.*:1935.*\-.*\-\s*.*rtmp
`-

Ignoreregex: 0 total

Summary
=======

Addresses found:
[4]
193.33.70.59 (Tue Oct 16 15:58:55 2012)

Date template hits:
5 hit(s): Year-Month-Day Hour:Minute:Second

Success, the total number of match is 1

Настройка логирования wowza

root@bai-08:~#vim /usr/local/WowzaMediaServer/conf/log4j.properties
...
log4j.appender.serverError.layout.Delimeter=tab
...

Полезные ссылки:
http://www.fail2ban.org/wiki/index.php/MANUAL_0_8
http://docs.python.org/2/library/re.html
https://github.com/fail2ban/fail2ban/downloads

Автор: admin, 15 августа 2013
Рубрики: Системы мониторинга
Метки: ,

Написать комментарий

Последние статьи

Яндекс.Метрика
?>