Initial commit
Benjamin Renard

Benjamin Renard commited on 2014-12-31 15:04:38
Showing 4 changed files, with 252 additions and 0 deletions.

... ...
@@ -0,0 +1 @@
1
+*~
... ...
@@ -0,0 +1,35 @@
1
+Fail2ban action script to stock banned IP in a JSON file
2
+========================================================
3
+
4
+This script is design to be use as action script for fail2ban.
5
+
6
+Installation
7
+------------
8
+
9
+ - Put action.d/jsonfile.conf in /etc/fail2ban/action.d
10
+ - Put bin/fail2ban-jsonfile in /usr/local/bin/fail2ban-jsonfile
11
+
12
+Configuration
13
+-------------
14
+
15
+Jail example :
16
+
17
+  [myapp]
18
+  enabled  = true
19
+  filter   = myapp
20
+  action   = jsonfile[jsonpath=/var/tmp/myapp-banned-ip.json]
21
+  logpath  = /var/log/myapp.log
22
+
23
+Parameters :
24
+
25
+ - bin :
26
+   Specify the path to fail2ban-jsonfile script
27
+   Default : /usr/local/bin/fail2ban-jsonfile
28
+
29
+ - jsonpath :
30
+   The path of JSON file
31
+   Default : /tmp/fail2ban-jsonfile.json
32
+
33
+ - umask :
34
+   Umask use on JSON file creation (Integer)
35
+   Default : 0077
... ...
@@ -0,0 +1,66 @@
1
+# Fail2Ban configuration file
2
+#
3
+# Author: Benjamin Renard
4
+#
5
+# $Revision$
6
+#
7
+
8
+[Definition]
9
+
10
+# Option:  actionstart
11
+# Notes.:  command executed once at the start of Fail2Ban.
12
+# Values:  CMD
13
+#
14
+actionstart = <bin> -j <jsonpath> -a start -u <umask>
15
+
16
+# Option:  actionstop
17
+# Notes.:  command executed once at the end of Fail2Ban
18
+# Values:  CMD
19
+#
20
+actionstop = <bin> -j <jsonpath> -a stop
21
+
22
+# Option:  actioncheck
23
+# Notes.:  command executed once before each actionban command
24
+# Values:  CMD
25
+#
26
+
27
+# Option:  actionban
28
+# Notes.:  command executed when banning an IP. Take care that the
29
+#          command is executed with Fail2Ban user rights.
30
+# Tags:    <ip>  IP address
31
+#          <failures>  number of failures
32
+#          <time>  unix timestamp of the ban time
33
+# Values:  CMD
34
+#
35
+actionban = <bin> -j <jsonpath> -a ban -i "<ip>" -f "<failures>" -t "<time>" -u <umask>
36
+
37
+# Option:  actionunban
38
+# Notes.:  command executed when unbanning an IP. Take care that the
39
+#          command is executed with Fail2Ban user rights.
40
+# Tags:    <ip>  IP address
41
+#          <failures>  number of failures
42
+#          <time>  unix timestamp of the ban time
43
+# Values:  CMD
44
+#
45
+actionunban = <bin> -j <jsonpath> -a unban -i "<ip>" -u <umask>
46
+
47
+[Init]
48
+
49
+# Option:  bin
50
+# Note     Specify the path to fail2ban-jsonfile script
51
+#
52
+# Values:  Path to fail2ban-jsonfile script Default : /usr/local/bin/fail2ban-jsonfile
53
+bin = /usr/local/bin/fail2ban-jsonfile
54
+
55
+# Option:  jsonpath
56
+# Note     The path of JSON file
57
+#
58
+# Values:  Path to JSON file  Default : /tmp/fail2ban-jsonfile.json
59
+jsonpath = /tmp/fail2ban-jsonfile.json
60
+
61
+
62
+# Option:  umask
63
+# Note     Umask use on JSON file creation
64
+#
65
+# Values:  INTEGER (UMASK)  Default : 0077
66
+umask = 0077
... ...
@@ -0,0 +1,150 @@
1
+#!/usr/bin/python
2
+# -*- coding: utf-8 -*-
3
+
4
+import sys, os
5
+import json
6
+from optparse import OptionParser
7
+import logging
8
+
9
+parser = OptionParser()
10
+
11
+parser.add_option('-j',
12
+                  '--json',
13
+                  action="store",
14
+                  type="string",
15
+                  dest="jsonfile",
16
+                  help="JSON Storage file path")
17
+
18
+parser.add_option('-i',
19
+                  '--ip',
20
+                  action="store",
21
+                  type="string",
22
+                  dest="ip",
23
+                  help="IP address")
24
+
25
+parser.add_option('-a',
26
+                  '--action',
27
+                  action="store",
28
+                  type="string",
29
+                  dest="action",
30
+                  help="The action : start / stop / ban / unban / check")
31
+
32
+parser.add_option('-f',
33
+                  '--failures',
34
+                  action="store",
35
+                  type="string",
36
+                  dest="failures",
37
+                  help="The number of failures")
38
+
39
+parser.add_option('-t',
40
+                  '--time',
41
+                  action="store",
42
+                  type="string",
43
+                  dest="time",
44
+                  help="The unix timestamp of the ban time")
45
+
46
+parser.add_option('-l',
47
+                  '--log-file',
48
+                  action="store",
49
+                  type="string",
50
+                  dest="logfile",
51
+                  help="Log file path")
52
+
53
+parser.add_option('-u',
54
+                  '--umask',
55
+                  action="store",
56
+                  type="int",
57
+                  dest="umask",
58
+                  help="JSON file UMASK",
59
+		  default=0077)
60
+
61
+parser.add_option('-v',
62
+                  '--verbose',
63
+                  action="store_true",
64
+                  dest="verbose",
65
+                  help="Enable verbose mode")
66
+
67
+parser.add_option('-d',
68
+                  '--debug',
69
+                  action="store_true",
70
+                  dest="debug",
71
+                  help="Enable debug mode")
72
+
73
+(options, args) = parser.parse_args()
74
+
75
+logformat = '%(asctime)s - %(levelname)s - %(message)s'
76
+if options.debug:
77
+        loglevel = logging.DEBUG
78
+elif options.verbose:
79
+        loglevel = logging.INFO
80
+else:
81
+        loglevel = logging.WARNING
82
+
83
+if options.logfile:
84
+        logging.basicConfig(filename=options.logfile,level=loglevel,format=logformat)
85
+else:
86
+        logging.basicConfig(level=loglevel,format=logformat)
87
+
88
+if options.action is None or options.jsonfile is None:
89
+	logging.error('You must say what you want to do (-a) and the JSON file path (-j).')
90
+	sys.exit(1)
91
+
92
+if options.action in ['ban','unban','check'] and options.ip is None:
93
+	logging.error('You must provide the IP address')
94
+	sys.exit(1)
95
+
96
+def load_jsonfile(filepath):
97
+	try:
98
+		json_data = open(filepath)
99
+		data = json.load(json_data)
100
+		return data
101
+	except BaseException,e:
102
+		logging.warning('Fail to load JSON file, return empty hash (Error : %s)' % e)
103
+		return {}
104
+
105
+def write_jsonfile(filepath,data):
106
+	try:
107
+		os.umask(options.umask)
108
+		json_file = open(filepath, 'w')
109
+		json.dump(data,json_file)
110
+		return True
111
+	except BaseException,e:
112
+		logging.error('Fail to write JSON file : %s' % e)
113
+		return False
114
+
115
+if options.action=='start':
116
+	# Purge data in JSON file
117
+	if not write_jsonfile(options.jsonfile,{}):
118
+		logging.error("Fail to purge JSON file")
119
+		sys.exit(1)
120
+elif options.action=='stop':
121
+	# Remove JSON file
122
+	try:
123
+		os.unlink(options.jsonfile)
124
+	except BaseException,e:
125
+		logging.error('Fail to remove JSON file : %s' % e)
126
+		sys.exit(1)
127
+elif options.action=='ban':
128
+	data=load_jsonfile(options.jsonfile)
129
+	if options.ip not in data:
130
+		data[options.ip]={
131
+			'failures': options.failures,
132
+			'time': options.time
133
+		}
134
+		if not write_jsonfile(options.jsonfile,data):
135
+			sys.exit(1)
136
+elif options.action=='unban':
137
+	data=load_jsonfile(options.jsonfile)
138
+	if options.ip in data:
139
+		del data[options.ip]
140
+		if not write_jsonfile(options.jsonfile,data):
141
+			sys.exit(1)
142
+elif options.action=='check':
143
+	data=load_jsonfile(options.jsonfile)
144
+	if options.ip not in data:
145
+		sys.exit(1)
146
+else:
147
+	logging.error('Invalid action %s. Use -h parameter to get help.' % options.action)
148
+	sys.exit(1)
149
+
150
+sys.exit(0)
0 151