+

Last commit for check_bl: 1665b1e10062df3578493b29b3953c2418100b34

Add ability to resolv host parameter

Benjamin Renard [2015-12-02 16:00:28]
Add ability to resolv host parameter
#!/usr/bin/python

import dns.resolver
import re
import logging
import sys
from optparse import OptionParser

parser = OptionParser()


parser.add_option('-H',
                  '--host',
                  action="store",
                  type="string",
                  dest="host",
                  help="The host IP address to check")

parser.add_option('-B',
                  action="store",
                  type="string",
                  dest="bl",
                  help="Blacklist server(s) (separated by commas)")

parser.add_option('-t', '--timeout',
                  action="store",
                  type="int",
                  dest="timeout",
                  help="Timeout in second for DNS request (Default : 10s)",
                  default='10')

parser.add_option('-c',
                  action="store",
                  type="int",
                  dest="critical_count",
                  help="Critical blacklisted count")

parser.add_option('-C',
                  action="store",
                  type="int",
                  dest="critical_perc",
                  help="Critical blacklisted count as percentage (Default : 30%)",
                  default=30)

parser.add_option('-w',
                  action="store",
                  type="int",
                  dest="warning_count",
                  help="Warning blacklisted count")

parser.add_option('-W',
                  action="store",
                  type="int",
                  dest="warning_perc",
                  help="Warning blacklisted count as percentage (Default : 1%)",
                  default=1)

parser.add_option('-u',
                  action="store",
                  type="int",
                  dest="unknown_count",
                  help="Checking errors count triggering UNKNOWN status")

parser.add_option('-U',
                  action="store",
                  type="int",
                  dest="unknown_perc",
                  help="Checking errors count as percentage triggering UNKNOWN status (Default : 50%)",
                  default=50)

parser.add_option('-T',
                  '--threaded',
                  action="store_true",
                  help="Use thread for parallel checking",
                  dest="thread")

parser.add_option('-v',
                  '--verbose',
                  action="store_true",
                  help="Enable verbose mode",
                  dest="verbose")

parser.add_option('-d',
                  '--debug',
                  action="store_true",
                  help="Enable debug mode",
                  dest="debug")

(options, args) = parser.parse_args()

logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logger = logging.getLogger('BlChecker')

if options.debug:
        logger.setLevel(logging.DEBUG)
elif options.verbose:
        logger.setLevel(logging.INFO)
else:
        logger.setLevel(logging.WARNING)

logger.debug('Start with parameters : %s' % options)

# Check parameters
if not options.host or not options.bl:
	logger.error('You must provide host IP address and blacklist server(s)')
	sys.exit(3)

options.host=options.host.strip()

def parseIP(ip):
	return re.match('([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})',ip)

parsed_ip=parseIP(options.host)

if not parsed_ip:
	logger.debug('Host parameter is not a valid IP address, try to resolv it as DNS name')
	try:
		import socket
		res=socket.gethostbyname_ex(options.host)
		logger.debug('gethostbyname_ex() result : %s' % str(res))
		ip=res[2][0]
		parsed_ip=parseIP(ip)
		if not parsed_ip:
			raise Exception('Fail to parse resolved IP %s address on name %s' % (ip,options.host))
		logger.info('Resolved IP address corresponding to %s : %s' % (options.host,ip))
	except socket.gaierror:
		logger.error('Invalid host parameter (-H)')
		sys.exit(3)
	except Exception, e:
		logger.error('Error resolving name %s : %s' % (options.host,e))
		sys.exit(3)

# Check method
def check(parsed_ip,bl,logger=None,timeout=10):
	resolver = dns.resolver.Resolver()
	resolver.timeout = timeout
	resolver.lifetime = timeout
	lookup="%s.%s.%s.%s.%s" % (parsed_ip.group(4),parsed_ip.group(3),parsed_ip.group(2),parsed_ip.group(1),bl)
	try:
		r=resolver.query(lookup,'TXT')
		logger.info('Listed on BL %s (%s)' % (bl,lookup))
		return True
	except dns.resolver.NXDOMAIN:
		logger.debug('Not listed on BL %s' % bl)
		return False
	except dns.exception.Timeout:
		logger.info('Timeout looking on BL %s (%s)' % (bl,lookup))
	except Exception, e:
		logger.warning('Error looking on BL %s (%s) : %s' % (bl,lookup,e))


# Split BL from args
BLs=options.bl.split(',')
BLs_count=len(BLs)

logger.debug('BLs count : %s' % BLs_count)

#### Check ####

results={}

if options.thread:
	# Import lib
	from threading import Thread

	# Define Threader class
	class BlChecker(Thread):

		def __init__(self,parsed_ip,bl,timeout=10,logger=None):
			Thread.__init__(self)
			if logger:
				self.logger=logger
			else:
				self.logger=logging.getLogger('BlChecker')

			self.parsed_ip = parsed_ip
			self.bl = bl
			self.timeout = timeout

		def run(self):
			results[bl]=check(self.parsed_ip,self.bl,logger=self.logger,timeout=self.timeout)


	# Create and start a thread for check on all BL
	threads=[]

	for bl in BLs:
		th=BlChecker(parsed_ip,bl.strip(),timeout=options.timeout,logger=logger)
		th.start()
		threads.append(th)

	# Wait all BL checks ended
	for th in threads:
		th.join()
else:
	for bl in BLs:
		bl=bl.strip()
		results[bl]=check(parsed_ip,bl,timeout=options.timeout,logger=logger)

# Check BL check result and determine listed/error counts
listed=[]
error=[]

for bl in results:
	if results[bl] == -1:
		error.append(bl)
	elif results[bl]:
		listed.append(bl)

listed_count=len(listed)
error_count=len(error)

# Calculate thresholds
if options.critical_count:
	critical_count=options.critical_count
else:
	critical_count=int(round(BLs_count*options.critical_perc/100))
	if critical_count==0:
		critical_count=1

if options.warning_count:
	warning_count=options.warning_count
else:
	warning_count=int(round(BLs_count*options.warning_perc/100))
	if warning_count==0:
		warning_count=1

if options.unknown_count:
	unknown_count=options.unknown_count
else:
	unknown_count=int(round(BLs_count*options.unknown_perc/100))
	if unknown_count==0:
		unknown_count=1

logger.debug('Max : CRITICAL = %s / WARNING = %s / UNKNOWN = %s' % (critical_count,warning_count,unknown_count))

# Determine check result
result='OK'
result_code=0

if listed_count>=critical_count:
	result='CRITICAL'
	result_code=2
elif listed_count>=warning_count:
	result='WARNING'
	result_code=1
elif error_count>=unknown_count:
	result='UNKNOWN'
	result_code=3

# Compose return message
if listed_count==0:
	msg="%s : Not listed" % result
else:
	msg="%s : Listed on %s" % (result,', '.join(listed))

if error_count>0:
	msg+=", error checking blacklist(s) %s" % ', '.join(error)

# Add performance data
# (Syntax : 'label'=value[UOM];[warn];[crit];[min];[max])
msg+="|listed=%d;%d;%d;%d;%d" % (listed_count,warning_count,critical_count,0,BLs_count)
msg+=",check_errors=%d;%d;%d;%d;%d" % (error_count,warning_count,critical_count,0,BLs_count)

# Print result and exit
print msg
sys.exit(result_code)
ViewGit