Кто сталкивался с 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