| 1 | #! /usr/bin/env python |
|---|
| 2 | # |
|---|
| 3 | # This is a multi-threaded RBL lookup check for Icinga / Nagios. |
|---|
| 4 | # Copyright (C) 2012 Frode Egeland <egeland[at]gmail.com> |
|---|
| 5 | # |
|---|
| 6 | # Modified by Kumina bv in 2013. We only added an option to use an |
|---|
| 7 | # address instead of a hostname. |
|---|
| 8 | # |
|---|
| 9 | # Modified by Guillaume Subiron (Sysnove) in 2015 : mainly PEP8 |
|---|
| 10 | # |
|---|
| 11 | # This program is free software: you can redistribute it and/or modify |
|---|
| 12 | # it under the terms of the GNU General Public License as published by |
|---|
| 13 | # the Free Software Foundation, either version 3 of the License, or |
|---|
| 14 | # (at your option) any later version. |
|---|
| 15 | # |
|---|
| 16 | # This program is distributed in the hope that it will be useful, |
|---|
| 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 19 | # GNU General Public License for more details. |
|---|
| 20 | # |
|---|
| 21 | # You should have received a copy of the GNU General Public License |
|---|
| 22 | # along with this program. If not, see <http://www.gnu.org/licenses/> |
|---|
| 23 | # |
|---|
| 24 | # Downloaded from https://raw.githubusercontent.com/egeland/nagios-rbl-check/master/check_rbl.py |
|---|
| 25 | # on 2016-02-20 by adehnert |
|---|
| 26 | |
|---|
| 27 | import sys |
|---|
| 28 | import os |
|---|
| 29 | import getopt |
|---|
| 30 | import socket |
|---|
| 31 | import string |
|---|
| 32 | |
|---|
| 33 | rv = (2, 6) |
|---|
| 34 | if rv >= sys.version_info: |
|---|
| 35 | print "ERROR: Requires Python 2.6 or greater" |
|---|
| 36 | sys.exit(3) |
|---|
| 37 | |
|---|
| 38 | import Queue |
|---|
| 39 | import threading |
|---|
| 40 | |
|---|
| 41 | serverlist = [ |
|---|
| 42 | "truncate.gbudb.net", |
|---|
| 43 | "bad.psky.me", |
|---|
| 44 | "0spam.fusionzero.com", |
|---|
| 45 | "access.redhawk.org", |
|---|
| 46 | "b.barracudacentral.org", |
|---|
| 47 | "bhnc.njabl.org", |
|---|
| 48 | "bl.deadbeef.com", |
|---|
| 49 | "bl.spamcannibal.org", |
|---|
| 50 | "bl.spamcop.net", |
|---|
| 51 | "bl.technovision.dk", |
|---|
| 52 | "blackholes.five-ten-sg.com", |
|---|
| 53 | "blackholes.mail-abuse.org", |
|---|
| 54 | "blacklist.sci.kun.nl", |
|---|
| 55 | "blacklist.woody.ch", |
|---|
| 56 | "bogons.cymru.com", |
|---|
| 57 | "cbl.abuseat.org", |
|---|
| 58 | "cdl.anti-spam.org.cn", |
|---|
| 59 | "combined.abuse.ch", |
|---|
| 60 | "combined.rbl.msrbl.net", |
|---|
| 61 | "db.wpbl.info", |
|---|
| 62 | "dnsbl-1.uceprotect.net", |
|---|
| 63 | "dnsbl-2.uceprotect.net", |
|---|
| 64 | "dnsbl-3.uceprotect.net", |
|---|
| 65 | "dnsbl.cyberlogic.net", |
|---|
| 66 | "dnsbl.inps.de", |
|---|
| 67 | "dnsbl.kempt.net", |
|---|
| 68 | "dnsbl.njabl.org", |
|---|
| 69 | "dnsbl.solid.net", |
|---|
| 70 | "dnsbl.sorbs.net", |
|---|
| 71 | "drone.abuse.ch", |
|---|
| 72 | "duinv.aupads.org", |
|---|
| 73 | "dul.ru", |
|---|
| 74 | "dyna.spamrats.com", |
|---|
| 75 | "dynip.rothen.com", |
|---|
| 76 | "forbidden.icm.edu.pl", |
|---|
| 77 | "hil.habeas.com", |
|---|
| 78 | "images.rbl.msrbl.net", |
|---|
| 79 | "ips.backscatterer.org", |
|---|
| 80 | "ix.dnsbl.manitu.net", |
|---|
| 81 | "korea.services.net", |
|---|
| 82 | "mail-abuse.blacklist.jippg.org", |
|---|
| 83 | "no-more-funn.moensted.dk", |
|---|
| 84 | "noptr.spamrats.com", |
|---|
| 85 | "ohps.dnsbl.net.au", |
|---|
| 86 | "omrs.dnsbl.net.au", |
|---|
| 87 | "orvedb.aupads.org", |
|---|
| 88 | "osps.dnsbl.net.au", |
|---|
| 89 | "osrs.dnsbl.net.au", |
|---|
| 90 | "owfs.dnsbl.net.au", |
|---|
| 91 | "owps.dnsbl.net.au", |
|---|
| 92 | "phishing.rbl.msrbl.net", |
|---|
| 93 | "probes.dnsbl.net.au", |
|---|
| 94 | "proxy.bl.gweep.ca", |
|---|
| 95 | "proxy.block.transip.nl", |
|---|
| 96 | "psbl.surriel.com", |
|---|
| 97 | "rbl.interserver.net", |
|---|
| 98 | "rbl.orbitrbl.com", |
|---|
| 99 | "rbl.schulte.org", |
|---|
| 100 | "rdts.dnsbl.net.au", |
|---|
| 101 | "relays.bl.gweep.ca", |
|---|
| 102 | "relays.bl.kundenserver.de", |
|---|
| 103 | "relays.nether.net", |
|---|
| 104 | "residential.block.transip.nl", |
|---|
| 105 | "ricn.dnsbl.net.au", |
|---|
| 106 | "rmst.dnsbl.net.au", |
|---|
| 107 | "short.rbl.jp", |
|---|
| 108 | "spam.abuse.ch", |
|---|
| 109 | "spam.dnsbl.sorbs.net", |
|---|
| 110 | "spam.rbl.msrbl.net", |
|---|
| 111 | "spam.spamrats.com", |
|---|
| 112 | "spamguard.leadmon.net", |
|---|
| 113 | "spamlist.or.kr", |
|---|
| 114 | "spamrbl.imp.ch", |
|---|
| 115 | "spamsources.fabel.dk", |
|---|
| 116 | "spamtrap.drbl.drand.net", |
|---|
| 117 | "t3direct.dnsbl.net.au", |
|---|
| 118 | "tor.dnsbl.sectoor.de", |
|---|
| 119 | "torserver.tor.dnsbl.sectoor.de", |
|---|
| 120 | "ubl.lashback.com", |
|---|
| 121 | "ubl.unsubscore.com", |
|---|
| 122 | "virbl.bit.nl", |
|---|
| 123 | "virus.rbl.jp", |
|---|
| 124 | "virus.rbl.msrbl.net", |
|---|
| 125 | "wormrbl.imp.ch", |
|---|
| 126 | "zen.spamhaus.org", |
|---|
| 127 | ] |
|---|
| 128 | |
|---|
| 129 | #### |
|---|
| 130 | |
|---|
| 131 | queue = Queue.Queue() |
|---|
| 132 | global on_blacklist |
|---|
| 133 | on_blacklist = [] |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | class ThreadRBL(threading.Thread): |
|---|
| 137 | def __init__(self, queue): |
|---|
| 138 | threading.Thread.__init__(self) |
|---|
| 139 | self.queue = queue |
|---|
| 140 | |
|---|
| 141 | def run(self): |
|---|
| 142 | while True: |
|---|
| 143 | # grabs host from queue |
|---|
| 144 | hostname, root_name = self.queue.get() |
|---|
| 145 | |
|---|
| 146 | check_host = "%s.%s" % (hostname, root_name) |
|---|
| 147 | try: |
|---|
| 148 | check_addr = socket.gethostbyname(check_host) |
|---|
| 149 | except socket.error: |
|---|
| 150 | check_addr = None |
|---|
| 151 | if check_addr is not None and "127.0.0." in check_addr: |
|---|
| 152 | on_blacklist.append(root_name) |
|---|
| 153 | |
|---|
| 154 | # signals to queue job is done |
|---|
| 155 | self.queue.task_done() |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | def usage(argv0): |
|---|
| 159 | print "%s -w <WARN level> -c <CRIT level> -h <hostname>" % argv0 |
|---|
| 160 | print " or" |
|---|
| 161 | print "%s -w <WARN level> -c <CRIT level> -a <ipv4 address>" % argv0 |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | def main(argv, environ): |
|---|
| 165 | options, remainder = getopt.getopt(argv[1:], |
|---|
| 166 | "w:c:h:a:", |
|---|
| 167 | ["warn=", "crit=", "host=", "address="]) |
|---|
| 168 | status = {'OK': 0, 'WARNING': 1, 'CRITICAL': 2, 'UNKNOWN': 3} |
|---|
| 169 | host = None |
|---|
| 170 | addr = None |
|---|
| 171 | |
|---|
| 172 | if 3 != len(options): |
|---|
| 173 | usage(argv[0]) |
|---|
| 174 | sys.exit(status['UNKNOWN']) |
|---|
| 175 | |
|---|
| 176 | for field, val in options: |
|---|
| 177 | if field in ('-w', '--warn'): |
|---|
| 178 | warn_limit = int(val) |
|---|
| 179 | elif field in ('-c', '--crit'): |
|---|
| 180 | crit_limit = int(val) |
|---|
| 181 | elif field in ('-h', '--host'): |
|---|
| 182 | host = val |
|---|
| 183 | elif field in ('-a', '--address'): |
|---|
| 184 | addr = val |
|---|
| 185 | else: |
|---|
| 186 | usage(argv[0]) |
|---|
| 187 | sys.exit(status['UNKNOWN']) |
|---|
| 188 | |
|---|
| 189 | if host and addr: |
|---|
| 190 | print "ERROR: Cannot use both host and address, choose one." |
|---|
| 191 | sys.exit(status['UNKNOWN']) |
|---|
| 192 | |
|---|
| 193 | if host: |
|---|
| 194 | try: |
|---|
| 195 | addr = socket.gethostbyname(host) |
|---|
| 196 | except: |
|---|
| 197 | print "ERROR: Host '%s' not found - maybe try a FQDN?" % host |
|---|
| 198 | sys.exit(status['UNKNOWN']) |
|---|
| 199 | addr_parts = string.split(addr, '.') |
|---|
| 200 | addr_parts.reverse() |
|---|
| 201 | check_name = string.join(addr_parts, '.') |
|---|
| 202 | # We set this to make sure the output is nice. It's not used except for the output after this point. |
|---|
| 203 | host = addr |
|---|
| 204 | |
|---|
| 205 | # ##### Thread stuff: |
|---|
| 206 | |
|---|
| 207 | # spawn a pool of threads, and pass them queue instance |
|---|
| 208 | for i in range(10): |
|---|
| 209 | t = ThreadRBL(queue) |
|---|
| 210 | t.setDaemon(True) |
|---|
| 211 | t.start() |
|---|
| 212 | |
|---|
| 213 | # populate queue with data |
|---|
| 214 | for blhost in serverlist: |
|---|
| 215 | queue.put((check_name, blhost)) |
|---|
| 216 | |
|---|
| 217 | # wait on the queue until everything has been processed |
|---|
| 218 | queue.join() |
|---|
| 219 | |
|---|
| 220 | # ##### End Thread stuff |
|---|
| 221 | |
|---|
| 222 | if on_blacklist: |
|---|
| 223 | output = '%s on %s spam blacklists : %s' % (host, |
|---|
| 224 | len(on_blacklist), |
|---|
| 225 | ', '.join(on_blacklist)) |
|---|
| 226 | if len(on_blacklist) >= crit_limit: |
|---|
| 227 | print 'CRITICAL: %s' % output |
|---|
| 228 | sys.exit(status['CRITICAL']) |
|---|
| 229 | if len(on_blacklist) >= warn_limit: |
|---|
| 230 | print 'WARNING: %s' % output |
|---|
| 231 | sys.exit(status['WARNING']) |
|---|
| 232 | else: |
|---|
| 233 | print 'OK: %s' % output |
|---|
| 234 | sys.exit(status['OK']) |
|---|
| 235 | else: |
|---|
| 236 | print 'OK: %s not on known spam blacklists' % host |
|---|
| 237 | sys.exit(status['OK']) |
|---|
| 238 | |
|---|
| 239 | |
|---|
| 240 | if __name__ == "__main__": |
|---|
| 241 | main(sys.argv, os.environ) |
|---|