Load fail2ban-0.4.1 into debs/fail2ban/trunk.

debian-releases/etch
Yaroslav Halchenko 2005-07-06 23:10:26 +00:00
parent 2b5c103cd0
commit edd7ed5d30
16 changed files with 778 additions and 10 deletions

17
Makefile Normal file
View File

@ -0,0 +1,17 @@
# quick dirty hack to avoid reading documentation for cdbs where
# install target involved only if using autotools
DESTDIR=debian/fail2ban
all::
cp fail2ban.py fail2ban
gzip -c CHANGELOG > changelog.gz
install:: all
mkdir -p $(DESTDIR)/etc/default
cp config/fail2ban.conf.default $(DESTDIR)/etc/fail2ban.conf
cp config/gentoo-confd $(DESTDIR)/etc/default/fail2ban
mkdir -p $(DESTDIR)/usr/lib/fail2ban/
cp log4py.py $(DESTDIR)/usr/lib/fail2ban/
clean::
rm -rf changelog.gz fail2ban `find -iname '*.pyc' `

View File

@ -21,7 +21,7 @@ ipfw-start-rule = 100
# Notes.: start fail2ban as a daemon. Output is redirect to logfile.
# Values: [true | false] Default: false
#
background = false
background = true
# Option: debug
# Notes.: enable debug mode. More verbose output and bypass root user test.
@ -45,7 +45,7 @@ logfile = /var/log/fail2ban.log
# Notes.: number of retrys before IP gets banned.
# Values: NUM Default: 3
#
maxretry = 3
maxretry = 5
# Option: bantime
# Notes.: number of seconds an IP will be banned.
@ -85,9 +85,9 @@ enabled = false
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/httpd/access_log
# Values: FILE Default: /var/log/apache/access_log
#
logfile = /var/log/httpd/access_log
logfile = /var/log/apache/access_log
# Option: timeregex
# Notes.: regex to match timestamp in Apache logfile.
@ -118,9 +118,9 @@ enabled = true
# Option: logfile
# Notes.: logfile to monitor.
# Values: FILE Default: /var/log/secure
# Values: FILE Default: /var/log/auth.log
#
logfile = /var/log/secure
logfile = /var/log/auth.log
# Option: timeregex
# Notes.: regex to match timestamp in SSH logfile.
@ -140,4 +140,4 @@ timepattern = %%b %%d %%H:%%M:%%S
# Notes.: regex to match the password failures messages in the logfile.
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
#
failregex = Authentication failure|Failed password|Invalid user
failregex = Authentication failure|Failed password|Invalid user|Illegal user|Failed keyboard-interactive

12
debian/README.Debian vendored Normal file
View File

@ -0,0 +1,12 @@
fail2ban for Debian
-------------------
This package is nearly 100% identical to the upstream version. It was merely
packaged to be installed on a Debian system.
Module log4py installed into lib/fail2ban directory because there is no package for not-developed-in-a-long-time fail2ban
See the file TODO.Debian for more details, as well as the Debian Bug Tracking
system.
-- Yaroslav Halchenko <debian@onerussian.com>, Tue, 4 Jul 2005 00:00:00 -1000

3
debian/TODO vendored Normal file
View File

@ -0,0 +1,3 @@
Because this is just a quick hack to package fail2ban it might be missing some crucial parts...
-- yoh@onerussian.com

6
debian/changelog vendored Normal file
View File

@ -0,0 +1,6 @@
fail2ban (0.4.1-1) unstable; urgency=low
* First upstream release of a Debian package
-- Yaroslav Halchenko <debian@onerussian.com> Mon, 04 Jul 2005 11:47:23 +0300

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
4

18
debian/control vendored Normal file
View File

@ -0,0 +1,18 @@
Source: fail2ban
Section: net
Priority: optional
Maintainer: Yaroslav Halchenko <yoh@onerussian.com>
Build-Depends-Indep: debhelper (>= 4.1.67), python, python2.3-dev
Standards-Version: 3.6.1
Package: fail2ban
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}, python, iptables
Description: Ban IPs that make too many password failure
Fail2Ban scans log files like /var/log/pwdfail or
/var/log/apache/error_log and bans IP that makes too many password
failures. It updates firewall rules to reject the IP
address. Currently, iptables, ipfwadm and ipfw are supported.
.
Homepage: http://www.sourceforge.net/projects/fail2ban

26
debian/copyright vendored Normal file
View File

@ -0,0 +1,26 @@
This package was originally debianized by Yaroslav Halchenko
<debian@onerussian.com> on Mon Jul 4 14:41:34 HST 2005
It was downloaded from http://www.sourceforge.net/projects/fail2ban
pointed from the project page of the upstream author
Cyril Jaquier: <lostcontrol@users.sourceforge.net>
http://fail2ban.sourceforge.net
Copyright:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
See /usr/share/common-licenses/GPL for the full license.

2
debian/fail2ban.conffiles vendored Normal file
View File

@ -0,0 +1,2 @@
/etc/fail2ban.conf
/etc/default/fail2ban

61
debian/fail2ban.init vendored Normal file
View File

@ -0,0 +1,61 @@
#! /bin/sh
#
# skeleton example file to build /etc/init.d/ scripts.
# This file should be used to construct scripts for /etc/init.d.
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/fail2ban
NAME=fail2ban
DESC=fail2ban
PIDFILE=/var/run/$NAME.pid
test -x $DAEMON || exit 0
# Include fail2ban defaults if available
if [ -f /etc/default/fail2ban ] ; then
. /etc/default/fail2ban
fi
DAEMON_OPTS=$FAIL2BAN_OPTS
set -e
case "$1" in
start)
echo -n "Starting $DESC: "
[ -f $PIDFILE ] && [ ! -d /proc/`cat $PIDFILE` ] && rm -f $PIDFILE
start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
-b --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid
rm -f $PIDFILE
echo "$NAME."
;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: "
( $0 stop )
sleep 1
$0 start
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

1
debian/fail2ban.links vendored Normal file
View File

@ -0,0 +1 @@
/usr/bin/fail2ban /usr/sbin/fail2ban

20
debian/rules vendored Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/make -f
# Copyrignt 2003-04 Yaroslav Halchenko <debian@onerussian.com>
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/makefile.mk
include /usr/share/cdbs/1/class/python-distutils.mk
#include /usr/share/cdbs/1/rules/buildcore.mk
#include /usr/share/cdbs/1/class/autotools.mk
#DEB_MAKE_INSTALL_TARGET := "install DESTDIR=debian/fail2ban"
# does on package by package bases so doesn't work :-/
#DEB_DH_INSTALL_ARGS := --list-missing
# DEB_OPT_FLAG :=
# DEB_CONFIGURE_EXTRA_FLAGS := --enable-debug
# tight versioning
#DEB_DH_MAKESHLIBS_ARGS := -V
common-install-prehook-impl::
make install
clean::
make clean

6
debian/watch vendored Normal file
View File

@ -0,0 +1,6 @@
# watch control file for uscan
# Run the "uscan" command to check for upstream updates and more.
# Site Directory Pattern Version Script
version=2
http://voxel.dl.sourceforge.net/sourceforge/fail2ban/ \
fail2ban-([0-9]+\.[0-9]+\.[0-9]*)\.tar\.bz2 debian uupdate

View File

@ -29,6 +29,10 @@ __license__ = "GPL"
import time, sys, getopt, os, signal, string
from ConfigParser import *
# Appends our own modules path
# you: moved before loading log4py so we add path to it
sys.path.append('/usr/lib/fail2ban')
# Checks if log4py is present.
try:
import log4py
@ -36,8 +40,6 @@ except:
print "log4py is needed (see README)"
sys.exit(-1)
# Appends our own modules path
sys.path.append('/usr/lib/fail2ban')
from firewall.iptables import Iptables
from firewall.ipfw import Ipfw

593
log4py.py Normal file
View File

@ -0,0 +1,593 @@
"""
Python logging module - Version 1.3
Loglevels:
LOGLEVEL_NONE, LOGLEVEL_ERROR, LOGLEVEL_NORMAL, LOGLEVEL_VERBOSE, LOGLEVEL_DEBUG
Format-Parameters:
%C -- The name of the current class.
%D -- Program duration since program start.
%d -- Program duration for the last step (last output).
%F -- The name of the current function.
%f -- Current filename
%L -- Log type (Error, Warning, Debug or Info)
%M -- The actual message.
%N -- The current line number.
%T -- Current time (human readable).
%t -- Current time (machine readable)
%U -- Current fully qualified module/file.
%u -- Current module/file.
%x -- NDC (nested diagnostic contexts).
Pre-defined Formats:
FMT_SHORT -- %M
FMT_MEDIUM -- [ %C.%F ] %D: %M
FMT_LONG -- %T %L %C [%F] %x%M
FMT_DEBUG -- %T [%D (%d)] %L %C [%F (%N)] %x%M
"""
# Logging levels
LOGLEVEL_NONE = 1 << 0
LOGLEVEL_ERROR = 1 << 1
LOGLEVEL_NORMAL = 1 << 2
LOGLEVEL_VERBOSE = 1 << 3
LOGLEVEL_DEBUG = 1 << 4
# Pre-defined format strings
FMT_SHORT = "%M"
FMT_MEDIUM = "[ %C.%F ] %D: %M"
FMT_LONG = "%T %L %C [%F] %x%M"
FMT_DEBUG = "%T [%D (%d)] %L %C [%F (%N)] %x%M"
# Special logging targets
TARGET_MYSQL = "MySQL"
TARGET_POSTGRES = "Postgres"
TARGET_SYSLOG = "Syslog"
TARGET_SYS_STDOUT = "sys.stdout"
TARGET_SYS_STDERR = "sys.stderr"
TARGET_SYS_STDOUT_ALIAS = "stdout"
TARGET_SYS_STDERR_ALIAS = "stderr"
SPECIAL_TARGETS = [ TARGET_MYSQL, TARGET_POSTGRES, TARGET_SYSLOG, TARGET_SYS_STDOUT, TARGET_SYS_STDERR, TARGET_SYS_STDOUT_ALIAS, TARGET_SYS_STDERR_ALIAS ]
# Configuration files
CONFIGURATION_FILES = {}
CONFIGURATION_FILES[1] = "log4py.conf" # local directory
CONFIGURATION_FILES[2] = "$HOME/.log4py.conf" # hidden file in the home directory
CONFIGURATION_FILES[3] = "/etc/log4py.conf" # system wide file
# Constants for the FileAppender
ROTATE_NONE = 0
ROTATE_DAILY = 1
ROTATE_WEEKLY = 2
ROTATE_MONTHLY = 3
# The following constants are of internal interest only
# Message constants (used for ansi colors and for logtype %L)
MSG_DEBUG = 1 << 0
MSG_WARN = 1 << 1
MSG_ERROR = 1 << 2
MSG_INFO = 1 << 3
# Boolean constants
TRUE = "TRUE"
FALSE = "FALSE"
# Color constants
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
PURPLE = 35
AQUA = 36
WHITE = 37
LOG_MSG = { MSG_DEBUG: "DEBUG", MSG_WARN: "WARNING", MSG_ERROR: "ERROR", MSG_INFO: "INFO"}
LOG_COLORS = { MSG_DEBUG: [WHITE, BLACK, FALSE], MSG_WARN: [WHITE, BLACK, FALSE], MSG_ERROR: [WHITE, BLACK, TRUE], MSG_INFO: [WHITE, BLACK, FALSE]}
LOG_LEVELS = { "DEBUG": LOGLEVEL_DEBUG, "VERBOSE": LOGLEVEL_VERBOSE, "NORMAL": LOGLEVEL_NORMAL, "NONE": LOGLEVEL_NONE, "ERROR": LOGLEVEL_ERROR }
SECTION_DEFAULT = "Default"
from time import time, strftime, localtime
from types import StringType, ClassType, InstanceType, FileType, TupleType
from string import zfill, atoi, lower, upper, join, replace, split, strip
from re import sub
from ConfigParser import ConfigParser, NoOptionError
from os import stat, rename
import sys
import traceback
import os
import copy
import socket
import locale
if (os.name == "posix"):
import syslog
try:
import MySQLdb
mysql_available = TRUE
except:
mysql_available = FALSE
def get_homedirectory():
if (sys.platform == "win32"):
if (os.environ.has_key("USERPROFILE")):
return os.environ["USERPROFILE"]
else:
return "C:\\"
else:
if (os.environ.has_key("HOME")):
return os.environ["HOME"]
else:
# No home directory set
return ""
# This is the main class for the logging module
class Logger:
cache = {}
instance = None
configfiles = []
hostname = socket.gethostname()
def __init__(self, useconfigfiles = TRUE, customconfigfiles = None):
""" **(private)** Class initalization & customization. """
if (customconfigfiles):
if (type(customconfigfiles) == StringType):
customconfigfiles = [customconfigfiles]
Logger.configfiles = customconfigfiles
if (not Logger.instance):
self.__Logger_setdefaults()
if (useconfigfiles == TRUE):
self.__Logger_appendconfigfiles(Logger.configfiles)
# read the default options
self.__Logger_parse_options()
self.__Logger_timeinit = time()
self.__Logger_timelaststep = self.__Logger_timeinit
Logger.instance = self
if (useconfigfiles == TRUE):
# read and pre-cache settings for named classids
self.__Logger_cache_options()
def get_root(self):
""" Provides a way to change the base logger object's properties. """
return Logger.instance
def get_instance(self, classid = "Main", use_cache = TRUE):
""" Either get the cached logger instance or create a new one
Note that this is safe, even if you have your target set to sys.stdout
or sys.stderr
"""
cache = Logger.cache
if (type(classid) == ClassType):
classid = classid.__name__
elif (type(classid) == InstanceType):
classid = classid.__class__.__name__
# classid has to be lowercase, because the ConfigParser returns sections lowercase
classid = lower(classid)
if ((cache.has_key(classid)) and (use_cache == TRUE)):
cat = Logger.cache[classid]
else:
instance = Logger.instance
# test for targets which won't deep copy
targets = instance.__Logger_targets
deepcopyable = TRUE
for i in range(len(targets)):
if (type(targets[i]) == FileType):
deepcopyable = FALSE
if (deepcopyable == FALSE):
# swap the non-copyable target out for a moment
del instance.__Logger_targets
cat = copy.deepcopy(instance)
instance.__Logger_targets = targets
cat.__Logger_targets = targets
else:
cat = copy.deepcopy(instance)
cat.__Logger_classname = classid
# new categories have their own private Nested Diagnostic Contexts
self.__Logger_ndc = []
self.__Logger_classid = classid
cat.debug("Class %s instantiated" % classid)
if (use_cache == TRUE):
cache[classid] = cat
return cat
# Log-target handling (add, remove, set, remove_all)
def add_target(self, target, *args):
""" Add a target to the logger targets. """
if (not target in self.__Logger_targets):
if (target == TARGET_MYSQL):
if (mysql_available == TRUE):
# Required parameters: dbhost, dbname, dbuser, dbpass, dbtable
try:
self.__Logger_mysql_connection = MySQLdb.connect(host=args[0], db=args[1], user=args[2], passwd=args[3])
self.__Logger_mysql_cursor = self.__Logger_mysql_connection.cursor()
self.__Logger_mysql_tablename = args[4]
self.__Logger_targets.append(target)
except MySQLdb.OperationalError, detail:
self.error("MySQL connection failed: %s" % detail)
else:
self.error("MySQL target not added - Python-mysql not available")
else:
if (type(target) == StringType):
if (target not in SPECIAL_TARGETS):
# This is a filename
target = FileAppender(target, self.__Logger_rotation)
if ((target == TARGET_SYSLOG) and (os.name != "posix")):
self.warn("TARGET_SYSLOG is not available on non-posix platforms!")
else:
self.__Logger_targets.append(target)
def remove_target(self, target):
""" Remove a target from the logger targets. """
if (target in self.__Logger_targets):
if (target == TARGET_MYSQL):
self.__Logger_mysql_connection.close()
self.__Logger_targets.remove(target)
def set_target(self, target):
""" Set a single target. """
if (type(target) == StringType):
if (target not in SPECIAL_TARGETS):
# File target
target = FileAppender(target, self.__Logger_rotation)
self.__Logger_targets = [ target ]
def remove_all_targets(self):
""" Remove all targets from the logger targets. """
self.__Logger_targets=[]
def get_targets(self):
""" Returns all defined targets. """
return self.__Logger_targets
# Methods to set properties
def set_loglevel(self, loglevel):
""" Set the loglevel for the current instance. """
self.__Logger_loglevel = loglevel
def set_formatstring(self, formatstring):
""" Set a format string. """
self.__Logger_formatstring = formatstring
def set_use_ansi_codes(self, useansicodes):
""" Use ansi codes for output to the console (TRUE or FALSE). """
self.__Logger_useansicodes = useansicodes
def set_time_format(self, timeformat):
""" Set the time format (default: loaded from the system locale). """
self.__Logger_timeformat = timeformat
def set_rotation(self, rotation):
""" Set the file rotation mode to one of ROTATE_NONE, ROTATE_DAILY, ROTATE_WEEKLY, ROTATE_MONTHLY """
self.__Logger_rotation = rotation
for i in range(len(self.__Logger_targets)):
target = self.__Logger_targets[i]
if (isinstance(target, FileAppender)):
target.set_rotation(rotation)
# Method to get properties
def get_loglevel(self):
""" Returns the current loglevel. """
return self.__Logger_loglevel
def get_formatstring(self):
""" Returns the current format string. """
return self.__Logger_formatstring
def get_use_ansi_codes(self):
""" Returns, wether ansi codes are being used or not. """
return self.__Logger_useansicodes
def get_time_format(self):
""" Returns the current time format. """
return self.__Logger_timeformat
def get_rotation(self):
""" Returns the current rotation setting. """
return self.__Logger_rotation
# Methods to push and pop trace messages for nested contexts
def push(self, message):
""" Add a trace message. """
self.__Logger_ndc.append(message)
def pop(self):
""" Remove the topmost trace message. """
ct = len(self.__Logger_ndc)
if (ct):
del(self.__Logger_ndc[ct-1])
def clear_ndc(self):
""" Clears all NDC messages. """
self.__Logger_ndc = []
# Methods to actually print messages
def debug(self, *messages):
""" Write a debug message. """
if (self.__Logger_loglevel >= LOGLEVEL_DEBUG):
message = self.__Logger_collate_messages(messages)
self.__Logger_showmessage(message, MSG_DEBUG)
def warn(self, *messages):
""" Write a warning message. """
if (self.__Logger_loglevel >= LOGLEVEL_VERBOSE):
message = self.__Logger_collate_messages(messages)
self.__Logger_showmessage(message, MSG_WARN)
def error(self, *messages):
""" Write a error message. """
if (self.__Logger_loglevel >= LOGLEVEL_ERROR):
message = self.__Logger_collate_messages(messages)
self.__Logger_showmessage(message, MSG_ERROR)
def info(self, *messages):
""" Write a info message. """
if (self.__Logger_loglevel >= LOGLEVEL_NORMAL):
message = self.__Logger_collate_messages(messages)
self.__Logger_showmessage(message, MSG_INFO)
# Private methods of the Logger class - you never have to use those directly
def __Logger_collate_messages(self, messages):
""" **(private)** Create a single string from a number of messages. """
return strip(reduce(lambda x, y: "%s%s" % (x, y), messages))
def __Logger_tracestack(self):
""" **(private)** Analyze traceback stack and set linenumber and functionname. """
stack = traceback.extract_stack()
self.__Logger_module = stack[-4][0]
self.__Logger_linenumber = stack[-4][1]
self.__Logger_functionname = stack[-4][2]
self.__Logger_filename = stack[-4][0]
if (self.__Logger_functionname == "?"):
self.__Logger_functionname = "Main"
def __Logger_setdefaults(self):
""" **(private)** Set default values for internal variables. """
locale.setlocale(locale.LC_ALL)
self.__Logger_classid = None
self.__Logger_targets = [ TARGET_SYS_STDOUT ] # default target = sys.stdout
self.__Logger_formatstring = FMT_LONG
self.__Logger_loglevel = LOGLEVEL_NORMAL
self.__Logger_rotation = ROTATE_NONE
self.__Logger_useansicodes = FALSE
self.__Logger_functionname = ""
self.__Logger_filename = ""
self.__Logger_linenumber = -1
try:
self.__Logger_timeformat = "%s %s" % (locale.nl_langinfo(locale.D_FMT), locale.nl_langinfo(locale.T_FMT))
except (AttributeError):
self.__Logger_timeformat = "%d.%m.%Y %H:%M:%S"
self.__Logger_classname = None
self.__Logger_configfilename = ""
self.__Logger_module = ""
self.__Logger_ndc = [] # ndc = Nested Diagnostic Context
def __Logger_find_config(self):
""" **(private)** Search for configuration files. """
if (not self.__Logger_configfilename):
priorities = CONFIGURATION_FILES.keys()
priorities.sort()
configfilename = ""
for i in range(len(priorities)):
filename = CONFIGURATION_FILES[priorities[i]]
home_directory = get_homedirectory()
if (os.sep == "\\"):
home_directory = replace(home_directory, "\\", "\\\\")
filename = sub("\$HOME", home_directory, filename)
if (os.path.exists(filename)):
configfilename = filename
break
self.__Logger_configfilename = configfilename
return self.__Logger_configfilename
def __Logger_parse_options(self, section = SECTION_DEFAULT):
""" **(private)** Parse main options from config file. """
configfilename = self.__Logger_find_config()
if (configfilename != ""):
parser = ConfigParser()
parser.read(configfilename)
self.__Logger_set_instance_options(parser, section, self)
return TRUE
def __Logger_set_instance_options(self, parser, section, instance):
""" **(private)** Set the options for a given instance from the parser section """
for i in range(len(parser.options(section))):
option = lower(parser.options(section)[i])
value = parser.get(section, option)
if (option == "format"):
instance.set_formatstring(value)
elif (option == "timeformat"):
instance.set_time_format(value)
elif (option == "ansi"):
instance.set_use_ansi_codes(upper(value))
elif (option == "loglevel"):
instance.set_loglevel(LOG_LEVELS[upper(value)])
elif (option == "target"):
splitted = split(value, ",")
instance.remove_all_targets()
for i in range(len(splitted)):
instance.add_target(strip(splitted[i]))
def __Logger_cache_options(self):
""" **(private)** Read and cache debug levels for categories from config file. """
configfilename = self.__Logger_find_config()
if (configfilename != ""):
parser = ConfigParser()
parser.read(configfilename)
for i in range(len(parser.sections())):
section = parser.sections()[i]
if (section != SECTION_DEFAULT):
instance = self.get_instance(section)
self.__Logger_set_instance_options(parser, section, instance)
return TRUE
def __Logger_appendconfigfiles(self, filenames):
""" **(private)** Append a filename to the list of configuration files. """
filenames.reverse()
for i in range(len(filenames)):
keys = CONFIGURATION_FILES.keys()
CONFIGURATION_FILES[min(keys) - 1] = filenames[i]
def __Logger_get_ndc(self):
""" **(private)** Returns the NDC (nested diagnostic context) joined with single-spaces. """
if (len(self.__Logger_ndc)):
return join(self.__Logger_ndc)
else:
return ""
def __Logger_showmessage(self, message, messagesource):
""" **(private)** Writes a message to all targets set. """
if (isinstance(message, Exception)):
(exc_type, exc_value, tb) = sys.exc_info()
exception_summary = traceback.format_exception(exc_type, exc_value, tb)
message = 'Exception caught:\n'
for line in exception_summary:
message = "%s%s" % (message, line)
currenttime = time()
self.__Logger_tracestack()
timedifference = "%.3f" % (currenttime - self.__Logger_timeinit)
timedifflaststep = "%.3f" % (currenttime - self.__Logger_timelaststep)
self.__Logger_timelaststep = currenttime
milliseconds = int(round((currenttime - long(currenttime)) * 1000))
timeformat = sub("%S", "%S." + (zfill(milliseconds, 3)), self.__Logger_timeformat)
currentformattedtime = strftime(timeformat, localtime(currenttime))
line = self.__Logger_formatstring
line = sub("%C", str(self.__Logger_classname), line)
line = sub("%D", timedifference, line)
line = sub("%d", timedifflaststep, line)
line = sub("%F", self.__Logger_functionname, line)
line = sub("%f", self.__Logger_filename, line)
line = sub("%U", self.__Logger_module, line)
line = sub("%u", os.path.split(self.__Logger_module)[-1], line)
ndc = self.__Logger_get_ndc()
if (ndc != ""):
line = sub("%x", "%s - " % ndc, line)
else:
line = sub("%x", "", line)
message = replace(message, "\\", "\\\\")
if (self.__Logger_useansicodes == TRUE):
line = sub("%L", self.__Logger_ansi(LOG_MSG[messagesource], messagesource), line)
line = sub("%M", self.__Logger_ansi(message, messagesource), line)
else:
line = sub("%L", LOG_MSG[messagesource], line)
line = sub("%M", message, line)
line = sub("%N", str(self.__Logger_linenumber), line)
line = sub("%T", currentformattedtime, line)
line = sub("%t", `currenttime`, line)
for i in range(len(self.__Logger_targets)):
target = self.__Logger_targets[i]
if (target == TARGET_MYSQL):
sqltime = strftime("'%Y-%m-%d', '%H:%M:%S'", localtime(currenttime))
sqlStatement = "INSERT INTO %s (host, facility, level, date, time, program, msg) VALUES ('%s', '%s', '%s', %s, '%s', '%s')" % (self.__Logger_mysql_tablename, self.hostname, self.__Logger_functionname, LOG_MSG[messagesource], sqltime, str(self.__Logger_classname), sub("'", "`", message + " " + ndc))
self.__Logger_mysql_cursor.execute(sqlStatement)
elif (target == TARGET_SYSLOG):
# We don't need time and stuff here
syslog.syslog(message)
elif (isinstance(target, FileAppender)):
target.writeline(line)
elif (target == sys.stdout) or (lower(target) == TARGET_SYS_STDOUT) or (lower(target) == TARGET_SYS_STDOUT_ALIAS):
sys.stdout.write("%s\n" % line)
elif (target == sys.stderr) or (lower(target) == TARGET_SYS_STDERR) or (lower(target) == TARGET_SYS_STDERR_ALIAS):
sys.stderr.write("%s\n" % line)
else:
target.write("%s\n" % line)
def __Logger_ansi(self, text, messagesource):
""" **(private)** Converts plain text to ansi text. """
bold = LOG_COLORS[messagesource][2]
fg = str(LOG_COLORS[messagesource][0])
bg = LOG_COLORS[messagesource][1]
if (bold == TRUE):
fg = "%s;1" % fg
bg = bg + 10
text = "\033[%d;%sm%s\033[0m" % (bg, fg, text)
return text
class FileAppender:
def __init__(self, filename, rotation = ROTATE_NONE):
""" **(private)** Class initalization & customization. """
self.__FileAppender_filename = sub("\$HOME", get_homedirectory(), filename)
self.__FileAppender_filename = os.path.expanduser(self.__FileAppender_filename)
self.__FileAppender_filename = os.path.expandvars(self.__FileAppender_filename)
self.__FileAppender_rotation = rotation
def __FileAppender_rotate(self, modification_time):
""" **(private)** Check, wether the file has to be rotated yet or not. """
if (self.__FileAppender_rotation == ROTATE_DAILY):
strftime_mask = "%Y%j"
elif (self.__FileAppender_rotation == ROTATE_WEEKLY):
strftime_mask = "%Y%W"
elif (self.__FileAppender_rotation == ROTATE_MONTHLY):
strftime_mask = "%Y%m"
return (strftime(strftime_mask, localtime(time())) != strftime(strftime_mask, localtime(modification_time)))
def __FileAppender_date_string(self, modification_time):
""" **(private)** Returns a new filename for the rotated file with the appropriate time included. """
if (self.__FileAppender_rotation == ROTATE_DAILY):
return strftime("%Y-%m-%d", localtime(modification_time))
elif (self.__FileAppender_rotation == ROTATE_WEEKLY):
return strftime("%Y-Week %W", localtime(modification_time))
elif (self.__FileAppender_rotation == ROTATE_MONTHLY):
return strftime("%Y-Month %m", localtime(modification_time))
def get_rotation(self):
""" Returns the current rotation setting. """
return self.__FileAppender_rotation
def set_rotation(self, rotation):
""" Set the file rotation mode to one of ROTATE_NONE, ROTATE_DAILY, ROTATE_WEEKLY, ROTATE_MONTHLY """
self.__FileAppender_rotation = rotation
def write(self, text):
""" Write some text to the file appender. """
if ((os.path.exists(self.__FileAppender_filename)) and (self.__FileAppender_rotation != ROTATE_NONE)):
statinfo = stat(self.__FileAppender_filename)
if (self.__FileAppender_rotate(statinfo[8])):
splitted = os.path.splitext(self.__FileAppender_filename)
target_file = "%s-%s%s" % (splitted[0], self.__FileAppender_date_string(statinfo[8]), splitted[1])
rename(self.__FileAppender_filename, target_file)
file = open(self.__FileAppender_filename, "a")
file.write(text)
file.close()
def writeline(self, text):
""" Write some text including newline to the file appender. """
self.write("%s\n" % text)

View File

@ -36,7 +36,7 @@ setup(
author = "Cyril Jaquier",
author_email = "lostcontrol@users.sourceforge.net",
url = "http://www.sourceforge.net/projects/fail2ban",
scripts = ['fail2ban.py'],
scripts = ['fail2ban'],
py_modules = ['version'],
packages = ['firewall', 'logreader', 'confreader', 'utils']
)