Skip to content
This repository
Browse code

Upgraded to fresh upstream 0.6.0

  • Loading branch information...
commit ad466ecb3c47edf89d60456182296be46b3feecb 2 parents 7f0a3df + 840f6cd
Yaroslav Halchenko authored October 16, 2007
30  CHANGELOG
@@ -4,9 +4,37 @@
4 4
              |_| \__,_|_|_/___|_.__/\__,_|_||_|
5 5
 
6 6
 =============================================================
7  
-Fail2Ban (version 0.5.4)                           2005/09/13
  7
+Fail2Ban (version 0.6.0)                           2005/11/20
8 8
 =============================================================
9 9
 
  10
+ver. 0.6.0 (2005/11/20) - stable
  11
+----------
  12
+- Propagated patches introduced by Debian maintainer 
  13
+  (Yaroslav Halchenko):
  14
+  * Added an option to report local time (including timezone)
  15
+    or GMT in mail notification.
  16
+
  17
+ver. 0.5.5 (2005/10/26) - beta
  18
+----------
  19
+- Propagated patches introduced by Debian maintainer 
  20
+  (Yaroslav Halchenko):
  21
+  * Introduced fwcheck option to verify consistency of the
  22
+    chains. Implemented automatic restart of fail2ban main
  23
+    function in case check of fwban or fwunban command failed
  24
+    (closes: #329163, #331695). (Introduced patch was further
  25
+    adjusted by upstream author).
  26
+  * Added -f command line parameter for [findtime].
  27
+  * Added a cleanup of firewall rules on emergency shutdown
  28
+    when unknown exception is catched.
  29
+  * Fail2ban should not crash now if a wrong file name is
  30
+    specified in config.
  31
+  * reordered code a bit so that log targets are setup right
  32
+    after background and then only loglevel (verbose, debug)
  33
+    is processed, so the warning could be seen in the logs
  34
+  * Added a keyword <section> in parsing of the subject and
  35
+    the body of an email sent out by fail2ban (closes:
  36
+    #330311)
  37
+
10 38
 ver. 0.5.4 (2005/09/13) - beta
11 39
 ----------
12 40
 - Fixed bug #1286222.
2  PKG-INFO
... ...
@@ -1,6 +1,6 @@
1 1
 Metadata-Version: 1.0
2 2
 Name: fail2ban
3  
-Version: 0.5.4
  3
+Version: 0.6.0
4 4
 Summary: Ban IPs that make too many password failure
5 5
 Home-page: http://fail2ban.sourceforge.net
6 6
 Author: Cyril Jaquier
13  README
@@ -4,7 +4,7 @@
4 4
              |_| \__,_|_|_/___|_.__/\__,_|_||_|
5 5
 
6 6
 =============================================================
7  
-Fail2Ban (version 0.5.4)                           2005/09/13
  7
+Fail2Ban (version 0.6.0)                           2005/11/20
8 8
 =============================================================
9 9
 
10 10
 Fail2Ban scans log files like /var/log/pwdfail and bans IP
@@ -54,12 +54,12 @@ firewalls.
54 54
 Installation:
55 55
 -------------
56 56
 
57  
-Require: python-2.3 (http://www.python.org)
  57
+Require: python-2.4 (http://www.python.org)
58 58
 
59 59
 To install, just do:
60 60
 
61  
-> tar xvfj fail2ban-0.5.4.tar.bz2
62  
-> cd fail2ban-0.5.4
  61
+> tar xvfj fail2ban-0.6.0.tar.bz2
  62
+> cd fail2ban-0.6.0
63 63
 > python setup.py install
64 64
 
65 65
 This will install Fail2Ban into /usr/lib/fail2ban. The fail2ban
@@ -102,8 +102,9 @@ options:
102 102
   -h         display this help message
103 103
   -i <IP(s)> IP(s) to ignore
104 104
   -k         kill a currently running instance
105  
-  -r <VALUE> allow a max of VALUE password failure
106  
-  -t <TIME>  ban IP for TIME seconds
  105
+  -r <VALUE> allow a max of VALUE password failure [maxfailures]
  106
+  -t <TIME>  ban IP for TIME seconds [bantime]
  107
+  -f <TIME>  lifetime in seconds of failed entry [findtime]
107 108
   -v         verbose. Use twice for greater effect
108 109
   -V         print software version
109 110
 
11  TODO
@@ -4,7 +4,7 @@
4 4
              |_| \__,_|_|_/___|_.__/\__,_|_||_|
5 5
 
6 6
 =============================================================
7  
-ToDo
  7
+ToDo                                     $Revision: 1.5 $
8 8
 =============================================================
9 9
 
10 10
 See Feature Request Tracking System at SourceForge.net
@@ -12,3 +12,12 @@ See Feature Request Tracking System at SourceForge.net
12 12
 - improve installation process (better prefix support)
13 13
 - install Fail2ban into /usr/share
14 14
 - better configuration files
  15
+- add a check to see if the time of the log messages is
  16
+  correctly detected (valid regexp)
  17
+- split configuration files in /etc/fail2ban/services.d
  18
+  Example: /etc/fail2ban/services.d/apache
  19
+- template for common services in /etc/fail2ban/scripts.d
  20
+  Example: /etc/fail2ban/scripts.d/apache
  21
+- remove debug mode (root check)
  22
+- better return values in function
  23
+- use more email.Utils in mail.py
2  config/debian-initd
@@ -8,7 +8,7 @@
8 8
 #               Adjusted for Fail2Ban
9 9
 #                by Yaroslav Halchenko <debian@onerussian.com>.
10 10
 #
11  
-# Version:	$Id: debian-initd,v 1.1.2.2 2005/09/11 15:42:32 yarikoptic Exp $
  11
+# Version:	$Id: debian-initd,v 1.2 2005/11/20 17:07:47 lostcontrol Exp $
12 12
 #
13 13
 
14 14
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
53  config/fail2ban.conf.default
... ...
@@ -1,6 +1,6 @@
1 1
 # Fail2Ban configuration file
2 2
 #
3  
-# $Revision: 1.8.2.13 $
  3
+# $Revision: 1.9 $
4 4
 #
5 5
 # 2005.06.21  modified for readability  Iain Lea  iain@bricbrac.de
6 6
 
@@ -85,6 +85,21 @@ cmdend =
85 85
 #
86 86
 polltime = 1
87 87
 
  88
+# Option:  reinittime
  89
+# Notes.:  minimal number of seconds between the re-initialization of
  90
+#          firewalls due to external changes in their rules (see fwcheck)
  91
+# Values:  NUM  Default:  100
  92
+#
  93
+reinittime = 10
  94
+
  95
+# Option:  maxreinits
  96
+# Notes.:  maximal number of re-initialization of firewalls due to external
  97
+#          changes. -1 stays for infinite, so only reinittime is of importance
  98
+# Values:  NUM  Default:  -1
  99
+#
  100
+maxreinits = -1
  101
+
  102
+
88 103
 [MAIL]
89 104
 # Option:  enabled
90 105
 # Notes.:  enable mail notification when banning an IP address.
@@ -117,18 +132,26 @@ from = fail2ban
117 132
 #
118 133
 to = root
119 134
 
  135
+# Option:  localtime
  136
+# Notes.:  report local time (including timezone) or GMT
  137
+# Values:  [true | false]  Default:  false
  138
+#
  139
+localtime = true
  140
+
120 141
 # Option:  subject
121 142
 # Notes.:  subject of the e-mail.
122  
-# Tags:    <ip>  IP address
  143
+# Tags:    <section> active section (eg ssh, apache, etc)
  144
+#          <ip>  IP address
123 145
 #          <failures>  number of failures
124 146
 #          <failtime>  unix timestamp of the last failure
125  
-# Values:  TEXT  Default:  [Fail2Ban] Banned <ip>
  147
+# Values:  TEXT  Default:  [Fail2Ban] <section>: Banned <ip>
126 148
 #
127  
-subject = [Fail2Ban] Banned <ip>
  149
+subject = [Fail2Ban] <section>: Banned <ip>
128 150
 
129 151
 # Option:  message
130 152
 # Notes.:  message of the e-mail.
131  
-# Tags:    <ip>  IP address
  153
+# Tags:    <section> active section (eg ssh, apache, etc)
  154
+#          <ip>  IP address
132 155
 #          <failures>  number of failures
133 156
 #          <failtime>  unix timestamp of the last failure
134 157
 #          <br>  new line
@@ -136,7 +159,7 @@ subject = [Fail2Ban] Banned <ip>
136 159
 #
137 160
 message = Hi,<br>
138 161
           The IP <ip> has just been banned by Fail2Ban after
139  
-          <failures> attempts.<br>
  162
+          <failures> attempts against <section>.<br>
140 163
           Regards,<br>
141 164
           Fail2Ban
142 165
 
@@ -145,6 +168,7 @@ message = Hi,<br>
145 168
 # options: logfile, fwban, fwunban, timeregex, timepattern,
146 169
 # failregex.
147 170
 
  171
+
148 172
 [Apache]
149 173
 # Option:  enabled
150 174
 # Notes.:  enable monitoring for this section.
@@ -171,9 +195,15 @@ fwstart = iptables -N fail2ban-http
171 195
 # Values:  CMD  Default:
172 196
 #
173 197
 fwend = iptables -D INPUT -p tcp --dport http -j fail2ban-http
174  
-        iptables -D fail2ban-http -j RETURN
  198
+        iptables -F fail2ban-http
175 199
         iptables -X fail2ban-http
176 200
 
  201
+# Option:  fwcheck
  202
+# Notes.:  command executed once before each fwban command
  203
+# Values:  CMD  Default:
  204
+#
  205
+fwcheck = iptables -L INPUT | grep -q fail2ban-http
  206
+
177 207
 # Option:  fwban
178 208
 # Notes.:  command executed when banning an IP. Take care that the
179 209
 #          command is executed with Fail2Ban user rights.
@@ -217,6 +247,7 @@ timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
217 247
 #
218 248
 failregex = authentication failure|user .* not found
219 249
 
  250
+
220 251
 [SSH]
221 252
 # Option:  enabled
222 253
 # Notes.:  enable monitoring for this section.
@@ -243,9 +274,15 @@ fwstart = iptables -N fail2ban-ssh
243 274
 # Values:  CMD  Default:
244 275
 #
245 276
 fwend = iptables -D INPUT -p tcp --dport ssh -j fail2ban-ssh
246  
-        iptables -D fail2ban-ssh -j RETURN
  277
+        iptables -F fail2ban-ssh
247 278
         iptables -X fail2ban-ssh
248 279
 
  280
+# Option:  fwcheck
  281
+# Notes.:  command executed once before each fwban command
  282
+# Values:  CMD  Default:
  283
+#
  284
+fwcheck = iptables -L INPUT | grep -q fail2ban-ssh
  285
+
249 286
 # Option:  fwbanrule
250 287
 # Notes.:  command executed when banning an IP. Take care that the
251 288
 #          command is executed with Fail2Ban user rights.
2  config/gentoo-confd
@@ -16,7 +16,7 @@
16 16
 #
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.1.2.1 $
  19
+# $Revision: 1.2 $
20 20
 
21 21
 # Command line options for Fail2Ban. Refer to "fail2ban -h" for
22 22
 # valid options.
2  config/gentoo-initd
@@ -17,7 +17,7 @@
17 17
 #
18 18
 # Author: Sireyessire, Cyril Jaquier
19 19
 # 
20  
-# $Revision: 1.1.2.2 $
  20
+# $Revision: 1.2 $
21 21
 
22 22
 opts="start stop restart showlog"
23 23
 
2  config/redhat-initd
@@ -9,7 +9,7 @@
9 9
 #
10 10
 # Author: Andrey G. Grozin
11 11
 # 
12  
-# $Revision: 1.1.2.2 $
  12
+# $Revision: 1.2 $
13 13
 
14 14
 # Source function library.
15 15
 . /etc/init.d/functions
6  confreader/configreader.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.5.2.5 $
  19
+# $Revision: 1.6 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.5.2.5 $"
23  
-__date__ = "$Date: 2005/08/01 16:31:13 $"
  22
+__version__ = "$Revision: 1.6 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
12  fail2ban
@@ -18,11 +18,11 @@
18 18
 
19 19
 # Author: Cyril Jaquier
20 20
 # 
21  
-# $Revision: 1.4.2.5 $
  21
+# $Revision: 1.5 $
22 22
 
23 23
 __author__ = "Cyril Jaquier"
24  
-__version__ = "$Revision: 1.4.2.5 $"
25  
-__date__ = "$Date: 2005/08/04 20:51:14 $"
  24
+__version__ = "$Revision: 1.5 $"
  25
+__date__ = "$Date: 2005/11/20 17:07:47 $"
26 26
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
27 27
 __license__ = "GPL"
28 28
 
@@ -55,6 +55,12 @@ except Exception, e:
55 55
 	logSys.error("Type: " + `type.__name__` + "\n" +
56 56
 				 "Value: " + `e.args` + "\n" +
57 57
 				 "TB: " + `tbStack`)
  58
+	# Try to clean up after ourselves
  59
+	# just for extreme caution - wrapping with try
  60
+	try:
  61
+		fail2ban.restoreFwRules()
  62
+	except Exception:
  63
+		pass
58 64
 	# Remove the PID lock file. Should close #1239562
59 65
 	pidLock.remove()
60 66
 	logging.shutdown()
176  fail2ban.py
@@ -17,15 +17,15 @@
17 17
 # Author: Cyril Jaquier
18 18
 # Modified by: Yaroslav Halchenko (SYSLOG, findtime)
19 19
 # 
20  
-# $Revision: 1.20.2.18 $
  20
+# $Revision: 1.21 $
21 21
 
22 22
 __author__ = "Cyril Jaquier"
23  
-__version__ = "$Revision: 1.20.2.18 $"
24  
-__date__ = "$Date: 2005/09/13 20:42:33 $"
  23
+__version__ = "$Revision: 1.21 $"
  24
+__date__ = "$Date: 2005/11/20 17:07:47 $"
25 25
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
26 26
 __license__ = "GPL"
27 27
 
28  
-import time, sys, getopt, os, string, signal, logging, logging.handlers
  28
+import time, sys, getopt, os, string, signal, logging, logging.handlers, copy
29 29
 from ConfigParser import *
30 30
 
31 31
 from version import version
@@ -62,8 +62,9 @@ def dispUsage():
62 62
 	print "  -h         display this help message"
63 63
 	print "  -i <IP(s)> IP(s) to ignore"
64 64
 	print "  -k         kill a currently running instance"
65  
-	print "  -r <VALUE> allow a max of VALUE password failure"
66  
-	print "  -t <TIME>  ban IP for TIME seconds"
  65
+	print "  -r <VALUE> allow a max of VALUE password failure [maxfailures]"
  66
+	print "  -t <TIME>  ban IP for TIME seconds [bantime]"
  67
+	print "  -f <TIME>  lifetime in seconds of failed entry [findtime]"
67 68
 	print "  -v         verbose. Use twice for greater effect"
68 69
 	print "  -V         print software version"
69 70
 	print
@@ -92,19 +93,48 @@ def sigTERMhandler(signum, frame):
92 93
 	logSys.debug("Signal handler called with sig "+`signum`)
93 94
 	killApp()	
94 95
 
  96
+def setFwMustCheck(value):
  97
+	""" Set the mustCheck value of the firewalls (True/False)
  98
+	"""
  99
+	for element in logFwList:
  100
+		element[2].setMustCheck(value)
  101
+
  102
+def initializeFwRules():
  103
+	""" Initializes firewalls by running cmdstart and then
  104
+	    fwstart for each section
  105
+	"""
  106
+	# Execute global start command
  107
+	executeCmd(conf["cmdstart"], conf["debug"])
  108
+	# Execute start command of each section
  109
+	for element in logFwList:
  110
+		element[2].initialize(conf["debug"])
  111
+
  112
+def reBan():
  113
+	""" For each section asks the Firewall to reban known IPs
  114
+	"""
  115
+	for element in logFwList:
  116
+		element[2].reBan(conf["debug"])
  117
+
  118
+def restoreFwRules():
  119
+	""" Flush the ban list
  120
+	"""
  121
+	logSys.warn("Restoring firewall rules...")
  122
+	try:
  123
+		for element in logFwList:
  124
+			# Execute end command of each section
  125
+			element[2].restore(conf["debug"])
  126
+		# Execute global end command
  127
+		executeCmd(conf["cmdend"], conf["debug"])
  128
+	except ExternalError:
  129
+		# nothing bad really - we can survive :-)
  130
+		pass
  131
+
95 132
 def killApp():
96 133
 	""" Flush the ban list, remove the PID lock file and exit
97 134
 		nicely.
98 135
 	"""
99  
-	logSys.warn("Restoring firewall rules...")
100  
-	for element in logFwList:
101  
-		element[2].flushBanList(conf["debug"])
102  
-	# Execute end command of each section
103  
-	for element in logFwList:
104  
-		l = element[4]
105  
-		executeCmd(l["fwend"], conf["debug"])
106  
-	# Execute global start command
107  
-	executeCmd(conf["cmdend"], conf["debug"])
  136
+	# Restore Fw rules
  137
+	restoreFwRules()
108 138
 	# Remove the PID lock
109 139
 	pidLock.remove()
110 140
 	logSys.info("Exiting...")
@@ -127,6 +157,12 @@ def getCmdLineOptions(optList):
127 157
 			except ValueError:
128 158
 				logSys.warn("banTime must be an integer")
129 159
 				logSys.warn("Using default value")
  160
+		if opt[0] == "-f":
  161
+			try:
  162
+				conf["findtime"] = int(opt[1])
  163
+			except ValueError:
  164
+				logSys.warn("findTime must be an integer")
  165
+				logSys.warn("Using default value")
130 166
 		if opt[0] == "-i":
131 167
 			conf["ignoreip"] = opt[1]
132 168
 		if opt[0] == "-r":
@@ -149,6 +185,7 @@ def main():
149 185
 	formatter = logging.Formatter('%(asctime)s ' + formatterstring)
150 186
 	stdout.setFormatter(formatter)
151 187
 	
  188
+	conf["kill"] = False
152 189
 	conf["verbose"] = 0
153 190
 	conf["conffile"] = "/etc/fail2ban.conf"
154 191
 	
@@ -187,7 +224,9 @@ def main():
187 224
 					["str", "ignoreip", ""],
188 225
 					["int", "polltime", 1],
189 226
 					["str", "cmdstart", ""],
190  
-					["str", "cmdend", ""])
  227
+					["str", "cmdend", ""],
  228
+					["int", "reinittime", 100],
  229
+					["int", "maxreinits", 100])
191 230
 	
192 231
 	# Gets global configuration options
193 232
 	conf.update(confReader.getLogOptions("DEFAULT", optionValues))
@@ -199,8 +238,7 @@ def main():
199 238
 	pidLock.setPath(conf["pidlock"])
200 239
 	
201 240
 	# Now we can kill properly a running instance if needed
202  
-	try:
203  
-		conf["kill"]
  241
+	if conf["kill"]:
204 242
 		pid = pidLock.exists()
205 243
 		if pid:
206 244
 			killPID(int(pid))
@@ -209,8 +247,6 @@ def main():
209 247
 		else:
210 248
 			logSys.error("No running Fail2Ban found")
211 249
 			sys.exit(-1)
212  
-	except KeyError:
213  
-		pass
214 250
 
215 251
 	# Start Fail2Ban in daemon mode
216 252
 	if conf["background"]:
@@ -220,26 +256,8 @@ def main():
220 256
 			logSys.error("Unable to start daemon")
221 257
 			sys.exit(-1)
222 258
 
223  
-	# Verbose level
224  
-	if conf["verbose"]:
225  
-		logSys.warn("Verbose level is "+`conf["verbose"]`)
226  
-		if conf["verbose"] == 1:
227  
-			logSys.setLevel(logging.INFO)
228  
-		elif conf["verbose"] > 1:
229  
-			logSys.setLevel(logging.DEBUG)
230  
-		
231  
-	# Set debug log level
232  
-	if conf["debug"]:
233  
-		logSys.setLevel(logging.DEBUG)
234  
-		formatterstring = ('%(levelname)s: [%(filename)s (%(lineno)d)] ' +
235  
-						   '%(message)s')
236  
-		formatter = logging.Formatter("%(asctime)s " + formatterstring)
237  
-		stdout.setFormatter(formatter)
238  
-		logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " +
239  
-					"ONLY DISPLAYED IN THE LOG MESSAGES")
240  
-
241 259
 	# Process some options
242  
-	# Log targets
  260
+	# First setup Log targets
243 261
 	# Bug fix for #1234699
244 262
 	os.umask(0077)
245 263
 	for target in conf["logtargets"].split():
@@ -290,6 +308,24 @@ def main():
290 308
 		hdlr.setFormatter(tformatter)
291 309
 		logSys.addHandler(hdlr)
292 310
 	
  311
+	# Verbose level
  312
+	if conf["verbose"]:
  313
+		logSys.warn("Verbose level is "+`conf["verbose"]`)
  314
+		if conf["verbose"] == 1:
  315
+			logSys.setLevel(logging.INFO)
  316
+		elif conf["verbose"] > 1:
  317
+			logSys.setLevel(logging.DEBUG)
  318
+		
  319
+	# Set debug log level
  320
+	if conf["debug"]:
  321
+		logSys.setLevel(logging.DEBUG)
  322
+		formatterstring = ('%(levelname)s: [%(filename)s (%(lineno)d)] ' +
  323
+						   '%(message)s')
  324
+		formatter = logging.Formatter("%(asctime)s " + formatterstring)
  325
+		stdout.setFormatter(formatter)
  326
+		logSys.warn("DEBUG MODE: FIREWALL COMMANDS ARE _NOT_ EXECUTED BUT " +
  327
+					"ONLY DISPLAYED IN THE LOG MESSAGES")
  328
+	
293 329
 	# Ignores IP list
294 330
 	ignoreIPList = conf["ignoreip"].split(' ')
295 331
 
@@ -322,6 +358,7 @@ def main():
322 358
 					["int", "port", "25"],
323 359
 					["str", "from", "root"],
324 360
 					["str", "to", "root"],
  361
+					["bool", "localtime", False],
325 362
 					["str", "subject", "[Fail2Ban] Banned <ip>"],
326 363
 					["str", "message", "Fail2Ban notification"])
327 364
 	
@@ -334,6 +371,7 @@ def main():
334 371
 		mail = Mail(mailConf["host"], mailConf["port"])
335 372
 		mail.setFromAddr(mailConf["from"])
336 373
 		mail.setToAddr(mailConf["to"])
  374
+		mail.setLocalTimeFlag(mailConf["localtime"])
337 375
 		logSys.debug("to: " + mailConf["to"] + " from: " + mailConf["from"])
338 376
 	
339 377
 	# Options
@@ -348,8 +386,11 @@ def main():
348 386
 					["str", "fwstart", ""],
349 387
 					["str", "fwend", ""],
350 388
 					["str", "fwban", ""],
351  
-					["str", "fwunban", ""])
352  
-					
  389
+					["str", "fwunban", ""],
  390
+					["str", "fwcheck", ""])
  391
+	
  392
+	logSys.info("Fail2Ban v" + version + " is running")
  393
+	
353 394
 	# Gets the options of each sections
354 395
 	for t in confReader.getSections():
355 396
 		l = confReader.getLogOptions(t, optionValues)
@@ -358,7 +399,10 @@ def main():
358 399
 			lObj = LogReader(l["logfile"], l["timeregex"], l["timepattern"],
359 400
 							 l["failregex"], l["maxfailures"], l["findtime"])
360 401
 			# Creates a firewall object
361  
-			fObj = Firewall(l["fwban"], l["fwunban"], l["bantime"])
  402
+			fObj = Firewall(l["fwstart"], l["fwend"], l["fwban"], l["fwunban"],
  403
+							l["fwcheck"], l["bantime"])
  404
+			# "Name" the firewall
  405
+			fObj.setSection(t)
362 406
 			# Links them into a list. I'm not really happy
363 407
 			# with this :/
364 408
 			logFwList.append([t, lObj, fObj, dict(), l])
@@ -376,13 +420,10 @@ def main():
376 420
 		else:
377 421
 			logSys.warn(ip + " is not a valid IP address")
378 422
 	
379  
-	logSys.info("Fail2Ban v" + version + " is running")
380  
-	# Execute global start command
381  
-	executeCmd(conf["cmdstart"], conf["debug"])
382  
-	# Execute start command of each section
383  
-	for element in logFwList:
384  
-		l = element[4]
385  
-		executeCmd(l["fwstart"], conf["debug"])
  423
+	initializeFwRules()
  424
+	# try to reinit once if it fails immediately
  425
+	lastReinitTime = time.time() - conf["reinittime"] - 1
  426
+	reinits = 0
386 427
 	# Main loop
387 428
 	while True:
388 429
 		try:
@@ -429,7 +470,8 @@ def main():
429 470
 					if failTime < unixTime - findTime:
430 471
 						del element[3][attempt]
431 472
 					elif fails[attempt][0] >= element[1].getMaxRetry():
432  
-						aInfo = {"ip": attempt,
  473
+						aInfo = {"section": element[0],
  474
+								 "ip": attempt,
433 475
 								 "failures": element[3][attempt][0],
434 476
 								 "failtime": failTime}
435 477
 						logSys.info(element[0] + ": " + aInfo["ip"] +
@@ -441,7 +483,39 @@ def main():
441 483
 							mail.sendmail(mailConf["subject"],
442 484
 										  mailConf["message"], aInfo)
443 485
 						del element[3][attempt]
444  
-			
  486
+		except ExternalError, e:
  487
+			# Something wrong while dealing with Iptables.
  488
+			# May be chain got removed?
  489
+			reinits += 1
  490
+			logSys.error(e)
  491
+			if ((unixTime - lastReinitTime > conf["reinittime"]) and
  492
+				((conf["maxreinits"] < 0) or (reinits < conf["maxreinits"]))):
  493
+				logSys.warn("#%d reinitialization of firewalls"%reinits)
  494
+				lastReinitTime = unixTime
  495
+			else:
  496
+				logSys.error("Exiting: reinits follow too often, or too many " +
  497
+							 "reinit attempts")
  498
+				killApp()
  499
+			# We already failed runCheck so disable it until
  500
+			# restoring a safe state
  501
+			setFwMustCheck(False)
  502
+			# save firewalls to keep a list of IPs for rebanning
  503
+			logFwListCopy = copy.deepcopy(logFwList)
  504
+			try:
  505
+				# restore as much as possible
  506
+				restoreFwRules()
  507
+				# reinitialize all the chains
  508
+				initializeFwRules()
  509
+				# restore the lists of baned IPs
  510
+				logFwList.__init__(logFwListCopy)
  511
+				# reBan known IPs
  512
+				reBan()
  513
+				# Now we can enable the runCheck test again
  514
+				setFwMustCheck(True)
  515
+			except ExternalError:
  516
+				raise ExternalError("Big Oops happened: situation is out of " +
  517
+									"control. Something is wrong with your " +
  518
+									"setup. Please check your settings")
445 519
 		except KeyboardInterrupt:
446 520
 			# When the user press <ctrl>+<c> we exit nicely.
447 521
 			killApp()
92  firewall/firewall.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.8.2.6 $
  19
+# $Revision: 1.9 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.8.2.6 $"
23  
-__date__ = "$Date: 2005/08/01 16:31:42 $"
  22
+__version__ = "$Revision: 1.9 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
@@ -28,6 +28,10 @@
28 28
 
29 29
 from utils.process import executeCmd
30 30
 from utils.strings import replaceTag
  31
+# unfortunately but I have to bring ExternalError in especially for
  32
+# flushBanList: if one of IPs got flushed manually outside or something, we
  33
+# might endup with not "full" flush unless we handle exception within the loop
  34
+from utils.process import ExternalError
31 35
 
32 36
 # Gets the instance of the logger.
33 37
 logSys = logging.getLogger("fail2ban")
@@ -37,41 +41,102 @@ class Firewall:
37 41
 		the IP.
38 42
 	"""
39 43
 	
40  
-	def __init__(self, banRule, unBanRule, banTime):
  44
+	def __init__(self, startRule, endRule, banRule, unBanRule, checkRule,
  45
+				 banTime):
41 46
 		self.banRule = banRule
42 47
 		self.unBanRule = unBanRule
  48
+		self.checkRule = checkRule
  49
+		self.startRule = startRule
  50
+		self.endRule = endRule
43 51
 		self.banTime = banTime
44 52
 		self.banList = dict()
  53
+		self.section = ""
  54
+		self.mustCheck = True
  55
+
  56
+	def setSection(self, section):
  57
+		""" Set optional section name for clarify of logging
  58
+		"""
  59
+		self.section = section
  60
+		
  61
+	def getMustCheck(self):
  62
+		""" Return true if the runCheck test is executed
  63
+		"""
  64
+		return self.mustCheck
45 65
 	
  66
+	def setMustCheck(self, value):
  67
+		""" Enable or disable the execution of runCheck test
  68
+		"""
  69
+		self.mustCheck = value
  70
+
  71
+  	def initialize(self, debug):
  72
+		logSys.debug("%s: Initialize firewall rules"%self.section)
  73
+  		executeCmd(self.startRule, debug)
  74
+
  75
+	def restore(self, debug):
  76
+		logSys.debug("%s: Restore firewall rules"%self.section)
  77
+		try:
  78
+			self.flushBanList(debug)
  79
+			executeCmd(self.endRule, debug)
  80
+		except ExternalError:
  81
+			pass
  82
+
46 83
 	def addBanIP(self, aInfo, debug):
47 84
 		""" Bans an IP.
48 85
 		"""
49 86
 		ip = aInfo["ip"]
50 87
 		if not self.inBanList(ip):
51 88
 			crtTime = time.time()
52  
-			logSys.warn("Ban " + ip)
  89
+			logSys.warn("%s: Ban "%self.section + ip)
53 90
 			self.banList[ip] = crtTime
54 91
 			aInfo["bantime"] = crtTime
55  
-			executeCmd(self.banIP(aInfo), debug)
  92
+			self.runCheck(debug)
  93
+			cmd = self.banIP(aInfo)
  94
+			if executeCmd(cmd, debug):
  95
+				raise ExternalError("Firewall: execution of fwban command " +
  96
+									"'%s' failed"%cmd)
56 97
 		else:
57  
-			logSys.error(ip+" already in ban list")
  98
+			self.runCheck(debug)
  99
+			logSys.error("%s: "%self.section+ip+" already in ban list")
58 100
 	
59 101
 	def delBanIP(self, aInfo, debug):
60 102
 		""" Unban an IP.
61 103
 		"""
62 104
 		ip = aInfo["ip"]
63 105
 		if self.inBanList(ip):
64  
-			logSys.warn("Unban "+ip)
  106
+			logSys.warn("%s: Unban "%self.section + ip)
65 107
 			del self.banList[ip]
  108
+			self.runCheck(debug)
66 109
 			executeCmd(self.unBanIP(aInfo), debug)
67 110
 		else:
68  
-			logSys.error(ip+" not in ban list")
  111
+			logSys.error("%s: "%self.section+ip+" not in ban list")
  112
+
  113
+	def reBan(self, debug):
  114
+		""" Re-Bans known IPs.
  115
+			TODO: implement "failures" and "failtime"
  116
+		"""
  117
+		for ip in self.banList:
  118
+			aInfo = {"ip": ip,
  119
+					 "bantime":self.banList[ip]}
  120
+			logSys.warn("%s: ReBan "%self.section + ip)
  121
+			# next piece is similar to the on in addBanIp
  122
+			# so might be one more function will not hurt
  123
+			self.runCheck(debug)
  124
+			executeCmd(self.banIP(aInfo), debug)
69 125
 	
70 126
 	def inBanList(self, ip):
71 127
 		""" Checks if IP is in ban list.
72 128
 		"""
73 129
 		return self.banList.has_key(ip)
74  
-	
  130
+
  131
+	def runCheck(self, debug):
  132
+		""" Runs fwcheck command and throws an exception if it returns non-0
  133
+			result
  134
+		"""
  135
+		if self.mustCheck:
  136
+			executeCmd(self.checkRule, debug)
  137
+		else:
  138
+			return None
  139
+
75 140
 	def checkForUnBan(self, debug):
76 141
 		""" Check for IP to remove from ban list.
77 142
 		"""
@@ -93,7 +158,12 @@ def flushBanList(self, debug):
93 158
 			aInfo = {"ip": element[0],
94 159
 					 "bantime": element[1],
95 160
 					 "unbantime": time.time()}
96  
-			self.delBanIP(aInfo, debug)
  161
+			try:
  162
+				self.delBanIP(aInfo, debug)
  163
+			except ExternalError:
  164
+				# we must let it fail here in the loop, or we don't
  165
+				# flush properly
  166
+				pass
97 167
 			
98 168
 	def banIP(self, aInfo):
99 169
 		""" Returns query to ban IP.
18  logreader/logreader.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.13.2.8 $
  19
+# $Revision: 1.14 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.13.2.8 $"
23  
-__date__ = "$Date: 2005/09/05 21:06:15 $"
  22
+__version__ = "$Revision: 1.14 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
@@ -97,15 +97,15 @@ def isModified(self):
97 97
 		"""
98 98
 		try:
99 99
 			self.logStats = os.stat(self.logPath)
  100
+			if self.lastModTime == self.logStats.st_mtime:
  101
+				return False
  102
+			else:
  103
+				logSys.debug(self.logPath+" has been modified")
  104
+				self.lastModTime = self.logStats.st_mtime
  105
+				return True
100 106
 		except OSError:
101 107
 			logSys.error("Unable to get stat on "+self.logPath)
102  
-		
103  
-		if self.lastModTime == self.logStats.st_mtime:
104 108
 			return False
105  
-		else:
106  
-			logSys.debug(self.logPath+" has been modified")
107  
-			self.lastModTime = self.logStats.st_mtime
108  
-			return True
109 109
 	
110 110
 	def setFilePos(self, file):
111 111
 		""" Sets the file position. We must take care of log file rotation
7  man/fail2ban.8
@@ -33,10 +33,13 @@ display this help message
33 33
 kill a currently running Fail2Ban instance
34 34
 .TP 
35 35
 \fB\-r\fR \fIVALUE\fR
36  
-allow a max of \fIVALUE\fR password failure
  36
+allow a max of \fIVALUE\fR password failure [maxfailures]
37 37
 .TP 
38 38
 \fB\-t\fR \fITIME\fR
39  
-ban IP for \fITIME\fR seconds
  39
+ban IP for \fITIME\fR seconds [bantime]
  40
+.TP 
  41
+\fB\-f\fR \fITIME\fR
  42
+lifetime in seconds of failed entry [findtime]
40 43
 .TP 
41 44
 \fB\-v\fR
42 45
 verbose. Use twice for greater effect
6  setup.py
@@ -18,11 +18,11 @@
18 18
 
19 19
 # Author: Cyril Jaquier
20 20
 # 
21  
-# $Revision: 1.4.2.4 $
  21
+# $Revision: 1.5 $
22 22
 
23 23
 __author__ = "Cyril Jaquier"
24  
-__version__ = "$Revision: 1.4.2.4 $"
25  
-__date__ = "$Date: 2005/08/07 13:10:39 $"
  24
+__version__ = "$Revision: 1.5 $"
  25
+__date__ = "$Date: 2005/11/20 17:07:47 $"
26 26
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
27 27
 __license__ = "GPL"
28 28
 
6  utils/dns.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.7.2.3 $
  19
+# $Revision: 1.8 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.7.2.3 $"
23  
-__date__ = "$Date: 2005/08/17 19:26:49 $"
  22
+__version__ = "$Revision: 1.8 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
19  utils/mail.py
@@ -16,18 +16,17 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.1.2.4 $
  19
+# $Revision: 1.2 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.1.2.4 $"
23  
-__date__ = "$Date: 2005/09/12 14:42:08 $"
  22
+__version__ = "$Revision: 1.2 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
27  
-import logging, smtplib
  27
+import logging, smtplib, email.Utils
28 28
 
29 29
 from utils.strings import replaceTag
30  
-from time import strftime, gmtime
31 30
 
32 31
 # Gets the instance of the logger.
33 32
 logSys = logging.getLogger("fail2ban")
@@ -39,6 +38,7 @@ class Mail:
39 38
 	def __init__(self, host, port = 25):
40 39
 		self.host = host
41 40
 		self.port = port
  41
+		self.localTimeFlag = False
42 42
 		
43 43
 	def setFromAddr(self, fromAddr):
44 44
 		""" Set from: address
@@ -50,6 +50,11 @@ def setToAddr(self, toAddr):
50 50
 		"""
51 51
 		self.toAddr = toAddr.split()
52 52
 
  53
+	def setLocalTimeFlag(self, localTimeFlag):
  54
+		""" Set to: address
  55
+		"""
  56
+		self.localTimeFlag = localTimeFlag
  57
+
53 58
 	def sendmail(self, subject, message, aInfo):
54 59
 		""" Send an email using smtplib
55 60
 		"""
@@ -58,7 +63,7 @@ def sendmail(self, subject, message, aInfo):
58 63
 		
59 64
 		mail = ("From: %s\r\nTo: %s\r\nDate: %s\r\nSubject: %s\r\n\r\n" %
60 65
 				(self.fromAddr, ", ".join(self.toAddr),
61  
-				strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()),
  66
+				email.Utils.formatdate(localtime = self.localTimeFlag),
62 67
 				subj)) + msg
63 68
 		
64 69
 		try:
@@ -71,4 +76,4 @@ def sendmail(self, subject, message, aInfo):
71 76
 			logSys.error("Unable to send mail to " + self.host + ":" +
72 77
 						 `self.port` + " from " + self.fromAddr + " to " +
73 78
 						 `self.toAddr` + ": " + `e` + ": " + `e.args`)
74  
-		
  79
+		
9  utils/pidlock.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.1.2.2 $
  19
+# $Revision: 1.2 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.1.2.2 $"
23  
-__date__ = "$Date: 2005/08/07 13:08:18 $"
  22
+__version__ = "$Revision: 1.2 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
@@ -70,6 +70,9 @@ def remove(self):
70 70
 				logSys.debug("Removed PID lock " + self.path)
71 71
 			except OSError:
72 72
 				logSys.error("Unable to remove PID lock " + self.path)
  73
+			except AttributeError:
  74
+				# AttributeError if self.path wasn't specified yet
  75
+				logSys.debug("PID lock not removed because not defined yet")
73 76
 		
74 77
 		def exists(self):
75 78
 			""" Returns the current PID if Fail2Ban is running or False
12  utils/process.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.1.2.4 $
  19
+# $Revision: 1.2 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.1.2.4 $"
23  
-__date__ = "$Date: 2005/08/04 20:48:30 $"
  22
+__version__ = "$Revision: 1.2 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
@@ -29,6 +29,11 @@
29 29
 # Gets the instance of the logger.
30 30
 logSys = logging.getLogger("fail2ban")
31 31
 
  32
+class ExternalError(UserWarning):
  33
+	""" Exception to warn about failed fwcheck or fwban command
  34
+	"""
  35
+	pass
  36
+
32 37
 def createDaemon():
33 38
 	""" Detach a process from the controlling terminal and run it in the
34 39
 		background as a daemon.
@@ -126,6 +131,7 @@ def executeCmd(cmd, debug):
126 131
 		retval = os.system(cmd)
127 132
 		if not retval == 0:
128 133
 			logSys.error("'" + cmd + "' returned " + `retval`)
  134
+			raise ExternalError("Execution of command '%s' failed" % cmd)
129 135
 		return retval
130 136
 	else:
131 137
 		return None
6  utils/strings.py
@@ -16,11 +16,11 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.1.2.2 $
  19
+# $Revision: 1.2 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.1.2.2 $"
23  
-__date__ = "$Date: 2005/08/01 16:35:18 $"
  22
+__version__ = "$Revision: 1.2 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
8  version.py
@@ -16,12 +16,12 @@
16 16
 
17 17
 # Author: Cyril Jaquier
18 18
 # 
19  
-# $Revision: 1.12.2.10 $
  19
+# $Revision: 1.13 $
20 20
 
21 21
 __author__ = "Cyril Jaquier"
22  
-__version__ = "$Revision: 1.12.2.10 $"
23  
-__date__ = "$Date: 2005/09/13 20:43:00 $"
  22
+__version__ = "$Revision: 1.13 $"
  23
+__date__ = "$Date: 2005/11/20 17:07:47 $"
24 24
 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25 25
 __license__ = "GPL"
26 26
 
27  
-version = "0.5.4"
  27
+version = "0.6.0"

0 notes on commit ad466ec

Please sign in to comment.
Something went wrong with that request. Please try again.