mirror of https://github.com/cowrie/cowrie.git
139 lines
5.5 KiB
Python
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:
|