#!/usr/bin/env python #Copyright 2005,2006 Sebastian Hagen # This file is part of eucharis. # eucharis is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation # eucharis is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with eucharis; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging from time import time import optparse import socket_management import data_formatting import input_handlers import __main__ from data_types import istr from iptracking import core_base from input_handlers import handlers_user from client_dict import dict_connection LOOKUP_NONE = 0 LOOKUP_DEFINE = 1 LOOKUP_MATCH = 2 class info_request_handler(handlers_user, core_base): def __init__(self, irc_server=None, control_connection=None): self.ctcp_commands = ['PING', 'VERSION', 'TIME', 'CLIENTINFO'] self.trigger_commands = ['uptime'] self.handler_bindings = { 'irc_server': [['CTCP', ctcp_command, self.irc_ctcp_handler, []] for ctcp_command in self.ctcp_commands] + [['trigger', istr(trigger_command), self.irc_trigger_handler, []] for trigger_command in self.trigger_commands], 'control_connection': [ ], } core_base.__init__(self, irc_server=irc_server, control_connection=control_connection, irc_client=None, botnet_interface=None) self.handlers_modify(action='register') self.ts_init = time() def system_uptime_get(self): try: uptime_list = file('/proc/uptime').read(1048576).strip().split() except IOError: return None if (not uptime_list): return None try: uptime_value = float(uptime_list[0]) except ValueError: return None else: return uptime_value @staticmethod def irc_ctcpreply_send(output, target, ctcp, text): output(command='NOTICE', arguments=[target, '\001%s %s\001' % (ctcp, text)]) @staticmethod def irc_triggerreply_send(output, target, text): output(command='PRIVMSG', arguments=[target, text]) def irc_ctcp_handler(self, parent, output, event_type, event, permissions, data): source = data['source'] command = data['command'] text = data['text'] if (event == 'PING'): self.irc_ctcpreply_send(output, source, command, text) elif (event == 'VERSION'): self.irc_ctcpreply_send(output, source, command, ' '.join(__main__.version_info)) elif (event == 'TIME'): self.irc_ctcpreply_send(output, source, command, data_formatting.seconds_hr_absolute(time())) elif (event == 'CLIENTINFO'): self.irc_ctcpreply_send(output, source, command, ' '.join(self.ctcp_commands)) def irc_trigger_handler(self, parent, output, event_type, event, permissions, data): event_lc = event.lower() target, source = data['reply_target'], data['source'] if (event_lc == 'uptime'): uptime_self = time() - self.ts_init uptime_self_str = data_formatting.seconds_hr_relative(uptime_self, 1) self.irc_triggerreply_send(output, target, 'Process uptime: %s' % (uptime_self_str,)) uptime_system = self.system_uptime_get() if (uptime_system): uptime_system_str = data_formatting.seconds_hr_relative(uptime_system, 1) else: uptime_system_str = 'unknown' self.irc_triggerreply_send(output, target, 'System uptime: %s' % (uptime_system_str,)) class dict_request_handler(handlers_user, core_base): def __init__(self, irc_server, dictd_address, reconnect_delay=3600, source_preferred=None): self.handler_bindings = { 'irc_server':( ('trigger', 'dict', self.irc_trigger_handler, ()), ) } self.logger = logging.getLogger('dict_request_handler') self.source_preferred = source_preferred core_base.__init__(self, irc_server=irc_server, control_connection=None, irc_client=None, botnet_interface=None) self.handlers_modify(action='register') self.connection = None self.dictd_address = dictd_address self.dict_connection_init() self.reconnect_delay = reconnect_delay self.output = self.reply_target = None self.optparser = input_handlers.input_parser(custom_output=self.optparse_output, program_name='dict', usage='%prog [options] [word]', option_list=[ optparse.make_option('-d', '--database', action='store', type='string', dest='database', default=None, help='select a database to search'), optparse.make_option('-m', '--match', action='store_true', dest='match', default=False, help='match instead of define'), optparse.make_option('-s', '--strategy', action='store', type='string', dest='strategy', default='prefix', help='strategy for matching'), optparse.make_option('-D', '--dbs', action='store_true', dest='db_list', default=False, help='show available databases'), optparse.make_option('-S', '--strats', action='store_true', dest='strat_list', default=False, help='show available strategies'), optparse.make_option('-i', '--info', action='store', type='string', dest='db_info', default=None, help='show information about a database'), optparse.make_option('-I', '--serverinfo', action='store_true', dest='server_info', default=False, help='show information about the server'), ] ) def dict_connection_init(self): try: self.connection = dict_connection(self.dictd_address, self.dict_connection_close_handler) except StandardError: self.logger.log(35, 'Connection attempt to dict at %r failed:' % (self.dictd_address,), exc_info=True) self.connection = None def irc_triggerreply_send(self, output, target, text): output(source=self.source_preferred, command='PRIVMSG', arguments=[target, text]) def optparse_output(self, text): if (callable(self.output) and self.reply_target): self.irc_triggerreply_send(self.output, self.reply_target, text) def irc_trigger_handler(self, parent, output, event_type, event, permissions, data): request_string = ' '.join(data['arguments']) data['output'] = output self.reply_target = target = data['reply_target'] self.output = output try: (input_options, input_arguments) = self.optparser.parse_args(data['arguments']) except ValueError: return self.output = self.reply_target = None if not (self.connection): self.dict_connection_init() request_string = ' '.join(input_arguments) if (input_options.db_list or input_options.strat_list or input_options.server_info or input_options.db_info): if not (self.connection): self.irc_triggerreply_send(output, target, 'Unable to comply; failed to connect to dictd at %s.' % (self.dictd_address,)) else: if (input_options.db_list): self.irc_triggerreply_send(output, target, 'Requesting list of available databases.') self.connection.showdb(callback_handler=self.dict_response_handler, sessiondata=data) if (input_options.strat_list): self.irc_triggerreply_send(output, target, 'Requesting list of available strategies.') self.connection.showstrat(callback_handler=self.dict_response_handler, sessiondata=data) if (input_options.server_info): self.irc_triggerreply_send(output, target, 'Requesting server info.') self.connection.showserver(callback_handler=self.dict_response_handler, sessiondata=data) if (input_options.db_info): self.irc_triggerreply_send(output, target, 'Requesting info for db %r.' % (input_options.db_info,)) self.connection.showinfo(database=input_options.db_info, callback_handler=self.dict_response_handler, sessiondata=data) elif (input_arguments): if not (self.connection): self.irc_triggerreply_send(output, target, 'Unable to comply; failed to connect to dictd at %s.' % (self.dictd_address,)) else: if (input_options.match): if not (input_options.database): input_options.database = '*' self.connection.match(database=input_options.database, strategy=input_options.strategy, word=request_string, callback_handler=self.dict_response_handler, sessiondata=data) else: if not (input_options.database): input_options.database = '!' self.connection.define(database=input_options.database, word=request_string, callback_handler=self.dict_response_handler, sessiondata=data) else: self.irc_triggerreply_send(output, target, 'Nothing to do (use -h for help on valid arguments).') if not (self.connection): self.dict_connection_init() def dict_response_handler(self, dict_connection, success, numeric, result, sessiondata): output = sessiondata['output'] target = sessiondata['reply_target'] if (numeric == 150): #successful DEFINE response: list of subresults, each being a list of lines for subresult in result: word, dbname, dbdesc, resultlines = subresult self.irc_triggerreply_send(output, target, '%s from %r [%s]' % (word, dbdesc, dbname)) for line in resultlines: self.irc_triggerreply_send(output, target, ' ' + line) elif (numeric == 152): #successful match: dict with databases as keys, and match-lists as values for database in result.keys(): self.irc_triggerreply_send(output, target, '%s: %s' % (database, ' '.join(['%r' % (word,) for word in result[database]]))) elif(success): for line in result: self.irc_triggerreply_send(output, target, ' ' + line) else: self.irc_triggerreply_send(output, target, 'Got a %d (%r) failure response.' % (numeric, result)) def dict_connection_close_handler(self, fd): self.connection = None self.logger.log(20, 'Lost connection to dicd at %r.' % (self.dictd_address,))