Exemple #1
0
def unload(self):
    global can_see
    for channel in [
            channel for channel in self.channels
            if hasattr(channel, 'delayjoins') and channel in can_see
    ]:
        if not hasattr(channel, 'delayjoins') or not channel.delayjoins:
            channel.delayjoins = []
        # Show user joins to whoever needs them.
        for user in channel.users:
            for user2 in [
                    user2 for user2 in channel.users
                    if user2 not in can_see[channel][user]
            ]:
                logging.debug(
                    'Module unload: Showing join from {} to {}'.format(
                        user2, user))
                data = ':{}!{}@{} JOIN {}{}'.format(
                    user2.nickname, user2.ident, user2.cloakhost, channel.name,
                    ' {} :{}'.format(user2.svid, user2.realname)
                    if 'extended-join' in user.caplist else '')
                user._send(data)
                can_see[channel][user].append(user2)

    can_see = {}
Exemple #2
0
    def register(self):
        if not self.registered:
            self.validate()

        if hasattr(self, 'level'):
            pass

        mode_class_list = None
        if issubclass(self.__class__, UserMode):
            mode_class_list = self.ircd.user_mode_class
        elif issubclass(self.__class__, ChannelMode):
            mode_class_list = self.ircd.channel_mode_class

        if self not in mode_class_list:
            mode_class_list.append(self)

        if issubclass(self.__class__, UserMode):
            self.ircd.user_modes[self.mode] = (self.req_flag, self.desc)
            logging.debug('Usermode registered: {}'.format(self))
            # logging.debug('Permission flag: {}'.format(self.req_flag))
            # logging.debug('Description: {}'.format(self.desc))
        elif issubclass(self.__class__, ChannelMode):
            if self.type != 3 and self.param_help:
                t = (self.req_flag, self.desc, self.param_help)
            else:
                t = (self.req_flag, self.desc)
            self.ircd.channel_modes[self.type][self.mode] = t
            logging.debug('Channelmode registered: {}'.format(self))
            # logging.debug('Permission flag: {}'.format(self.req_flag))

        self.registered = 1
Exemple #3
0
    def unload(self):
        if self in self.ircd.command_class:
            self.ircd.command_class.remove(self)

        if self.support and self.support[0] in self.ircd.support:
            logging.debug('Removed support data')
            del self.ircd.support[self.support[0]]
        logging.debug('{} successfully unhooked'.format(self))
Exemple #4
0
 def take_mode(self, user):
     if self.mode not in user.modes:
         logging.debug('Failed attempt at removing non-active usermode "{}" from {}'.format(self.mode, user.nickname))
         return 0
     user.modes = user.modes.replace(self.mode, '')
     self.modebuf.append(self.mode)
     logging.debug('Usermode "{}" removed from {} usermodes. Now: {}'.format(self.mode, user.nickname, user.modes))
     return 1
Exemple #5
0
 def _send(self, data):
     if not hasattr(self, 'socket'):
         # logging.debug('Socket {} got sent flashed out.'.format(self))
         return
     if self.socket:
         self.sendbuffer += data + '\r\n'
         if self.server.use_poll:
             logging.debug(
                 'Flag for {} set to READ_WRITE (_send())'.format(self))
             self.server.pollerObject.modify(self.socket, READ_WRITE)
Exemple #6
0
def init(self, reload=False):
    global can_see
    if can_see or reload:
        return
    can_see = {}
    for chan in self.channels:
        if chan not in can_see:
            can_see[chan] = {}
            logging.debug('INIT: Channel {} added to can_see dict'.format(
                chan.name))
        for user in [user for user in chan.users if user not in can_see[chan]]:
            can_see[chan][user] = []
Exemple #7
0
def hidequit(self, localServer):
    global can_see
    for channel in [chan for chan in self.channels if chmode in chan.modes]:
        del can_see[channel][self]
        for user in [
                user for user in channel.users
                if user in can_see[channel] and self in can_see[channel][user]
                and user.chlevel(channel) < 2
        ]:
            logging.debug('/quit: User {} can not see {} anymore.'.format(
                user.nickname, self.nickname))
            can_see[channel][user].remove(self)
Exemple #8
0
    def register(self, **kwargs):
        if not self.registered:
            if type(self.command) == str:
                self.command = [self.command.upper()]
            else:
                self.command = [x.upper() for x in self.command]
            self.help = self.__doc__
            self.validate()

            self.ircd.command_class.append(self)
            logging.debug(f'Command registered: {self}')
            self.registered = 1
Exemple #9
0
    def give_mode(self, user):
        if self.mode in user.modes:
            logging.error(f'Usermode "{self.mode}" is already active on user {user.nickname}')
            return 0

        if self.req_flag == 1 and 'o' not in user.modes:
            logging.error(f'User {user} is not allowed to set this mode: {self.req_flag}')
            return 0

        user.modes += self.mode
        self.modebuf.append(self.mode)
        logging.debug('Usermode of {} is now: {} (+{})'.format(user.nickname, user.modes, self.mode))
        return 1
Exemple #10
0
def webstats_ratelimit(localServer):
    global allowed_ips
    for ip in dict(localServer.webstats_ip_requests):
        rate_ip = [i for i in allowed_ips if match(i, ip)]
        if not rate_ip:
            logging.debug(
                'Something went wrong. Could not find a rate_limit for IP "{}", removing from dict.'
                .format(ip))
            del localServer.webstats_ip_requests[ip]
            break
        rate_limit = allowed_ips[rate_ip[0]]["rate_limit"]
        if int(time.time(
        )) - localServer.webstats_ip_requests[ip]['ctime'] > rate_limit[1]:
            del localServer.webstats_ip_requests[ip]
            logging.debug("API rate limit for {} reset.".format(ip))
Exemple #11
0
    def unload(self):
        mode_class_list = None
        if issubclass(self.__class__, UserMode):
            mode_class_list = self.ircd.user_mode_class
            del self.ircd.user_modes[self.mode]

        elif issubclass(self.__class__, ChannelMode):
            mode_class_list = self.ircd.channel_mode_class
            if self.mode in self.ircd.channel_modes[self.type]:
                del self.ircd.channel_modes[self.type][self.mode]

        if self in mode_class_list:
            mode_class_list.remove(self)

        logging.debug('{} successfully unhooked'.format(self))
Exemple #12
0
def hide_kick(self, ircd, user, channel, reason):
    if chmode in channel.modes:
        global can_see
        if channel not in can_see:
            logging.error(
                '/KICK: CRITICAL ERROR: channel {} is not found in the can_see dict!'
                .format(channel.name))
            return
        can_see[channel][user] = []
        for u in [
                u for u in channel.users
                if u in can_see[channel] and user in can_see[channel][u]
        ]:
            logging.debug('/kick: User {} can not see {} anymore.'.format(
                u.nickname, user.nickname))
            can_see[channel][u].remove(user)
Exemple #13
0
def showjoin(self, ircd, channel, msg):
    if chmode in channel.modes:
        global can_see
        for user in [
                user for user in channel.users
                if self not in can_see[channel][user] and user != self
        ]:
            logging.debug(
                '/privmsg: Allowing visibility state for {} to {}'.format(
                    self.nickname, user.nickname))
            data = ':{}!{}@{} JOIN {}{}'.format(
                self.nickname, self.ident, self.cloakhost, channel.name,
                ' {} :{}'.format(self.svid, self.realname)
                if 'extended-join' in user.caplist else '')
            user._send(data)
            can_see[channel][user].append(self)
    return msg
Exemple #14
0
def visible_in_chan(self, localServer, user, channel):
    global can_see
    if chmode not in channel.modes or (
            chmode in channel.modes and self.chlevel(channel) > 2
            or user == self
    ):  # or ('o' in self.modes and user.chlevel(channel) <= 2)):
        if chmode in channel.modes and user not in can_see[channel][self]:
            can_see[channel][self].append(user)
        return 1
    if not can_see:
        return 1
    # if self in can_see[channel]:
    #    logging.debug('User {} can see the following users on {}: {}'.format(self.nickname, channel.name, can_see[channel][self]))
    if self in can_see[channel] and user in can_see[channel][self]:
        logging.debug('visible_in_chan() dict, returning 1')
        return 1
    return 0
Exemple #15
0
def hidepart(self, localServer, channel):
    if chmode in channel.modes:
        global can_see
        if channel not in can_see:
            logging.error(
                '/PART: CRITICAL ERROR: channel {} is not found in the can_see dict!'
                .format(channel.name))
            return
        can_see[channel][self] = []
        for user in [
                user for user in channel.users
                if user in can_see[channel] and self in can_see[channel][user]
                and user.chlevel(channel) < 2
        ]:
            logging.debug('/part: User {} can not see {} anymore.'.format(
                user.nickname, self.nickname))
            can_see[channel][user].remove(self)
Exemple #16
0
    def check(self, client, recv):
        cmd = recv[0].upper()
        if type(client
                ).__name__ != self.req_class and self.req_class == 'Server':
            client.sendraw(ERR.SERVERONLY, f':{cmd} is a server only command')
            return 0
        received_params = len(recv) - 1
        if received_params < self.params:
            client.sendraw(
                ERR.NEEDMOREPARAMS,
                f':{cmd} Not enough parameters. Required: {self.params}')
            return 0

        if self.req_modes and type(client).__name__ != 'Server':
            req_modes = ' '.join(self.req_modes)
            if 'o' in req_modes and 'o' not in client.modes:
                client.sendraw(
                    ERR.NOPRIVILEGES,
                    ':Permission denied - You are not an IRC Operator')
                return 0

            forbid = set(req_modes).difference(set(client.modes))
            if forbid:
                client.sendraw(ERR.NOPRIVILEGES,
                               ':Permission denied - Required mode not set')
                return 0

            if self.req_flags:
                forbid = 1
                if '|' in self.req_flags:
                    if list(
                            filter(lambda f: f in client.operflags,
                                   self.req_flags.split('|'))):
                        forbid = False
                        logging.debug(
                            'You have one of the required flags. Allowing command.'
                        )
                else:
                    forbid = {self.req_flags}.difference(set(client.operflags))
                if forbid:
                    client.sendraw(
                        ERR.NOPRIVILEGES,
                        ':Permission denied - You do not have the correct IRC Operator privileges'
                    )
                    return 0
        return 1
Exemple #17
0
def set_D(localServer, self, channel, mode):
    if mode == chmode:
        if 'u' in channel.modes:
            localServer.notice(self, 'Mode +D cannot be set: channel has +u')
            return 0
        global can_see
        if channel not in can_see:
            can_see[channel] = {}

        for user1 in [u for u in channel.users if u not in can_see[channel]]:
            can_see[channel][user1] = []
            for user2 in [
                    user2 for user2 in channel.users
                    if user2 not in can_see[channel][user1]
            ]:
                can_see[channel][user1].append(user2)
                logging.debug('Mode set, so user {} is visible to {}'.format(
                    user2.nickname, user1.nickname))
    return 1
Exemple #18
0
def process_webstats(self, localServer, recv):
    global allowed_ips
    ip = [i for i in allowed_ips if match(i, recv[1])]
    if not ip or ip[0] not in allowed_ips:
        return self._send(
            'WEBSTATS 403 You are not allowed to make that API call.')
    if "rate_limit" in allowed_ips[ip[0]]:
        rate_limit = allowed_ips[ip[0]]["rate_limit"]
    else:
        rate_limit = (9999, 1)  # 2 Unlimited.
    ip = recv[1]
    if ip not in localServer.webstats_ip_requests:
        localServer.webstats_ip_requests[ip] = {}
        localServer.webstats_ip_requests[ip]['calls'] = {}
        localServer.webstats_ip_requests[ip]['ctime'] = int(
            time.time())  # First API call for this IP.
    logging.debug('Rate limit: {}'.format(rate_limit))
    ago = int(time.time()) - localServer.webstats_ip_requests[ip]['ctime']
    if len(localServer.webstats_ip_requests[ip]['calls']) >= rate_limit[0]:
        logging.debug("Max. calls exceeded for IP: {}".format(ip))
        return self._send('WEBSTATS 403 Rate limited.')
    response = {}
    response['users'] = [u.nickname for u in localServer.users if u.registered]
    response['channels'] = [
        c.name for c in localServer.channels
        if 's' not in c.modes and 'p' not in c.modes
    ]
    self._send('WEBSTATS 200 {}'.format(response))
    localServer.webstats_ip_requests[ip]['calls'][int(round(time.time() *
                                                            1000))] = 1
    calls = len(localServer.webstats_ip_requests[ip]['calls'])
    logging.debug(
        "This IP made {} call{} this session, first call was {} second{} ago.".
        format(calls, '' if calls == 1 else 's', ago, '' if ago == 1 else 's'))
Exemple #19
0
    def new_sync(self, ircd, skip, data, direct=None):
        try:
            if type(skip) != list:
                skip = [skip]
            for t in [t for t in skip if type(t).__name__ != 'Server']:
                logging.error(
                    '{}HALT: wrong source type in new_sync(): {} with data: {}{}'
                    .format(R2, t, data, W))
                return
            if data.split()[1] in ['UID', 'SID']:
                data = data.split()
                data = '{} {} {}'.format(' '.join(data[:3]),
                                         str(int(data[3]) + 1),
                                         ' '.join(data[4:]))
            if direct:  # Private messages and notices. direct represents the target.server
                dest = direct if direct.socket else direct.uplink
                # if direct.socket:
                # logging.debug('Directly linked to us, no more hops needed.')
                if not direct.socket:
                    logging.debug(
                        'Server has hopcount of {d.hopcount}, sending to {d.uplink} first.'
                        .format(d=direct))
                dest._send(data)
                return

            for server in [
                    server for server in ircd.servers
                    if server and server.socket and server not in skip
            ]:
                if not server.eos:
                    if server not in ircd.sync_queue:
                        ircd.sync_queue[server] = []
                    ircd.sync_queue[server].append(data)
                    logging.debug(
                        '{}Added to {} sync queue because they are not done syncing: {}{}'
                        .format(R2, server, data, W))
                    continue
                server._send(data)
        except Exception as ex:
            logging.exception(ex)
Exemple #20
0
 def _send(self, data):
     try:
         if self.socket:
             self.sendbuffer += data + '\r\n'
             if self.localServer.use_poll:
                 logging.debug(
                     'Flag for {} set to READ_WRITE (_send())'.format(self))
                 self.localServer.pollerObject.modify(
                     self.socket, READ_WRITE)
             ignore = ['PRIVMSG', 'NOTICE', 'PING', 'PONG']
             try:
                 if data.split()[0] not in ['PING', 'PONG']:
                     if len(data) > 1 and data.split()[1] not in ignore:
                         # pass
                         logging.info('{}{} <<<-- {}{}'.format(
                             B,
                             self.hostname if self.hostname != '' else self,
                             data, W))
             except:
                 pass
     except Exception as ex:
         logging.exception(ex)
def read_socket(ircd, sock):
    if not hasattr(sock, 'socket'):
        # Client probably repidly disconnected. Possible causes can be ZNC that have not yet accepted new cert.
        # sock.quit('No socket')
        return

    try:
        if sock.cls:
            buffer_len = int(ircd.conf['class'][sock.cls]['sendq']) * 2
        else:
            buffer_len = 8192 if type(sock).__name__ == 'User' else 65536
        try:
            recv = sock.socket.recv(buffer_len).decode('utf-8')

        except UnicodeDecodeError as ex:  # Do nothing, skip read.
            logging.debug(f'Unable to read socket {sock}: {ex}')

            #####
            sock.quit('')  # Drunk shit, REMOVE THIS!!!!!!!!! #####
            #####

            return
        except Exception as ex:
            # logging.exception(ex)
            sock.quit('Read error: {}'.format(ex))
            return

        if not recv:
            # logging.error('No data received from {}'.format(sock))
            sock.quit('Read error')
            return

        sock.recvbuffer += recv
        check_flood(ircd, sock)
        sock.handle_recv()
        return recv
    except Exception as ex:
        logging.exception(ex)
Exemple #22
0
    def execute(self, client, recv):
        nick = recv[2]
        params = []
        allow = 1
        for p in recv:
            params.append(p)
        for user in [
                user for user in self.ircd.users
                if user.nickname.lower() == nick.lower()
        ]:
            logging.error('Found double user in UID: {}'.format(user))
            if not user.server:
                logging.error(
                    'Quitting {} because their server could not be found (UID)'
                    .format(user))
                user.quit('Unknown or corrupted connection with the same nick')
                continue

            logging.error(
                '{}ERROR: user {} already found on the network{}'.format(
                    R, user, W))
            localTS = int(user.signon)
            remoteTS = int(recv[4])
            if remoteTS <= localTS:
                logging.info(
                    '{}Local user {} disconnected from local server.{}'.format(
                        R, user, W))
                user.quit('Local Nick Collision', silent=True)
                continue
            else:
                allow = 0
                logging.debug('Disallowing remote user {}'.format(user))
                return

        if allow:
            u = ircd.User(client, server_class=self.ircd, params=params)
            cmd = ' '.join(recv)
            self.ircd.new_sync(self.ircd, client, cmd)
Exemple #23
0
    def pre_hook(self, user, channel, param, action=''):
        if type(user).__name__ == 'User':  # Servers can set modes too.
            hook = 'local_chanmode' if user.server != self.ircd else 'remote_chanmode'
        else:
            hook = 'local_chanmode' if user == self.ircd else 'remote_chanmode'
        # logging.debug('Looking for pre_* hooks for {}'.format(self))

        if self.mode not in self.ircd.core_chmodes and self.type == 0:
            if not hasattr(channel, self.list_name):
                setattr(channel, self.list_name, {})

        for callable in [callable for callable in self.ircd.hooks if callable[0].lower() == 'pre_' + hook and self.mode in callable[1]]:
            try:
                # logging.debug('Calling {} with action {}'.format(callable, action))
                # We pass the modebar to the module hook because we need to know which mode to work on.
                ok = callable[2](user, self.ircd, channel, self.modebuf, self.parambuf, action, self.mode, param)
                if not ok and ok is not None:
                    logging.debug('Further processing halted for {}{}{}'.format(action, self.mode, ' ' + param if param else ''))
                    logging.debug('Blocked by: {}'.format(callable))
                    return 0
            except Exception as ex:
                logging.exception(ex)
        return 1
Exemple #24
0
def LoadModule(self, name, path, reload=False, module=None):
    package = name.replace('/', '.')
    try:
        if reload:
            module = importlib.reload(module)
            logging.debug('Requesting reload from importlib')
        else:
            module = importlib.import_module(package)
            importlib.reload(module)
        if not module.__doc__:
            logging.info('Invalid module.')
            return 'Invalid module'
        callables = FindCallables(module)
        hook_fail = HookToCore(
            self, callables,
            reload=reload)  # If None is returned, assume success.
        if hook_fail:
            logging.debug('Hook failed: {}'.format(hook_fail))
            UnloadModule(self, name)

            return hook_fail
        self.modules[module] = callables
        name = module.__name__
        update_support(self)
        logging.info('Loaded: {}'.format(name))
    except FileNotFoundError as ex:
        return ex
    except Exception as ex:
        logging.exception(ex)
        UnloadModule(self, name)
        # if not reload:
        if not self.running:
            print(
                'Server could not be started due to an error in {}: {}'.format(
                    name, ex))
            sys.exit()
        raise
Exemple #25
0
def hidejoin(self, ircd, channel, **kwargs):
    try:
        if chmode in channel.modes:
            global can_see
            if channel not in can_see:
                can_see[channel] = {}
                logging.debug('/JOIN: Channel {} added to can_see dict'.format(
                    channel.name))
            if self not in can_see[channel]:
                can_see[channel][self] = []
            # <self> just joined <channel>. They can see everyone currently on the channel.
            can_see[channel][self] = list(
                channel.users
            )  # /!\ Do NOT RE-ASSIGN the list. Make a copy! /!\
            for user in [user for user in channel.users if user != self]:
                if visible_in_chan(
                        user, ircd, self,
                        channel) and self not in can_see[channel][user]:
                    can_see[channel][user].append(self)
                    logging.debug('/join: User {} can see {}'.format(
                        user.nickname, self.nickname))
        return 1, 0
    except Exception as ex:
        logging.exception(ex)
Exemple #26
0
    def execute(self, client, recv):
        if type(client).__name__ == 'Server':
            if len(recv) == 1:
                with open(self.ircd.confdir + 'ircd.motd') as f:
                    b_motd = bytes(f.read(), 'utf-8')
                    logging.debug('Sending to remote: {}'.format(b_motd))
                    client._send('MOTD {}'.format(b_motd))
                    return
            else:
                logging.debug('Received remote motd response.')
                logging.debug('Sending reply to: {}'.format(self.ircd.remote_motd_request[client]))
                b_motd = ' '.join(recv[1:])
                logging.debug('Bytes: {}'.format(b_motd))
                self.ircd.remote_motd_request[client].sendraw(self.RPL.ENDOFMOTD, '{} Message of the Day'.format(client.hostname))
                for line in eval(b_motd).decode('utf-8').split('\n'):
                    self.ircd.remote_motd_request[client].sendraw(self.RPL.MOTD, ':- {}'.format(line))
                self.ircd.remote_motd_request[client].sendraw(self.RPL.ENDOFMOTD, ':End of Message of the Day.')

        else:
            if len(recv) == 1:
                client.sendraw(self.RPL.MOTDSTART, '{} Message of the Day'.format(self.ircd.hostname))
                with open(self.ircd.confdir + 'ircd.motd') as f:
                    for line in f.read().split('\n'):
                        client.sendraw(self.RPL.MOTD, ':- {}'.format(line))
                    client.sendraw(self.RPL.ENDOFMOTD, ':End of Message of the Day.')
            else:
                remoteserver = recv[1].lower()
                if hasattr(self.ircd, 'remote_motd_request') and remoteserver.lower() != self.ircd.hostname.lower():
                    server_exists = [server for server in self.ircd.servers if server.hostname.lower() == remoteserver]
                    if not server_exists and remoteserver != self.ircd.hostname:
                        return client.sendraw(402, '{} :No such server'.format(remoteserver))
                    if not server_exists[0].socket:  ### Will fix hops later.
                        return self.ircd.notice(client, '* You can only request remote MOTDs from directly linked servers.')
                    if 'o' not in client.modes:
                        client.flood_penalty += 50000
                    server = server_exists[0] if server_exists[0].socket else server_exists[0].introducedBy
                    self.ircd.remote_motd_request[server] = client
                    server._send('MOTD')
Exemple #27
0
    def quit(self,
             reason,
             error=True,
             banmsg=None,
             kill=False,
             silent=False,
             api=False,
             squit=False):  # Why source?
        try:
            if not hasattr(self, 'socket'):
                self.socket = None
            self.recvbuffer = ''
            ircd = self.ircd if not self.socket else self.server
            sourceServer = self.server if (self.server.socket or self.server
                                           == ircd) else self.server.uplink
            if self.registered:
                logging.debug('User {} quit. Uplink source: {}'.format(
                    self.nickname, sourceServer))
            for callable in [
                    callable for callable in ircd.hooks
                    if callable[0].lower() == 'pre_local_quit'
            ]:
                try:
                    callable[2](self, ircd)
                except Exception as ex:
                    logging.exception(ex)

            if banmsg:
                ircd.notice(
                    self,
                    '*** You are banned from this server: {}'.format(banmsg))

            if int(
                    time.time()
            ) - self.signon < 60 and self.registered and not error and self.socket:
                reason = str(ircd.conf['settings']['quitprefix']).strip()
                if reason.endswith(':'):
                    reason = reason[:-1]
                reason += ': ' + self.nickname

            if self.socket and reason and not api:
                self._send('ERROR :Closing link: [{}] ({})'.format(
                    self.hostname, reason))

            while self.sendbuffer:
                # logging.info('User {} has sendbuffer remaining: {}'.format(self, self.sendbuffer.rstrip()))
                try:
                    sent = self.socket.send(
                        bytes(self.sendbuffer + '\n', 'utf-8'))
                    self.sendbuffer = self.sendbuffer[sent:]
                except:
                    break

            if self in ircd.pings:
                del ircd.pings[self]
                # logging.debug('Removed {} from server PING check'.format(self))

            if self.registered and (self.server == ircd or self.server.eos):
                if reason and not kill:
                    skip = [sourceServer]
                    if squit:
                        for server in [
                                server for server in ircd.servers
                                if hasattr(server, 'protoctl')
                                and 'NOQUIT' in server.protoctl
                        ]:  # and not server.eos]:
                            skip.append(server)
                    ircd.new_sync(ircd, skip,
                                  ':{} QUIT :{}'.format(self.uid, reason))

                if self.socket and reason and not silent:
                    ircd.snotice(
                        'c', '*** Client exiting: {} ({}@{}) ({})'.format(
                            self.nickname, self.ident, self.hostname, reason))

            self.registered = False

            for channel in iter(
                [channel for channel in self.channels
                 if 'j' in channel.modes]):
                self.handle('PART', '{}'.format(channel.name))
                continue

            # Check module hooks for visible_in_channel()

            # FIX: [05:57:26] * vknzvmwlcrcdzz ([email protected]) Quit (Write error: [Errno 110] Connection timed out)
            # IN STATUS WINDOW?

            all_broadcast = [self]
            for channel in self.channels:
                for user in channel.users:
                    if user not in all_broadcast and user != self:
                        all_broadcast.append(user)
            inv_checked = 0
            for u in iter([u for u in all_broadcast if u != self]):
                visible = 0
                for channel in iter(
                    [chan for chan in self.channels if not visible]):
                    for callable in [
                            callable for callable in ircd.hooks
                            if callable[0].lower() == 'visible_in_channel'
                    ]:
                        try:
                            visible = callable[2](u, ircd, self, channel)
                            inv_checked = 1
                            # logging.debug('Is {} visible for {} on {}? :: {}'.format(self.nickname, u.nickname, channel.name, visible))
                        except Exception as ex:
                            logging.exception(ex)
                    if visible:  # Break out of the channels loop. No further checks are required.
                        break
                if not visible and inv_checked:
                    logging.debug(
                        'User {} is not allowed to see {} on any channel, not sending quit.'
                        .format(u.nickname, self.nickname))
                    all_broadcast.remove(u)

            if self.nickname != '*' and self.ident != '' and reason:
                self.broadcast(all_broadcast, 'QUIT :{}'.format(reason))

            for channel in list(self.channels):
                channel.users.remove(self)
                del channel.usermodes[self]
                self.channels.remove(channel)
                if len(channel.users) == 0 and 'P' not in channel.modes:
                    ircd.channels.remove(channel)
                    del ircd.chan_params[channel]
                    for callable in [
                            callable for callable in ircd.hooks
                            if callable[0].lower() == 'channel_destroy'
                    ]:
                        try:
                            callable[2](self, ircd, channel)
                        except Exception as ex:
                            logging.exception(ex)

            watch_notify_offline = iter([
                user for user in ircd.users if self.nickname.lower() in
                [x.lower() for x in user.watchlist]
            ])
            for user in watch_notify_offline:
                user.sendraw(
                    RPL.LOGOFF, '{} {} {} {} :logged offline'.format(
                        self.nickname, self.ident, self.cloakhost,
                        self.signon))

            if self in ircd.users:
                ircd.users.remove(self)

            if self.socket:
                if ircd.use_poll:
                    ircd.pollerObject.unregister(self.socket)
                try:
                    self.socket.shutdown(socket.SHUT_WR)
                except:
                    pass
                self.socket.close()

            hook = 'local_quit' if self.server == ircd else 'remote_quit'
            for callable in [
                    callable for callable in ircd.hooks
                    if callable[0].lower() == hook
            ]:
                try:
                    callable[2](self, ircd)
                except Exception as ex:
                    logging.exception(ex)

            gc.collect()
            del gc.garbage[:]

            if not ircd.forked:
                try:
                    logging.debug('Growth after self.quit() (if any):')
                    objgraph.show_growth(limit=10)
                except:  # Prevent weird spam shit.
                    pass

            del self

        except Exception as ex:
            logging.exception(ex)
Exemple #28
0
    def welcome(self):
        if not self.registered:
            for callable in [
                    callable for callable in self.server.hooks
                    if callable[0].lower() == 'pre_local_connect'
            ]:
                try:
                    success = callable[2](self, self.server)
                    if not success and success is not None:  # Modules need to explicitly return False or 0, not the default None.
                        logging.debug(
                            f"Connection process denied for user {self} by module: {callable}"
                        )
                        return
                except Exception as ex:
                    logging.exception(ex)

            deny, reason = 0, ''
            if self.ip in self.server.deny_cache:
                deny = 1
                if 'reason' in self.server.deny_cache[self.ip]:
                    reason = self.server.deny_cache[self.ip]['reason']

            deny_except = False
            if 'except' in self.server.conf and 'deny' in self.server.conf[
                    'except']:
                for e in self.server.conf['except']['deny']:
                    if match(e, self.ident + '@' + self.ip) or match(
                            e, self.ident + '@' + self.hostname):
                        deny_except = True
                        break

            if not deny_except and not deny:
                for entry in self.server.deny:
                    if match(entry, self.ident + '@' + self.ip) or match(
                            entry, self.ident + '@' + self.hostname):
                        self.server.deny_cache[self.ip] = {}
                        self.server.deny_cache[self.ip]['ctime'] = int(
                            time.time())
                        reason = self.server.deny[entry] if self.server.deny[
                            entry] else ''
                        self.server.deny_cache[self.ip]['reason'] = reason
                        logging.info(
                            'Denied client {} with match: {} [{}]'.format(
                                self, entry, reason))
                        deny = 1
                        break

            if deny:
                if reason:
                    self.server.notice(
                        self, '* Connection denied: {}'.format(reason))
                return self.quit(
                    'Your host matches a deny block, and is therefore not allowed.'
                )

            block = 0
            for cls in iter([
                    cls for cls in self.server.conf['allow']
                    if cls in self.server.conf['class']
            ]):
                t = self.server.conf['allow'][cls]
                isMatch = False
                if 'ip' in t:
                    clientmask = '{}@{}'.format(self.ident, self.ip)
                    isMatch = match(t['ip'], clientmask)
                if 'hostname' in t and not isMatch:  # Try with hostname. IP has higher priority.
                    clientmask = '{}@{}'.format(self.ident, self.hostname)
                    isMatch = match(t['hostname'], clientmask)
                if isMatch:
                    if 'options' in t:
                        if 'ssl' in t['options'] and not self.ssl:
                            continue
                    self.cls = cls
                    if 'block' in t:
                        for entry in t['block']:
                            clientmask_ip = '{}@{}'.format(self.ident, self.ip)
                            clientmask_host = '{}@{}'.format(
                                self.ident, self.hostname)
                            block = match(entry, clientmask_ip) or match(
                                entry, clientmask_host)
                            if block:
                                logging.info(
                                    'Client {} blocked by {}: {}'.format(
                                        self, cls, entry))
                                break
                    break

            if not self.cls or block:
                return self.quit(
                    'You are not authorized to connect to this server')

            totalClasses = list(
                filter(lambda u: u.server == self.server and u.cls == self.cls,
                       self.server.users))
            if len(totalClasses) > int(
                    self.server.conf['class'][self.cls]['max']):
                return self.quit('Maximum connections for this class reached')

            clones = [
                u for u in self.server.users if u.socket and u.ip == self.ip
            ]
            if len(clones) >= int(
                    self.server.conf['allow'][self.cls]['maxperip']):
                return self.quit('Maximum connections from your IP')

            # Resolve IP in the background to test against deny-block matches, if host resolution is disabled.
            if 'dontresolve' in self.server.conf['settings']:
                threading.Thread(target=resolve_ip, args=([self])).start()

            if not hasattr(self, 'socket'):
                return
            self.sendraw(
                RPL.WELCOME, ':Welcome to the {} IRC Network {}!{}@{}'.format(
                    self.server.name, self.nickname, self.ident,
                    self.hostname))
            self.sendraw(
                RPL.YOURHOST, ':Your host is {}, running version {}'.format(
                    self.server.hostname, self.server.version))
            d = datetime.datetime.fromtimestamp(
                self.server.creationtime).strftime('%a %b %d %Y')
            t = datetime.datetime.fromtimestamp(
                self.server.creationtime).strftime('%H:%M:%S %Z')
            self.sendraw(RPL.CREATED,
                         ':This server was created {} at {}'.format(d, t))

            umodes, chmodes = '', ''
            for m in iter([
                    m for m in self.server.user_modes
                    if m.isalpha() and m not in umodes
            ]):
                umodes += m
            for t in self.server.channel_modes:
                for m in iter([
                        m for m in self.server.channel_modes[t]
                        if m.isalpha() and m not in chmodes
                ]):
                    chmodes += m
            umodes = ''.join(sorted(set(umodes)))
            chmodes = ''.join(sorted(set(chmodes)))

            self.sendraw(
                RPL.MYINFO,
                '{} {} {} {}'.format(self.server.hostname, self.server.version,
                                     umodes, chmodes))
            show_support(self, self.server)
            cipher = None
            if self.ssl and hasattr(self.socket,
                                    'cipher') and self.socket.cipher:
                if self.socket.cipher():
                    cipher = self.socket.cipher()[0]
                    self.send(
                        'NOTICE',
                        ':*** You are connected to {} with {}-{}'.format(
                            self.server.hostname, self.socket.version(),
                            cipher))

            msg = '*** Client connecting: {u.nickname} ({u.ident}@{u.hostname}) {{{u.cls}}} [{0}{1}]'.format(
                'secure' if self.ssl else 'plain',
                '' if not cipher else ' ' + cipher,
                u=self)
            self.server.snotice('c', msg)

            binip = IPtoBase64(self.ip) if self.ip.replace(
                '.', '').isdigit() else self.ip
            data = '{s.nickname} {s.server.hopcount} {s.signon} {s.ident} {s.hostname} {s.uid} 0 +{s.modes} {s.cloakhost} {s.cloakhost} {0} :{s.realname}'.format(
                binip, s=self)
            self.server.new_sync(self.server, self.server,
                                 ':{} UID {}'.format(self.server.sid, data))

            self.registered = True

            current_lusers = len([
                user for user in self.server.users
                if user.server == self.server and user.registered
            ])
            if current_lusers > self.server.maxusers:
                self.server.maxusers = current_lusers

            if len(self.server.users) > self.server.maxgusers:
                self.server.maxgusers = len(self.server.users)
                if self.server.maxgusers % 10 == 0:
                    self.server.snotice(
                        's', '*** New global user record: {}'.format(
                            self.server.maxgusers))

            self.handle('lusers')
            self.handle('motd')
            for callable in [
                    callable for callable in self.server.hooks
                    if callable[0].lower() == 'welcome'
            ]:
                try:
                    callable[2](self, self.server)
                except Exception as ex:
                    logging.exception(ex)
            if self.fingerprint:
                self.send(
                    'NOTICE',
                    ':*** Your TLS fingerprint is {}'.format(self.fingerprint))
                data = 'MD client {} certfp :{}'.format(
                    self.uid, self.fingerprint)
                self.server.new_sync(self.server, self.server,
                                     ':{} {}'.format(self.server.sid, data))

            modes = []
            for mode in self.server.conf['settings']['modesonconnect']:
                if mode in self.server.user_modes and mode not in 'oqrzS':
                    modes.append(mode)
            if self.ssl and hasattr(self.socket, 'cipher'):
                modes.append('z')
            if len(modes) > 0:
                p = {'override': True}
                self.handle('mode',
                            '{} +{}'.format(self.nickname, ''.join(modes)),
                            params=p)

            watch_notify = iter([
                user for user in self.server.users if self.nickname.lower() in
                [x.lower() for x in user.watchlist]
            ])
            for user in watch_notify:
                user.sendraw(
                    RPL.LOGON, '{} {} {} {} :logged online'.format(
                        self.nickname, self.ident, self.cloakhost,
                        self.signon))

            for callable in [
                    callable for callable in self.server.hooks
                    if callable[0].lower() == 'local_connect'
            ]:
                try:
                    callable[2](self, self.server)
                except Exception as ex:
                    logging.exception(ex)

        gc.collect()
Exemple #29
0
    def __init__(self,
                 server,
                 sock=None,
                 address=None,
                 is_ssl=None,
                 server_class=None,
                 params=None):
        try:
            self.socket = sock
            self.server = None
            self.cloakhost = '*'
            self.connected = True
            self.nickname = '*'
            self.ident = ''
            self.hostname = ''
            self.realname = ''
            self.svid = '*'
            self.channels = []
            self.modes = ''
            self.operflags = []
            self.snomasks = ''
            self.swhois = []
            self.watchlist = []
            self.caplist = []
            self.sends_cap = False
            self.cap_end = False
            self.watchC = False
            self.watchS = False
            self.ssl = is_ssl

            self.operaccount = ''
            self.away = False
            self.sendbuffer = ''
            self.operswhois = ''
            self.fingerprint = None

            self.flood_penalty = 0
            self.flood_penalty_time = 0

            if self.socket:
                self.server = server
                self.ircd = server
                self.addr = address
                self.ip, self.hostname = self.addr[0], self.addr[0]
                if self.ip.startswith('::ffff:') and self.ip[7:].replace(
                        '.', '').isdigit():
                    # logging.debug('Invalid IPv6, using {}'.format(self.ip[7:]))
                    self.ip = self.ip[7:]
                if self.hostname.startswith(
                        '::ffff:') and self.hostname[7:].replace('.',
                                                                 '').isdigit():
                    # logging.debug('Invalid IPv6, using {}'.format(self.ip[7:]))
                    self.hostname = self.hostname[7:]

                self.cls = None
                self.signon = int(time.time())
                self.registered = False
                self.ping = int(time.time())
                self.recvbuffer = ''
                self.validping = False
                self.server_pass_accepted = False
                self.uid = '{}{}'.format(
                    self.server.sid, ''.join(
                        random.choice(string.ascii_uppercase + string.digits)
                        for _ in range(6)))
                while [
                        u for u in self.server.users if hasattr(u, 'uid')
                        and u != self and u.uid == self.uid
                ]:
                    # while list(filter(lambda u: u.uid == self.uid, self.server.users)):
                    self.uid = '{}{}'.format(
                        self.server.sid, ''.join(
                            random.choice(string.ascii_uppercase +
                                          string.digits) for _ in range(6)))

                self.lastPingSent = time.time() * 1000
                self.lag_measure = self.lastPingSent

                self.server.users.append(self)
                for callable in [
                        callable for callable in server.hooks
                        if callable[0].lower() == 'new_connection'
                ]:
                    try:
                        callable[2](self, server)
                    except Exception as ex:
                        logging.exception(ex)
                if 'dnsbl' in self.server.conf and self.ip.replace(
                        '.', '').isdigit() and not ipaddress.ip_address(
                            self.ip).is_private:
                    # self.sendraw('020', ':Please wait while we process your connection.')
                    dnsbl_except = False
                    if 'except' in self.server.conf and 'dnsbl' in self.server.conf[
                            'except']:
                        for e in self.server.conf['except']['dnsbl']:
                            if match(e, self.ip):
                                dnsbl_except = True
                                break
                    if not dnsbl_except:
                        DNSBLCheck(self)

                TKL.check(self, self.server, self, 'z')
                TKL.check(self, self.server, self, 'Z')

                throttleTreshhold = int(
                    self.server.conf['settings']['throttle'].split(':')[0])
                throttleTime = int(
                    self.server.conf['settings']['throttle'].split(':')[1])
                total_conns = [
                    u for u in self.server.throttle
                    if u.ip == self.ip and int(time.time()) -
                    self.server.throttle[u]['ctime'] <= throttleTime
                ]
                throttle_except = False
                if 'except' in self.server.conf and 'throttle' in self.server.conf[
                        'except']:
                    for e in self.server.conf['except']['throttle']:
                        if match(e, self.ip):
                            throttle_except = True
                            break
                if len(total_conns
                       ) >= throttleTreshhold and not throttle_except:
                    self.quit('Throttling - You are (re)connecting too fast')

                unknown_conn = [
                    user for user in self.server.users
                    if user.ip == self.ip and not user.registered
                ]
                if len(unknown_conn) > 20:
                    self.quit('Too many unknown connections from your IP')

                self.server.throttle[self] = {}
                self.server.throttle[self]['ip'] = self.ip
                self.server.throttle[self]['ctime'] = int(time.time())
                self.server.totalcons += 1

                if self.ssl and self.socket:
                    try:
                        fp = self.socket.getpeercert(binary_form=True)
                        if fp:
                            self.fingerprint = hashlib.sha256(
                                repr(fp).encode('utf-8')).hexdigest()
                    except Exception as ex:
                        logging.exception(ex)

                self.idle = int(time.time())
                if self.ip in self.server.hostcache:
                    self.hostname = self.server.hostcache[self.ip]['host']
                    self._send(
                        ':{u.server.hostname} NOTICE AUTH :*** Found your hostname ({u.hostname}) [cached]'
                        .format(u=self))
                elif 'dontresolve' not in self.server.conf['settings'] or (
                        'dontresolve' in self.server.conf['settings']
                        and not self.server.conf['settings']['dontresolve']):
                    try:
                        self.hostname = socket.gethostbyaddr(self.ip)[0]
                        if not self.hostname.split('.')[1]:
                            raise
                        self.server.hostcache[self.ip] = {}
                        self.server.hostcache[self.ip]['host'] = self.hostname
                        self.server.hostcache[self.ip]['ctime'] = int(
                            time.time())
                        self._send(
                            ':{u.server.hostname} NOTICE AUTH :*** Found your hostname ({u.hostname})'
                            .format(u=self))
                    except Exception as ex:
                        self.hostname = self.ip
                        # self._send(':{} NOTICE AUTH :*** Couldn\'t resolve your hostname; using IP address instead ({})'.format(self.server.hostname, self.hostname))
                        self._send(
                            ':{u.server.hostname} NOTICE AUTH :*** Couldn\'t resolve your hostname; using IP address instead ({u.hostname})'
                            .format(u=self))
                else:
                    self._send(
                        ':{u.server.hostname} NOTICE AUTH :*** Host resolution is disabled, using IP ({u.ip})'
                        .format(u=self))

                TKL.check(self, self.server, self, 'g')
                TKL.check(self, self.server, self, 'G')

                self.cloakhost = cloak(self)

            else:
                try:
                    self.origin = server_class
                    self.ircd = server_class
                    self.origin.users.append(self)
                    self.cls = 0
                    self.nickname = params[2]
                    self.idle = int(params[4])
                    self.signon = int(params[4])
                    self.ident = params[5]
                    self.hostname = params[6]
                    self.uid = params[7]
                    server = list(
                        filter(lambda s: s.sid == params[0][1:],
                               self.ircd.servers))
                    if not server:
                        logging.debug(
                            f'Quitting {self.nickname} because their server does not exist'
                        )
                        self.quit('Unknown connection')
                        return
                    self.server = server[0]
                    self.modes = params[9].strip('+')
                    if params[11] == '*':
                        self.cloakhost = params[6]
                    else:
                        self.cloakhost = params[11]
                    if params[12] != '*' and not params[12].replace(
                            '.', '').isdigit() and params[12] is not None:
                        self.ip = Base64toIP(params[12])
                    else:
                        self.ip = params[12]
                    self.realname = ' '.join(params[13:])[1:]
                    self.registered = True
                    TKL.check(self, self.origin, self, 'Z')
                    TKL.check(self, self.origin, self, 'G')
                    if len(self.origin.users) > self.origin.maxgusers:
                        self.origin.maxgusers = len(self.origin.users)

                    watch_notify = iter([
                        user for user in self.origin.users
                        if self.nickname.lower() in
                        [x.lower() for x in user.watchlist]
                    ])
                    for user in watch_notify:
                        user.sendraw(
                            RPL.LOGON, '{} {} {} {} :logged online'.format(
                                self.nickname, self.ident, self.cloakhost,
                                self.signon))

                    # msg = '*** Remote client connecting: {} ({}@{}) {{{}}} [{}{}]'.format(self.nickname, self.ident, self.hostname, str(self.cls), 'secure' if 'z' in self.modes else 'plain', ' '+self.socket.cipher()[0] if self.ssl else '')
                    # self.server.snotice('C', msg)
                except Exception as ex:
                    logging.exception(ex)
            # logging.info('New user class {} successfully created'.format(self))
            gc.collect()

        except Exception as ex:
            logging.exception(ex)
Exemple #30
0
 def __del__(self):
     # pass
     logging.debug('User {} closed'.format(self))