Exemple #1
0
    def load(self,path):
        ''' Load configuration from config file '''
        conf = ConfigParser.SafeConfigParser()

        try:
            f = open(path,'r')
            conf.readfp(f)

            self.server = conf.get('General','server')
            self.port = int(conf.getint('General','port'))

            self.user = conf.get('General','user')
            self.name = conf.get('General','name')
            self.nick = conf.get('General','nick')

            self.ssl_enabled = conf.getboolean('General','ssl_enabled')

            self.control_list = conf.get('General','control_list').split(',')
            self.plugins = conf.get('General','plugins').split(',')

            for channel in conf.sections():                
                if channel != 'General':
                    acl = {}
                    item_list = conf.items(channel)
                    for item in item_list:
                        acl[item[0]] = item[1]

                    self.channels[channel] = acl

        except:
            log.e(traceback.format_exc())            
            return False

        return True
Exemple #2
0
 def threadProc():
     log.i("thread %s started!", name)
     try:
         target(*args)
         log.i("thread %s ended!", name)
     except Exception as e:
         log.e("thread %s crash!err=%s", name, e)
Exemple #3
0
    def save(self,path):
        ''' Save configuration to config file '''
        conf = ConfigParser.SafeConfigParser()
        
        conf.add_section('General')
        conf.set('General','server',self.server)
        conf.set('General','port',str(self.port))
        conf.set('General','user',self.user)
        conf.set('General','name',self.name)
        conf.set('General','nick',self.nick)
        conf.set('General','ssl_enabled',str(self.ssl_enabled))
        conf.set('General','control_list',','.join(self.control_list))
        conf.set('General','plugins',','.join(self.plugins))

        for chan in self.channels.iterkeys():
            conf.add_section(chan)
            for user in self.channels[chan].iterkeys():
                conf.set(chan,user,self.channels[chan][user])
        try:
            f = open(path,'w')
            conf.write(f)
            f.close()
        except:
            log.e(traceback.format_exc())
            return False

        return True
Exemple #4
0
def excepthook(excType, excValue, tb):
    '''''write the unhandle exception to log'''
    from log import log
    import traceback
    log.e('Unhandled Error: %s',
          ''.join(traceback.format_exception(excType, excValue, tb)))
    sys.exit(-1)
Exemple #5
0
 def __notify_box_close(self):
     with self.__notify_box_close_lock:
         log.v('Notify box %d close.' % self.box.uuid)
         try:
             self.box.send(Message.create_close_data())
         except Exception as e:
             log.e('Send close message failed.')
Exemple #6
0
 def __handle_quit_request(self, r):
     c, addr = r.accept()
     data = c.recv(config.SOCKET_RECV_LEN)
     if data == RelayServer.MSG_QUIT:
         self.__is_quit_thread = True
         log.d('Get a quit request from quit-port.')
     else:
         log.e('Get an unknown message from quit-port.')
Exemple #7
0
 def on_msg_recv(self, msg):
     ''' Execute plugins on cmd recv hooks '''
     for hook in self.on_msg_recv_hooks:
         #Try block to avoid breaking on bugged plugins
         try:
             hook(self, msg)
         except:
             log.e("Hook %s chashed" % hook.__name__)
             log.e(traceback.format_exc())
Exemple #8
0
 def on_permission_denied(self, cmd):
     ''' Execute plugins on cmd recv hooks '''
     for hook in self.on_permission_denied_hooks:
         #Try block to avoid breaking on bugged plugins
         try:
             hook(self, cmd)
         except:
             log.e("Hook %s chashed" % hook.__name__)
             log.e(traceback.format_exc())
Exemple #9
0
 def on_disconnect(self):
     ''' Execute plugins on disconnect hooks '''
     for hook in self.on_disconnect_hooks:
         #Try block to avoid breaking on bugged plugins
         try:
             hook(self)
         except:
             log.e("Hook %s chashed" % hook.__name__)
             log.e(traceback.format_exc())
Exemple #10
0
 def __handle_conn(self):
     msg = RelayManagerMessage(self.conn.recv(config.SOCKET_RECV_LEN, magic=0x4699))
     if not msg.is_valid:
         return
     if msg.msg_type == RelayManagerMessage.Type.GET_TOKEN_ACK:
         self.__handle_get_token_ack(msg)
     elif msg.msg_type == RelayManagerMessage.Type.ACCESS_GRANTED:
         self.__handle_access_granted(msg)
     else:
         log.e('Invalid msg from RM.')
Exemple #11
0
    def __init__(self, data):
        self.data = data
        self.is_valid = False
        self.msg_type = RelayManagerMessage.Type.NONE
        self.content = None
        self.body = {'data': None}

        if len(data) < RelayManagerMessage.__HEADER_LEN:
            return

        header, body = data[:RelayManagerMessage.__HEADER_LEN], data[
            RelayManagerMessage.__HEADER_LEN:]
        magic, msg_type, body_len = struct.unpack('!HHi', header)
        if magic != RelayManagerMessage.MAGIC or body_len != len(body):
            return
        self.msg_type = msg_type

        # Parse message body, MUST set 'self.is_valid' to True when body is valid.
        if msg_type == RelayManagerMessage.Type.ACCEPT:
            if body_len == 0:
                self.is_valid = True
        elif msg_type == RelayManagerMessage.Type.REFUSE:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.ecode = int(self.content['reason'])
                    self.message = str(self.content['message'])
                    self.is_valid = True
                except:
                    log.e('The content of RM refuse is invalid, %s.' %
                          str(self.content))
        elif msg_type == RelayManagerMessage.Type.GET_TOKEN_ACK:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.body['serial_no'] = str(self.content['serialNo'])
                    self.body['service'] = str(self.content['service'])
                    if 'token' in self.content:
                        self.body['token'] = str(self.content['token'])
                    else:
                        self.body['token'] = None
                    self.is_valid = True
                except:
                    log.e('The content of RM get-token-ack is invalid, %s.' %
                          str(self.content))
        elif msg_type == RelayManagerMessage.Type.ACCESS_GRANTED:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.body['serial_no'] = str(self.content['serialNo'])
                    self.body['service'] = str(self.content['service'])
                    self.body['token'] = str(self.content['token'])
                    self.body['expire'] = int(self.content['expire']) * 60
                    self.is_valid = True
                except:
                    log.e('The content of RM get-token-ack is invalid, %s.' %
                          str(self.content))
        else:
            log.e('Unknown relay manger message type.')
Exemple #12
0
    def process_server_cmd(self,cmd):
        '''
        Process a command sent by the server.
        It does not require checking for permissions.
        '''
        if cmd.name not in self.server_commands:
            return False

        log.i("Command from server: %s" % cmd.name)

        result = getattr(self, cmd.name)(cmd)

        if result == False:
            log.e("Unable to send command response to server: '%s'" % cmd.name)

        return True
Exemple #13
0
 def bind_socket_to_port(self, s, ip, port):
     """ Bind a socket with ip and port and return bound port.
     """
     count = 0
     cur_port = port
     while True:
         try:
             cur_port = port + count
             s.bind((ip, cur_port))
             break
         except socket.error as err:
             log.e('Bind port %s, %d failed, error number: %d' % (ip, cur_port, err.errno))
             count += 1
             if count > 15:
                 count = 0
             time.sleep(2)
     return cur_port
Exemple #14
0
    def recv(self):
        ''' Recv wrapper to handle exceptions '''
        if self.socket == None:
            return False

        if self.conf.ssl_enabled == True and self.ssl_socket == None:
            return False

        try:
            #IRC protocol uses 512 bytes as buffer size
            if self.conf.ssl_enabled:
                return self.ssl_socket.read(512)
            else:
                return self.socket.recv(512)
        except Exception as e:
            log.e(traceback.format_exc())
            return ''
Exemple #15
0
    def run(self):
        self.load_plugin_list()
        log.i("Plugins Loaded.")

        self.connect()
        log.i("Bot Connected.")

        self.on_connect()
        log.i("Deception locked and loaded!")

        while self.connected:
            msg = self.recv()

            if len(msg) == 0:
                self.connected = False
                continue

            msglist = msg.split('\n')

            for line in msglist:
                if len(line) == 0: continue

                log.d(line)

                cmd = self.parse_cmd(line.strip())
                if cmd == None:
                    self.on_msg_recv(line)
                    continue

                log.d(cmd);

                if self.process_server_cmd(cmd):
                    continue

                if cmd.name not in self.cmd_handlers.keys():
                    log.e("Command '%s' not recognized." % cmd.name)
                    self.on_unknown_cmd(cmd)
                    continue

                if not self.check_permission(cmd):
                    self.on_permission_denied(cmd)

                self.process_cmd(cmd)

        self.on_disconnect()
Exemple #16
0
    def send(self,msg):
        ''' Send wrapper to handle exceptions '''
        if self.socket == None:
            return False

        if self.conf.ssl_enabled == True and self.ssl_socket == None:
            return False

        try:
            if self.conf.ssl_enabled:
                self.ssl_socket.write(msg)
            else:
                self.socket.sendall(msg)

            return True
        except Exception as e:
            log.e(traceback.format_exc())
            return False
Exemple #17
0
    def run(self):
        self.is_quit = False

        while not self.is_quit:
            log.v('[RM] Try connect to relay manager.')

            self.conn = RelayManagerConnection(socket.socket(socket.AF_INET, socket.SOCK_STREAM))

            try:
                self.__connect()
            except (socket.error, socket.timeout) as e:
                log.e('[RM] Send connect request to relay manager failed: %s' % str(e))
                self.conn.close()
                time.sleep(30)
                continue

            log.v('[RM] Relay manager connected.')

            self.__update_network_speed()
            self.__send_heartbeat()
            self.__send_status()

            while not self.is_quit:
                try:
                    reads, _, errors = select.select([self.conn], [], [self.conn], 1)
                    self.__update_messages()
                    self.__update_messages_udp()
                    self.__update_tracers()
                    if self.conn in reads:
                        self.__handle_conn()
                    if self.conn in errors:
                        raise socket.error('connection error in select()')
                except (socket.error, socket.timeout) as e:
                    log.e('[RM] Send HEARTBEAT or STATUS failed: %s' % str(e))
                    self.conn.close()
                    time.sleep(1)
                    break

        # Quit the connection.
        try:
            self.__send_disconnect()
            self.conn.close()
        except (socket.error, socket.timeout) as e:
            pass
Exemple #18
0
    def __handle_connection_write(self, c):
        log.v('Handle connection writing.')

        if c is self.box:
            log.v('Handle box writing.')

            try:
                # Check box timeout without PING from relay.
                # c.timeout_tracer.reset()
                c.send()
                if c.blocked:
                    self.__close_box()
            except (socket.error, socket.timeout) as e:
                log.e('Send buffered datas to box %d failed: %s' %
                      (c.uuid, str(e)))
                self.__close_box()
        elif c in self.clients:
            log.v('Handle client writing.')

            try:
                log.v(
                    'Send data to client %d in __handle_connection_write().' %
                    c.uuid)
                c.timeout_tracer.reset()
                changed = c.send()
                if changed:
                    if c.blocked:
                        log.v('Client %d has blocked' % c.uuid)
                        self.box.append_data_to_buffer(
                            Message.create_pause_data(c.uuid))
                    else:
                        log.v('Client %d has not blocked' % c.uuid)
                        self.box.append_data_to_buffer(
                            Message.create_resume_data(c.uuid))
                else:
                    # log.v('Client %d blocked state has not changed.' % c.uuid)
                    pass
            except (socket.error, socket.timeout) as e:
                log.e('Send buffered datas to client failed: %s' % str(e))
                self.__notify_box_client_broken(c.uuid)
                self.__close_client(c)
Exemple #19
0
    def connect(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        try:
            self.socket.connect((self.conf.server, self.conf.port))

            if (self.conf.ssl_enabled):
                self.ssl_socket = socket.ssl(self.socket)

            self.send("NICK %s\n" % self.conf.nick)
            self.send("USER %s 0 * :%s\n" % (self.conf.user, self.conf.name))

            #TODO: wait for event 376`
            time.sleep(10)

            self.connected = True
        except Exception as e:
            log.e(traceback.format_exc())

            if (self.socket != None):
                self.socket.close()
Exemple #20
0
    def __handle_connection_read(self, r):
        # log.v('Handle connection reading.')

        if r is self.s:
            log.v('Handle box listener reading.')

            c, addr = r.accept()
            conn = BoxConnection(c)
            log.d('Connected by box %d, address, %s' % (conn.uuid, repr(addr)))
            if self.box:
                conn.close()
            else:
                self.box_cache.append(conn)
        elif r in self.box_cache:
            log.v('Handle cached box reading.')

            try:
                self.__handle_cached_box_connection(r)
            except (socket.error, socket.timeout) as e:
                log.e('Cached box %d connection encounter an error: %s' %
                      (r.uuid, str(e)))
                self.__close_cached_box(r)
        elif r is self.box:
            log.v('Handle box reading.')

            try:
                self.__handle_box_connection(r)
            except (socket.error, socket.timeout) as e:
                log.e('Box %d connection encounter an error: %s' %
                      (r.uuid, str(e)))
                self.__close_box()
        elif r is self.cs:
            log.v('Handle client listener reading.')

            c, addr = r.accept()
            conn = ClientConnection(c)
            log.d('Connected by client %d, address, %s' %
                  (conn.uuid, repr(addr)))
            if not self.box:
                log.d('Skip this client because no box connected !!!')
                conn.close()
                return
            self.clients.append(conn)
        elif r in self.clients:
            log.v('Handle client reading.')

            try:
                r.timeout_tracer.reset()
                self.__handle_client_connection(r)
            except (socket.error, socket.timeout) as e:
                log.e('Client %d connection enconter an error: %s.' %
                      (r.uuid, str(e)))
                self.__notify_box_client_broken(r.uuid)
                self.__close_client(r)
        elif r is self.__qs:
            log.v('Handle quit-socket reading.')

            self.__handle_quit_request(r)
        else:
            log.d('The connection does not need handle.')
Exemple #21
0
    def load_plugin(self, name, sync=False):
        ''' Load plugin on runtime '''
        log.i("Loading plugin: '%s'" % name)

        try:
            module = __import__('plugins.' + name, fromlist=["plugins"])

            if sync: reload(module)

            #Load event hooks
            if hasattr(module, 'ON_CONNECT'):
                for hook in module.ON_CONNECT:
                    self.on_connect_hooks.append(hook)

            if hasattr(module, 'ON_DISCONNECT'):
                for hook in module.ON_DISCONNECT:
                    self.on_disconnect_hooks.append(hook)

            if hasattr(module, 'ON_MSG_RECV'):
                for hook in module.ON_MSG_RECV:
                    self.on_msg_recv_hooks.append(hook)

            if hasattr(module, 'ON_UNKNOWN_CMD'):
                for hook in module.ON_UNKNOWN_CMD:
                    self.on_unknown_cmd_hooks.append(hook)

            if hasattr(module, 'ON_PERMISSION_DENIED'):
                for hook in module.ON_PERMISSION_DENIED:
                    self.on_permission_denied_hooks.append(hook)

            #Load plugin commands
            if hasattr(module, 'COMMAND_HANDLERS'):
                for handler in module.COMMAND_HANDLERS.keys():
                    self.cmd_handlers[handler] = module.COMMAND_HANDLERS[handler]

        except:
            log.e("Unable to load plugin '%s'" % name)
            log.e(traceback.format_exc())
Exemple #22
0
    def __handle_connection_error(self, c):
        # log.v('Handle connection error.')

        if c in self.box_cache:
            log.e('Cached box %d error from select().' % c.uuid)
            self.__close_cached_box(c)
        elif c is self.box:
            log.e('Box %d error from select().' % c.uuid)
            self.__close_box()
        elif c in self.clients:
            log.e('Client %d error from select().' % c.uuid)
            self.__close_client(c)
Exemple #23
0
    def process_cmd(self,cmd):
        ''' Execute plugins commands '''
        if cmd.name not in self.cmd_handlers.keys():
            return False

        log.i("Command from user: %s" % cmd.name)

        if not self.check_permission(cmd):
            log.e("User %s does not have enough permission for command %s" % (cmd.user, cmd.name))
            return False

        #Try block to avoid breaking on bugged plugins
        try:
            result = self.cmd_handlers[cmd.name][0](self,cmd)

            if result == False:
                log.e("Unable to send command response to server: '%s'" % cmd.name)
        except:
            log.e("Command '%s' crashed." % cmd.name)
            log.e(traceback.format_exc())

        return True
Exemple #24
0
    def __handle_box_register(self, c, msg):
        """
        :param c:
        :param msg:
        :return: the box is valid.
        """

        log.d('Get box %d register content: %s' % (c.uuid, msg.content))

        try:
            sn = str(msg.content['deviceId'])
            service = str(msg.content['service'])
            token = str(msg.content['token'])
        except:
            log.e('Box register information format is not correct.')
            c.send(Message.create_refuse_data(ECode.RELAY_BOX_INVALID_INFO))
            return False

        device_token = self.hub_linker.connector.verify_token(
            sn, service, token)
        if not device_token:
            log.e('Box register information is invalid by hub.')
            c.send(Message.create_refuse_data(ECode.RELAY_BOX_INVALID_INFO))
            return False

        log.d('Box register info is valid, device_id %s, token %s.' %
              (str(sn), str(token)))

        _, _, cport, udp_port = self.upnp.get_router_info()
        if not cport:
            log.e('Can not set up client upnp port.')
            c.send(
                Message.create_refuse_data(
                    ECode.RELAY_FAILED_CREATE_CLIENT_PORT))
            return False
        reply = {'port': str(cport)}
        c.send(Message.create_accept_data(reply))
        return True
Exemple #25
0
    def join(self, channel):
        ''' Join a channel '''
        if channel == None:
            log.e("Missing parameter for JOIN message")

        self.send("JOIN %s\n" % channel)
Exemple #26
0
    def __init__(self, data, conn=None):
        if not data:
            raise socket.error('Get the EOF message')
        self.data = data
        self.is_valid = False
        self.type = None
        # Possible value:
        #   json unpacked data.
        #   data stream.
        self.content = None
        # Error code, ing, 4 byte in data.
        self.ecode = -1
        self.message = ''
        # Client UUID, long, long, 8 byte in data
        self.uuid = -1
        if len(data) < Message.HEADER_LEN:
            return
        header, body = data[:Message.HEADER_LEN], data[Message.HEADER_LEN:]
        magic, self.type, length = struct.unpack('!HHi', header)
        if magic != Message.MAGIC or length != len(body):
            return

        # Parse message body.
        # MUST set 'self.is_valid' to True when body is valid.
        if self.type == Type.CONNECT \
                or self.type == Type.ACCEPT:
            self.is_valid = self.content = Message.get_unpacked_json_data(body)
        elif self.type == Type.REFUSE:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.ecode = int(self.content['reason'])
                    self.message = str(self.content['message'])
                    self.is_valid = True
                except:
                    log.e('The content of relay REFUSE is invalid, %s.' %
                          str(self.content))
        elif self.type == Type.DISCONNECT \
                or self.type == Type.CLOSE \
                or self.type == Type.PING \
                or self.type == Type.PING_ACK:
            self.is_valid = len(body) == 0
        elif self.type == Type.SERVER_DATA \
                or self.type == Type.CLIENT_DATA:
            if len(body) <= Message.UUID_LEN:
                return
            uuid_data, self.content = body[:Message.UUID_LEN], body[Message.
                                                                    UUID_LEN:]
            self.uuid = struct.unpack('@q', uuid_data)[0]
            self.is_valid = True
        elif self.type == Type.SERVER_ERROR \
                or self.type == Type.CLIENT_ERROR:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.uuid = int(self.content['connection'])
                    self.ecode = int(self.content['error'])
                    self.is_valid = True
                except:
                    log.e(
                        'The content of relay SERVER_ERROR or CLIENT_ERROR is invalid, %s.'
                        % str(self.content))
        elif self.type == Type.PAUSE \
                or self.type == Type.RESUME:
            self.content = Message.get_unpacked_json_data(body)
            if isinstance(self.content, dict):
                try:
                    self.uuid = int(self.content['connection'])
                    self.is_valid = True
                except:
                    log.e(
                        'The content of relay PAUSE or RESUME is invalid, %s.'
                        % str(self.content))
        else:
            log.e('Unknown message type.')
Exemple #27
0
 def pong(self, cmd):
     ''' Reply to ping requests '''
     if len(cmd.args) >= 1:
         self.send("PONG : %s\r\n" % cmd.args[0])
     else:
         log.e("Missing parameter for PING message")
Exemple #28
0
    def part(self, channel):
        ''' Part from channel  '''
        if channel == None:
            log.e("Missing parameter for PART message")

        self.send("PART %s\n" % channel)
Exemple #29
0
    def mode(self, target, mode, user):
        ''' Set channel mode for user '''
        if target == None or mode == None or user == None:
            log.e("Missing parameters for MODE message")

        self.send("MODE %s %s %s\n" % (target, mode, user))
Exemple #30
0
    def privmsg(self,target,msg):
        ''' Send a message to channel/user  '''
        if target == None or msg == None:
            log.e("Missing parameters for PRIVMSG message")

        self.send("PRIVMSG %s :%s\n" % (target, msg))