Initial commit
Benjamin Renard

Benjamin Renard commited on 2015-12-02 15:27:12
Showing 2 changed files, with 296 additions and 0 deletions.

... ...
@@ -0,0 +1,46 @@
1
+Nagios plugin to check SMTP Blacklist
2
+=====================================
3
+
4
+Usage
5
+-----
6
+
7
+  Usage: check_bl [options]
8
+  
9
+  Options:
10
+    -h, --help            show this help message and exit
11
+    -H HOST, --host=HOST  The host IP address to check
12
+    -B BL                 Blacklist server(s) (separated by commas)
13
+    -t TIMEOUT, --timeout=TIMEOUT
14
+                          Timeout in second for DNS request (Default : 10s)
15
+    -c CRITICAL_COUNT     Critical blacklisted count
16
+    -C CRITICAL_PERC      Critical blacklisted count as percentage (Default :
17
+                          30%)
18
+    -w WARNING_COUNT      Warning blacklisted count
19
+    -W WARNING_PERC       Warning blacklisted count as percentage (Default : 1%)
20
+    -u UNKNOWN_COUNT      Checking errors count triggering UNKNOWN status
21
+    -U UNKNOWN_PERC       Checking errors count as percentage triggering UNKNOWN
22
+                          status (Default : 50%)
23
+    -T, --threaded        Use thread for parallel checking
24
+    -v, --verbose         Enable verbose mode
25
+    -d, --debug           Enable debug mode
26
+
27
+Copyright
28
+---------
29
+
30
+Copyright (c) 2013 Benjamin Renard 
31
+
32
+License
33
+-------
34
+
35
+This program is free software; you can redistribute it and/or
36
+modify it under the terms of the GNU General Public License version 2
37
+as published by the Free Software Foundation.
38
+
39
+This program is distributed in the hope that it will be useful,
40
+but WITHOUT ANY WARRANTY; without even the implied warranty of
41
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42
+GNU General Public License for more details.
43
+
44
+You should have received a copy of the GNU General Public License
45
+along with this program; if not, write to the Free Software
46
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
... ...
@@ -0,0 +1,250 @@
1
+#!/usr/bin/python
2
+
3
+import dns.resolver
4
+import re
5
+import logging
6
+import sys
7
+from optparse import OptionParser
8
+
9
+parser = OptionParser()
10
+
11
+
12
+parser.add_option('-H',
13
+                  '--host',
14
+                  action="store",
15
+                  type="string",
16
+                  dest="host",
17
+                  help="The host IP address to check")
18
+
19
+parser.add_option('-B',
20
+                  action="store",
21
+                  type="string",
22
+                  dest="bl",
23
+                  help="Blacklist server(s) (separated by commas)")
24
+
25
+parser.add_option('-t', '--timeout',
26
+                  action="store",
27
+                  type="int",
28
+                  dest="timeout",
29
+                  help="Timeout in second for DNS request (Default : 10s)",
30
+                  default='10')
31
+
32
+parser.add_option('-c',
33
+                  action="store",
34
+                  type="int",
35
+                  dest="critical_count",
36
+                  help="Critical blacklisted count")
37
+
38
+parser.add_option('-C',
39
+                  action="store",
40
+                  type="int",
41
+                  dest="critical_perc",
42
+                  help="Critical blacklisted count as percentage (Default : 30%)",
43
+                  default=30)
44
+
45
+parser.add_option('-w',
46
+                  action="store",
47
+                  type="int",
48
+                  dest="warning_count",
49
+                  help="Warning blacklisted count")
50
+
51
+parser.add_option('-W',
52
+                  action="store",
53
+                  type="int",
54
+                  dest="warning_perc",
55
+                  help="Warning blacklisted count as percentage (Default : 1%)",
56
+                  default=1)
57
+
58
+parser.add_option('-u',
59
+                  action="store",
60
+                  type="int",
61
+                  dest="unknown_count",
62
+                  help="Checking errors count triggering UNKNOWN status")
63
+
64
+parser.add_option('-U',
65
+                  action="store",
66
+                  type="int",
67
+                  dest="unknown_perc",
68
+                  help="Checking errors count as percentage triggering UNKNOWN status (Default : 50%)",
69
+                  default=50)
70
+
71
+parser.add_option('-T',
72
+                  '--threaded',
73
+                  action="store_true",
74
+                  help="Use thread for parallel checking",
75
+                  dest="thread")
76
+
77
+parser.add_option('-v',
78
+                  '--verbose',
79
+                  action="store_true",
80
+                  help="Enable verbose mode",
81
+                  dest="verbose")
82
+
83
+parser.add_option('-d',
84
+                  '--debug',
85
+                  action="store_true",
86
+                  help="Enable debug mode",
87
+                  dest="debug")
88
+
89
+(options, args) = parser.parse_args()
90
+
91
+logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
92
+logger = logging.getLogger('BlChecker')
93
+
94
+if options.debug:
95
+        logger.setLevel(logging.DEBUG)
96
+elif options.verbose:
97
+        logger.setLevel(logging.INFO)
98
+else:
99
+        logger.setLevel(logging.WARNING)
100
+
101
+logger.debug('Start with parameters : %s' % options)
102
+
103
+# Check parameters
104
+if not options.host or not options.bl:
105
+	logger.error('You must provide host IP address and blacklist server(s)')
106
+	sys.exit(1)
107
+
108
+# Clean parameters
109
+options.host=options.host.strip()
110
+
111
+# Check method
112
+def check(ip,bl,logger=None,timeout=10):
113
+	m=re.match('([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})',ip)
114
+	if m:
115
+		resolver = dns.resolver.Resolver()
116
+		resolver.timeout = timeout
117
+		resolver.lifetime = timeout
118
+		lookup="%s.%s.%s.%s.%s" % (m.group(4),m.group(3),m.group(2),m.group(1),bl)
119
+		try:
120
+			r=resolver.query(lookup,'TXT')
121
+			logger.info('Listed on BL %s (%s)' % (bl,lookup))
122
+			return True
123
+		except dns.resolver.NXDOMAIN:
124
+			logger.debug('Not listed on BL %s' % bl)
125
+			return False
126
+		except dns.exception.Timeout:
127
+			logger.info('Timeout looking on BL %s (%s)' % (bl,lookup))
128
+		except Exception, e:
129
+			logger.warning('Error looking on BL %s (%s) : %s' % (bl,lookup,e))
130
+	else:
131
+		logger.error('Fail to parse IP address %s' % ip)
132
+	return -1
133
+
134
+
135
+# Split BL from args
136
+BLs=options.bl.split(',')
137
+BLs_count=len(BLs)
138
+
139
+logger.debug('BLs count : %s' % BLs_count)
140
+
141
+#### Check ####
142
+
143
+results={}
144
+
145
+if options.thread:
146
+	# Import lib
147
+	from threading import Thread
148
+
149
+	# Define Threader class
150
+	class BlChecker(Thread):
151
+
152
+		def __init__(self,ip,bl,timeout=10,logger=None):
153
+			Thread.__init__(self)
154
+			if logger:
155
+				self.logger=logger
156
+			else:
157
+				self.logger=logging.getLogger('BlChecker')
158
+
159
+			self.ip = ip
160
+			self.bl = bl
161
+			self.timeout = timeout
162
+		
163
+		def run(self):
164
+			results[bl]=check(self.ip,self.bl,logger=self.logger,timeout=self.timeout)
165
+
166
+
167
+	# Create and start a thread for check on all BL
168
+	threads=[]
169
+
170
+	for bl in BLs:
171
+		th=BlChecker(options.host,bl.strip(),timeout=options.timeout,logger=logger)
172
+		th.start()
173
+		threads.append(th)
174
+
175
+	# Wait all BL checks ended
176
+	for th in threads:
177
+		th.join()
178
+else:
179
+	for bl in BLs:
180
+		bl=bl.strip()
181
+		results[bl]=check(options.host,bl,timeout=options.timeout,logger=logger)
182
+
183
+# Check BL check result and determine listed/error counts
184
+listed=[]
185
+error=[]
186
+
187
+for bl in results:	
188
+	if results[bl] == -1:
189
+		error.append(bl)
190
+	elif results[bl]:
191
+		listed.append(bl)
192
+
193
+listed_count=len(listed)
194
+error_count=len(error)
195
+
196
+# Calculate thresholds
197
+if options.critical_count:
198
+	critical_count=options.critical_count
199
+else:
200
+	critical_count=int(round(BLs_count*options.critical_perc/100))
201
+	if critical_count==0:
202
+		critical_count=1
203
+
204
+if options.warning_count:
205
+	warning_count=options.warning_count
206
+else:
207
+	warning_count=int(round(BLs_count*options.warning_perc/100))
208
+	if warning_count==0:
209
+		warning_count=1
210
+
211
+if options.unknown_count:
212
+	unknown_count=options.unknown_count
213
+else:
214
+	unknown_count=int(round(BLs_count*options.unknown_perc/100))
215
+	if unknown_count==0:
216
+		unknown_count=1
217
+
218
+logger.debug('Max : CRITICAL = %s / WARNING = %s / UNKNOWN = %s' % (critical_count,warning_count,unknown_count))
219
+
220
+# Determine check result
221
+result='OK'
222
+result_code=0
223
+
224
+if listed_count>=critical_count:
225
+	result='CRITICAL'
226
+	result_code=2
227
+elif listed_count>=warning_count:
228
+	result='WARNING'
229
+	result_code=1
230
+elif error_count>=unknown_count:
231
+	result='UNKNOWN'
232
+	result_code=3
233
+
234
+# Compose return message
235
+if listed_count==0:
236
+	msg="%s : Not listed" % result
237
+else:
238
+	msg="%s : Listed on %s" % (result,', '.join(listed))
239
+
240
+if error_count>0:
241
+	msg+=", error checking blacklist(s) %s" % ', '.join(error)
242
+
243
+# Add performance data
244
+# (Syntax : 'label'=value[UOM];[warn];[crit];[min];[max])
245
+msg+="|listed=%d;%d;%d;%d;%d" % (listed_count,warning_count,critical_count,0,BLs_count)
246
+msg+=",check_errors=%d;%d;%d;%d;%d" % (error_count,warning_count,critical_count,0,BLs_count)
247
+
248
+# Print result and exit
249
+print msg
250
+sys.exit(result_code)
0 251