From bfa69815b4c9ea20b0a36303c4325b55b9e36d00 Mon Sep 17 00:00:00 2001 From: James Lu Date: Tue, 5 Jul 2016 00:24:23 -0700 Subject: [PATCH] protocols: split things common between nefarious and ts6_common into a new ircs2s_common module --- protocols/ircs2s_common.py | 82 ++++++++++++++++++++++++++++++++++++++ protocols/nefarious.py | 49 +++-------------------- protocols/ts6_common.py | 73 +-------------------------------- 3 files changed, 89 insertions(+), 115 deletions(-) create mode 100644 protocols/ircs2s_common.py diff --git a/protocols/ircs2s_common.py b/protocols/ircs2s_common.py new file mode 100644 index 0000000..188f8c3 --- /dev/null +++ b/protocols/ircs2s_common.py @@ -0,0 +1,82 @@ +""" +ircs2s_common.py: Common base protocol class with functions shared by TS6 and P10-based protocols. +""" + +from pylinkirc.classes import Protocol +from pylinkirc.log import log + +class IRCS2SProtocol(Protocol): + + def handle_kill(self, source, command, args): + """Handles incoming KILLs.""" + killed = args[0] + # Depending on whether the IRCd sends explicit QUIT messages for + # killed clients, the user may or may not have automatically been + # removed from our user list. + # If not, we have to assume that KILL = QUIT and remove them + # ourselves. + data = self.irc.users.get(killed) + if data: + self.removeClient(killed) + + # TS6-style kills look something like this: + # <- :GL KILL 38QAAAAAA :hidden-1C620195!GL (test) + # What we actually want is to format a pretty kill message, in the form + # "Killed (killername (reason))". + + if source in self.irc.users: + # Killer was a user (they're SO fired) + killer = self.irc.users[source].nick + elif source in self.irc.servers: + # Killer was a server (impossible, the machine is always right) + killer = self.irc.servers[source].name + else: + # Killer was... neither? We must have aliens or something. Fallback + # to the given "UID". + killer = source + + # Get the reason, which is enclosed in brackets. + reason = ' '.join(args[1].split(" ")[1:]) + + killmsg = "Killed (%s %s)" % (killer, reason) + + return {'target': killed, 'text': killmsg, 'userdata': data} + + + def handle_squit(self, numeric, command, args): + """Handles incoming SQUITs.""" + # <- ABAAE SQ nefarious.midnight.vpn 0 :test + + split_server = self._getSid(args[0]) + + affected_users = [] + log.debug('(%s) Splitting server %s (reason: %s)', self.irc.name, split_server, args[-1]) + + if split_server not in self.irc.servers: + log.warning("(%s) Tried to split a server (%s) that didn't exist!", self.irc.name, split_server) + return + + # Prevent RuntimeError: dictionary changed size during iteration + old_servers = self.irc.servers.copy() + # Cycle through our list of servers. If any server's uplink is the one that is being SQUIT, + # remove them and all their users too. + for sid, data in old_servers.items(): + if data.uplink == split_server: + log.debug('Server %s also hosts server %s, removing those users too...', split_server, sid) + # Recursively run SQUIT on any other hubs this server may have been connected to. + args = self.handle_squit(sid, 'SQUIT', [sid, "0", + "PyLink: Automatically splitting leaf servers of %s" % sid]) + affected_users += args['users'] + + for user in self.irc.servers[split_server].users.copy(): + affected_users.append(user) + log.debug('Removing client %s (%s)', user, self.irc.users[user].nick) + self.removeClient(user) + + sname = self.irc.servers[split_server].name + uplink = self.irc.servers[split_server].uplink + del self.irc.servers[split_server] + log.debug('(%s) Netsplit affected users: %s', self.irc.name, affected_users) + + return {'target': split_server, 'users': affected_users, 'name': sname, + 'uplink': uplink} diff --git a/protocols/nefarious.py b/protocols/nefarious.py index 63903b1..7cc515b 100644 --- a/protocols/nefarious.py +++ b/protocols/nefarious.py @@ -2,15 +2,14 @@ nefarious.py: Nefarious IRCu protocol module for PyLink. """ -import sys -import os import base64 import struct from ipaddress import ip_address -from pylinkirc import utils +from pylinkirc import utils, structures from pylinkirc.classes import * from pylinkirc.log import log +from pylinkirc.protocols.ircs2s_common import * class P10UIDGenerator(utils.IncrementalUIDGenerator): """Implements an incremental P10 UID Generator.""" @@ -59,7 +58,7 @@ class P10SIDGenerator(): self.currentnum += 1 return sid -class P10Protocol(Protocol): +class P10Protocol(IRCS2SProtocol): def __init__(self, irc): super().__init__(irc) @@ -504,8 +503,8 @@ class P10Protocol(Protocol): # XXX: there HAS to be a better way of doing this def access_sort(key): prefixes, user = key - # This is some hocus pocus. Add the prefixes given for each userpair, - # giving each one a set value. This ensures that 'ohv' > 'oh' > 'ov' > 'o' > 'hv' > 'h' > 'v' > '' + # Add the prefixes given for each userpair, giving each one a set value. This ensures + # that 'ohv' > 'oh' > 'ov' > 'o' > 'hv' > 'h' > 'v' > '' accesses = {'o': 100, 'h': 10, 'v': 1} num = 0 @@ -1181,44 +1180,6 @@ class P10Protocol(Protocol): self.removeClient(killed) return {'target': killed, 'text': args[1], 'userdata': data} - def handle_squit(self, numeric, command, args): - """Handles incoming SQUITs.""" - # <- ABAAE SQ nefarious.midnight.vpn 0 :test - - split_server = self._getSid(args[0]) - - affected_users = [] - log.debug('(%s) Splitting server %s (reason: %s)', self.irc.name, split_server, args[-1]) - - if split_server not in self.irc.servers: - log.warning("(%s) Tried to split a server (%s) that didn't exist!", self.irc.name, split_server) - return - - # Prevent RuntimeError: dictionary changed size during iteration - old_servers = self.irc.servers.copy() - # Cycle through our list of servers. If any server's uplink is the one that is being SQUIT, - # remove them and all their users too. - for sid, data in old_servers.items(): - if data.uplink == split_server: - log.debug('Server %s also hosts server %s, removing those users too...', split_server, sid) - # Recursively run SQUIT on any other hubs this server may have been connected to. - args = self.handle_squit(sid, 'SQUIT', [sid, "0", - "PyLink: Automatically splitting leaf servers of %s" % sid]) - affected_users += args['users'] - - for user in self.irc.servers[split_server].users.copy(): - affected_users.append(user) - log.debug('Removing client %s (%s)', user, self.irc.users[user].nick) - self.removeClient(user) - - sname = self.irc.servers[split_server].name - uplink = self.irc.servers[split_server].uplink - del self.irc.servers[split_server] - log.debug('(%s) Netsplit affected users: %s', self.irc.name, affected_users) - - return {'target': split_server, 'users': affected_users, 'name': sname, - 'uplink': uplink} - def handle_topic(self, source, command, args): """Handles TOPIC changes.""" # <- ABAAA T #test GL!~gl@nefarious.midnight.vpn 1460852591 1460855795 :blah diff --git a/protocols/ts6_common.py b/protocols/ts6_common.py index 5bd19d2..de759bf 100644 --- a/protocols/ts6_common.py +++ b/protocols/ts6_common.py @@ -2,13 +2,12 @@ ts6_common.py: Common base protocol class with functions shared by the UnrealIRCd, InspIRCd, and TS6 protocol modules. """ -import sys -import os import string from pylinkirc import utils, structures from pylinkirc.classes import * from pylinkirc.log import log +from pylinkirc.protocols.ircs2s_common import * class TS6SIDGenerator(): """ @@ -98,7 +97,7 @@ class TS6UIDGenerator(utils.IncrementalUIDGenerator): self.length = 6 super().__init__(sid) -class TS6BaseProtocol(Protocol): +class TS6BaseProtocol(IRCS2SProtocol): def __init__(self, irc): super().__init__(irc) @@ -352,41 +351,6 @@ class TS6BaseProtocol(Protocol): handle_notice = handle_privmsg - def handle_kill(self, source, command, args): - """Handles incoming KILLs.""" - killed = args[0] - # Depending on whether the IRCd sends explicit QUIT messages for - # killed clients, the user may or may not have automatically been - # removed from our user list. - # If not, we have to assume that KILL = QUIT and remove them - # ourselves. - data = self.irc.users.get(killed) - if data: - self.removeClient(killed) - - # TS6-style kills look something like this: - # <- :GL KILL 38QAAAAAA :hidden-1C620195!GL (test) - # What we actually want is to format a pretty kill message, in the form - # "Killed (killername (reason))". - - if source in self.irc.users: - # Killer was a user (they're SO fired) - killer = self.irc.users[source].nick - elif source in self.irc.servers: - # Killer was a server (impossible, the machine is always right) - killer = self.irc.servers[source].name - else: - # Killer was... neither? We must have aliens or something. Fallback - # to the given "UID". - killer = source - - # Get the reason, which is enclosed in brackets. - reason = ' '.join(args[1].split(" ")[1:]) - - killmsg = "Killed (%s %s)" % (killer, reason) - - return {'target': killed, 'text': killmsg, 'userdata': data} - def handle_kick(self, source, command, args): """Handles incoming KICKs.""" # :70MAAAAAA KICK #test 70MAAAAAA :some reason @@ -428,39 +392,6 @@ class TS6BaseProtocol(Protocol): self.irc.users[user].nick = user return {'target': user, 'ts': int(args[1]), 'oldnick': oldnick} - def handle_squit(self, numeric, command, args): - """Handles incoming SQUITs (netsplits).""" - # :70M SQUIT 1ML :Server quit by GL!gl@0::1 - log.debug('handle_squit args: %s', args) - split_server = args[0] - affected_users = [] - log.debug('(%s) Splitting server %s (reason: %s)', self.irc.name, split_server, args[-1]) - if split_server not in self.irc.servers: - log.warning("(%s) Tried to split a server (%s) that didn't exist!", self.irc.name, split_server) - return - - uplink = self.irc.servers[split_server].uplink - - # Prevent RuntimeError: dictionary changed size during iteration - old_servers = self.irc.servers.copy() - for sid, data in old_servers.items(): - if data.uplink == split_server: - log.debug('Server %s also hosts server %s, removing those users too...', split_server, sid) - args = self.handle_squit(sid, 'SQUIT', [sid, "PyLink: Automatically splitting leaf servers of %s" % sid]) - affected_users += args['users'] - - for user in self.irc.servers[split_server].users.copy(): - affected_users.append(user) - log.debug('Removing client %s (%s)', user, self.irc.users[user].nick) - self.removeClient(user) - - sname = self.irc.servers[split_server].name - del self.irc.servers[split_server] - - log.debug('(%s) Netsplit affected users: %s', self.irc.name, affected_users) - return {'target': split_server, 'users': affected_users, 'name': sname, - 'uplink': uplink} - def handle_topic(self, numeric, command, args): """Handles incoming TOPIC changes from clients. For topic bursts, TB (TS6/charybdis) and FTOPIC (InspIRCd) are used instead."""