-
Notifications
You must be signed in to change notification settings - Fork 0
/
killbot.py
159 lines (135 loc) · 4.47 KB
/
killbot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from gevent import monkey
monkey.patch_all()
import sys
import sopel.module
from sopel.tools import stderr
import socket
import gevent
import dns.resolver
sys.path.append('/usr/local/lib/python2.7/site-packages')
from dnsbl import Base
#TODO gateway cloak support
blacklists = [
"dnsbl.dronebl.org",
"cbl.abuseat.org",
"http.dnsbl.sorbs.net",
"misc.dnsbl.sorbs.net",
"socks.dnsbl.sorbs.net",
"proxies.dnsbl.sorbs.net",
"tor.efnet.org",
"rbl.efnet.org",
"rbl.efnetrbl.org",
"torexit.dan.me.uk",
"tor.dnsbl.sectoor.de",
"xbl.spamhaus.org",
]
dnsResolver = None
def setup(bot):
global dnsResolver
dnsResolver = dns.resolver.Resolver()
@sopel.module.commands('host')
@sopel.module.priority('low')
@sopel.module.require_admin
@sopel.module.example('.host google.com')
def doManualLookup(bot, trigger):
if not trigger.sender == bot.config.killbot.control_channel:
return
else:
list = getIPList(trigger.group(2))
rep = " ".join(list)
bot.reply(rep)
@sopel.module.commands('rbl')
@sopel.module.priority('low')
@sopel.module.require_admin
@sopel.module.example('.rbl 8.8.8.8 or .rbl google.com')
def doRBLLookup(bot, trigger):
if not trigger.sender == bot.config.killbot.control_channel:
return
else:
checkResults = baseRBLLookup(trigger.group(2))
rep = ""
for r in checkResults:
if r[1] != False:
if r[1] != None:
rep += "HIT: %s %s " % (r[0], r[1])
if rep == "":
rep = "No hits"
bot.reply(rep)
@sopel.module.event('JOIN')
@sopel.module.rule('.*')
@sopel.module.priority('high')
def processJoin(bot, trigger):
ips = getIPList(trigger.host)
for ip in ips:
bot.msg(bot.config.killbot.control_channel, 'doing lookup on %s' % ip)
blResult = baseRBLLookup(ip)
ban = False
why = ''
for r in blResult:
stderr(r)
if r[1] != False:
if r[1] != None:
ban = True
why += "HIT: %s %s " % (r[0], r[1])
if ban == True:
if trigger.sender == '##politics':
bot.write(['MODE', trigger.sender, '+b', '*!*@' + trigger.host])
bot.write(['REMOVE', trigger.sender, trigger.nick], "This host has violated channel policy.")
bot.msg(bot.config.killbot.control_channel, 'I would have banned %s on %s because of a blacklist hit.' % (trigger.nick, trigger.sender))
bot.msg(bot.config.killbot.control_channel, why)
else:
bot.msg(bot.config.killbot.control_channel, '%s is clean.' % trigger.host)
def baseRBLLookup(ip):
backend = Base(ip=ip, providers=blacklists, timeout=10)
return backend.check()
def getIPList(hostname):
#takes a hostname or ip address, returns list containing
#ip addresses that hostname resolves to, or original ip address
#always returns a list
ipList = []
if hostname.find('/') != -1:
#this is a cloak, dns lookups don't matter
return ipList
if validateIP(hostname) == True:
ipList.append('%s' % hostname)
return ipList
else:
stderr('resolving %s' % hostname)
try:
ipv4 = dnsResolver.query(hostname,'A')
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
ipv4 = []
try:
ipv6 = dnsResolver.query(hostname,'AAAA')
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
ipv6 = []
for a in ipv4:
stderr(' resolved A record to %s' % a)
ipList.append('%s' % a)
for aaaa in ipv6:
stderr(' resolved AAAA record to %s' % aaaa)
ipList.append('%s' % aaaa)
return ipList
#for some reason we couldn't find anything
stderr('getIPList fell through for %s' % hostname)
return ipList
def validateIP(address):
return validateIPV4(address) or validateIPV6(address)
def validateIPV4(address):
try:
socket.inet_pton(socket.AF_INET, address)
except AttributeError:
try:
socket.inet_aton(address)
except socket.error:
return False
return address.count('.') == 3
except socket.error:
return False
return True
def validateIPV6(address):
try:
socket.inet_pton(socket.AF_INET6, address)
except socket.error:
return False
return True