cowrie/kippo/dblog/mysql.py

139 lines
5.5 KiB
Python

from kippo.core import dblog
from twisted.enterprise import adbapi
from twisted.internet import defer
from twisted.python import log
import MySQLdb, uuid
class ReconnectingConnectionPool(adbapi.ConnectionPool):
"""Reconnecting adbapi connection pool for MySQL.
This class improves on the solution posted at
http://www.gelens.org/2008/09/12/reinitializing-twisted-connectionpool/
by checking exceptions by error code and only disconnecting the current
connection instead of all of them.
Also see:
http://twistedmatrix.com/pipermail/twisted-python/2009-July/020007.html
"""
def _runInteraction(self, interaction, *args, **kw):
try:
return adbapi.ConnectionPool._runInteraction(
self, interaction, *args, **kw)
except MySQLdb.OperationalError, e:
if e[0] not in (2006, 2013):
raise
log.msg("RCP: got error %s, retrying operation" %(e))
conn = self.connections.get(self.threadID())
self.disconnect(conn)
# try the interaction again
return adbapi.ConnectionPool._runInteraction(
self, interaction, *args, **kw)
class DBLogger(dblog.DBLogger):
def start(self, cfg):
self.db = ReconnectingConnectionPool('MySQLdb',
host = cfg.get('database_mysql', 'host'),
db = cfg.get('database_mysql', 'database'),
user = cfg.get('database_mysql', 'username'),
passwd = cfg.get('database_mysql', 'password'),
cp_min = 1,
cp_max = 1)
def sqlerror(self, error):
print 'SQL Error:', error.value
def simpleQuery(self, sql, args):
""" Just run a deferred sql query, only care about errors """
d = self.db.runQuery(sql, args)
d.addErrback(self.sqlerror)
def createSession(self, peerIP, peerPort, hostIP, hostPort):
sid = uuid.uuid1().hex
self.createSessionWhenever(sid, peerIP, hostIP)
return sid
# This is separate since we can't return with a value
@defer.inlineCallbacks
def createSessionWhenever(self, sid, peerIP, hostIP):
sensorname = self.getSensor() or hostIP
r = yield self.db.runQuery(
'SELECT `id` FROM `sensors` WHERE `ip` = %s', (sensorname,))
if r:
id = r[0][0]
else:
yield self.db.runQuery(
'INSERT INTO `sensors` (`ip`) VALUES (%s)', (sensorname,))
r = yield self.db.runQuery('SELECT LAST_INSERT_ID()')
id = int(r[0][0])
# now that we have a sensorID, continue creating the session
self.simpleQuery(
'INSERT INTO `sessions` (`id`, `starttime`, `sensor`, `ip`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)',
(sid, self.nowUnix(), id, peerIP))
def handleConnectionLost(self, session, args):
ttylog = self.ttylog(session)
if ttylog:
self.simpleQuery(
'INSERT INTO `ttylog` (`session`, `ttylog`) VALUES (%s, %s)',
(session, self.ttylog(session)))
self.simpleQuery(
'UPDATE `sessions` SET `endtime` = FROM_UNIXTIME(%s)' + \
' WHERE `id` = %s',
(self.nowUnix(), session))
def handleLoginFailed(self, session, args):
self.simpleQuery('INSERT INTO `auth` (`session`, `success`' + \
', `username`, `password`, `timestamp`)' + \
' VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s))',
(session, 0, args['username'], args['password'], self.nowUnix()))
def handleLoginSucceeded(self, session, args):
self.simpleQuery('INSERT INTO `auth` (`session`, `success`' + \
', `username`, `password`, `timestamp`)' + \
' VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s))',
(session, 1, args['username'], args['password'], self.nowUnix()))
def handleCommand(self, session, args):
self.simpleQuery('INSERT INTO `input`' + \
' (`session`, `timestamp`, `success`, `input`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)',
(session, self.nowUnix(), 1, args['input']))
def handleUnknownCommand(self, session, args):
self.simpleQuery('INSERT INTO `input`' + \
' (`session`, `timestamp`, `success`, `input`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)',
(session, self.nowUnix(), 0, args['input']))
def handleInput(self, session, args):
self.simpleQuery('INSERT INTO `input`' + \
' (`session`, `timestamp`, `realm`, `input`)' + \
' VALUES (%s, FROM_UNIXTIME(%s), %s, %s)',
(session, self.nowUnix(), args['realm'], args['input']))
def handleTerminalSize(self, session, args):
self.simpleQuery('UPDATE `sessions` SET `termsize` = %s' + \
' WHERE `id` = %s',
('%sx%s' % (args['width'], args['height']), session))
@defer.inlineCallbacks
def handleClientVersion(self, session, args):
r = yield self.db.runQuery(
'SELECT `id` FROM `clients` WHERE `version` = %s', \
(args['version'],))
if r:
id = int(r[0][0])
else:
yield self.db.runQuery(
'INSERT INTO `clients` (`version`) VALUES (%s)', \
(args['version'],))
r = yield self.db.runQuery('SELECT LAST_INSERT_ID()')
id = int(r[0][0])
self.simpleQuery(
'UPDATE `sessions` SET `client` = %s WHERE `id` = %s',
(id, session))
# vim: set sw=4 et: