6
the bot has the capability to listen for udp packets which it will use
7
to /msg a given nick or channel.
11
* do !reload udp to enable the udp plugin
12
* call !udp-cfgsave to generate a config file in gozerdata/plugs/udp/config
13
* edit this file .. esp. look at the udpallowednicks list
14
* run ./bin/gozerbot-udp -s to generate clientside config file "udp-send"
20
echo "YOOO" | ./bin/gozerbot-udp
24
on IRC the bot's /msg to a user/channel are limited to 1 per 3 seconds so the
25
bot will not excessflood on the server. you can use partyudp if you need no
26
delay between sent messages, this will use dcc chat to deliver the message.
27
on jabber bots there is no delay
32
__copyright__ = 'this file is in the public domain'
36
from gozerbot.fleet import fleet
37
from gozerbot.generic import rlog, handle_exception, strippedtxt, lockdec
38
from gozerbot.config import config
39
from gozerbot.plughelp import plughelp
40
from gozerbot.partyline import partyline
41
from gozerbot.threads.thr import start_new_thread
42
from gozerbot.contrib.rijndael import rijndael
43
from gozerbot.persist.persistconfig import PersistConfig
45
import socket, re, time, Queue
49
plughelp.add('udp' , 'run the udp listen thread')
54
cfg.define('udp', 1) # set to 0 to disnable
55
cfg.define('udpparty', 0)
56
cfg.define('udpipv6', 0)
57
cfg.define('udpmasks', ['192.168*', ])
58
cfg.define('udphost', "localhost")
59
cfg.define('udpport', 5500)
60
cfg.define('udpallow', ["127.0.0.1", ])
61
cfg.define('udpallowednicks', ["#gozerbot", "dunker"])
62
cfg.define('udppassword', "mekker", exposed=False)
63
cfg.define('udpseed', "blablablablablaz", exposed=False) # needs to be 16 chars wide
64
cfg.define('udpstrip', 1) # strip all chars < char(32)
65
cfg.define('udpsleep', 0) # sleep in sendloop .. can be used to delay pack
66
cfg.define('udpdblog', 0)
67
cfg.define('udpbots', [cfg['udpbot'] or 'default', ])
73
""" check if addr matches a mask. """
75
if not cfg['udpmasks']:
77
for i in cfg['udpmasks']:
78
i = i.replace('*', '.*')
82
class Udplistener(object):
85
listen for udp messages.
90
self.outqueue = Queue.Queue()
91
self.queue = Queue.Queue()
94
self.sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
96
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
97
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
99
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
102
self.sock.setblocking(1)
103
self.sock.settimeout(1)
109
loop controling the rate of outputted messages.
111
.. literalinclude:: ../../gozerplugs/udp.py
112
:pyobject: Udplistener._outloop
116
rlog(5, 'udp', 'starting outloop')
118
(printto, txt) = self.outqueue.get()
121
self.dosay(printto, txt)
122
rlog(5, 'udp', 'stopping outloop')
124
def _handleloop(self):
126
(input, addr) = self.queue.get()
127
if not input or not addr:
131
self.handle(input, addr)
133
time.sleep(cfg['udpsleep'] or 0.01)
134
rlog(5, 'udp', 'shutting down udplistener')
137
""" listen for udp messages .. /msg via bot"""
140
for botname in cfg['udpbots']:
141
if not fleet.byname(botname):
142
rlog(10, 'udp', "can't find %s bot" % botname)
145
fleet.startok.wait(5)
146
self.sock.bind((cfg['udphost'], cfg['udpport']))
147
rlog(10, 'udp', 'udp listening on %s %s' % (cfg['udphost'], \
155
# loop on listening udp socket
158
input, addr = self.sock.recvfrom(64000)
159
except socket.timeout:
161
except Exception, ex:
168
rlog(10, self.name, str(ex))
177
self.queue.put((input, addr))
178
rlog(5, 'udp', 'shutting down main loop')
180
def handle(self, input, addr):
183
handle an incoming udp packet.
185
:param input: txt in udp packet
187
:param addr: address info of udp packet
188
:type add: (host, port) tuple
190
.. literalinclude:: ../../gozerplugs/udp.py
191
:pyobject: Udplistener.handle
196
for i in range(len(input)/16):
198
data += crypt.decrypt(input[i*16:i*16+16])
199
except Exception, ex:
200
rlog(10, 'udp', "can't decrypt: %s" % str(ex))
206
data = strippedtxt(data)
207
# check if udp is enabled and source ip is in udpallow list
208
if cfg['udp'] and (addr[0] in cfg['udpallow'] or \
210
# get printto and passwd data
211
header = re.search('(\S+) (\S+) (.*)', data)
214
if header.group(1) == cfg['udppassword']:
215
printto = header.group(2) # is the nick/channel
216
# check if printto is in allowednicks
217
if not printto in cfg['udpallowednicks']:
218
rlog(10, 'udp', "udp denied %s" % printto )
220
rlog(0, 'udp', str(addr[0]) + " udp allowed")
221
text = header.group(3) # is the text
222
self.say(printto, text)
224
rlog(10, 'udp', "can't match udppasswd from " + \
227
rlog(10, 'udp', "can't match udp from " + str(addr[0]))
229
rlog(10, 'udp', 'denied udp from ' + str(addr[0]))
231
def say(self, printto, txt):
236
.. literalinclude:: ../../gozerplugs/udp.py
237
:pyobject: Udplistener.say
241
self.outqueue.put((printto, txt))
243
def dosay(self, printto, txt):
246
send txt to printto .. do some checks.
248
.. literalinclude:: ../../gozerplugs/udp.py
249
:pyobject: Udplistener.dosay
253
if cfg['udpparty'] and partyline.is_on(printto):
254
partyline.say_nick(printto, txt)
256
if not cfg['udpbots']:
257
bots = [cfg['udpbot'], ]
259
bots = cfg['udpbots']
261
bot = fleet.byname(botname)
263
rlog(10, 'udp', "can't find %s bot in fleet" % botname)
265
#if not bot.jabber and not cfg['nolimiter']:
268
bot.say(printto, txt)
269
for i in self.loggers:
272
# the udplistener object
274
udplistener = Udplistener()
276
# initialize crypt object if udpseed is set in config
277
if cfg['udp'] and cfg['udpseed']:
278
crypt = rijndael(cfg['udpseed'])
285
.. literalinclude:: ../../gozerplugs/udp.py
291
start_new_thread(udplistener._listen, ())
292
start_new_thread(udplistener._handleloop, ())
293
start_new_thread(udplistener._outloop, ())
299
shutdown the udp plugin.
301
.. literalinclude:: ../../gozerplugs/udp.py
306
if cfg['udp'] and udplistener:
308
udplistener.outqueue.put_nowait((None, None))
309
udplistener.queue.put_nowait((None, None))
312
if cfg['udp'] and cfg['udpdblog']:
314
from gozerbot.database.db import Db
318
""" log udp data to database. """
320
# see tables/udplog for table definition and add udpdblog = 1 to
324
def log(self, printto, txt):
326
""" do the actual logging. """
329
res = self.db.execute("""INSERT into udplog(time,printto,txt)
330
values(%s,%s,%s) """, (time.time(), printto, txt))
331
except Exception, ex:
332
rlog(10, 'udp', 'failed to log to db: %s' % str(ex))
335
udplistener.loggers.append(Udpdblog())
336
rlog(10, 'udp', 'registered database udp logger')