From 95c848a7201ab47e635bf54263777937998df8cb Mon Sep 17 00:00:00 2001 From: Shane Moore Date: Wed, 30 Nov 2016 23:50:20 -0800 Subject: [PATCH 1/3] Add IRC option to publish Tor address --- docs/ENV-NOTES | 7 +++-- server/env.py | 1 + server/irc.py | 79 +++++++++++++++++++++++++++++++++++--------------- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/docs/ENV-NOTES b/docs/ENV-NOTES index f51004e..32fe2b0 100644 --- a/docs/ENV-NOTES +++ b/docs/ENV-NOTES @@ -90,8 +90,11 @@ IRC - set to anything non-empty IRC_NICK - the nick to use when connecting to IRC. The default is a hash of REPORT_HOST. Either way 'E_' will be prepended. REPORT_HOST - the host to advertise. Defaults to HOST. -REPORT_SSL_PORT - the SSL port to advertise. Defaults to SSL_PORT. +REPORT_HOST_TOR - Tor .onion address to advertise. Uses TCP/SSL_PORT rather + - than REPORT_* ports. REPORT_TCP_PORT - the TCP port to advertise. Defaults to TCP_PORT. + - '0' disables publishing the port for public use. +REPORT_SSL_PORT - the SSL port to advertise. Defaults to SSL_PORT. If synchronizing from the Genesis block your performance might change by tweaking the following cache variables. Cache size is only checked @@ -124,4 +127,4 @@ FORCE_REORG - if set to a positive integer, it will simulate a reorg of the blockchain for that number of blocks on startup. Although it should fail gracefully if set to a value greater than REORG_LIMIT, I do not recommend it as I have - not tried it and there is a chance your DB might corrupt. \ No newline at end of file + not tried it and there is a chance your DB might corrupt. diff --git a/server/env.py b/server/env.py index 58b8b9d..57d931f 100644 --- a/server/env.py +++ b/server/env.py @@ -54,6 +54,7 @@ class Env(LoggedClass): self.report_tcp_port = self.integer('REPORT_TCP_PORT', self.tcp_port) self.report_ssl_port = self.integer('REPORT_SSL_PORT', self.ssl_port) self.report_host = self.default('REPORT_HOST', self.host) + self.report_host_tor = self.default('REPORT_HOST_TOR', None) self.irc_nick = self.default('IRC_NICK', None) self.irc = self.default('IRC', False) # Debugging diff --git a/server/irc.py b/server/irc.py index 7930d07..6365fd1 100644 --- a/server/irc.py +++ b/server/irc.py @@ -20,12 +20,8 @@ from lib.hash import double_sha256 from lib.util import LoggedClass -def port_text(letter, port, default): - if not port: - return '' - if port == default: - return letter - return letter + str(port) +VERSION = '1.0' +DEFAULT_PORTS = {'t': 50001, 's': 50002} class IRC(LoggedClass): @@ -37,22 +33,29 @@ class IRC(LoggedClass): def __init__(self, env): super().__init__() - tcp_text = port_text('t', env.report_tcp_port, 50001) - ssl_text = port_text('s', env.report_ssl_port, 50002) - # If this isn't something the client expects you won't appear - # in the client's network dialog box self.env = env - version = '1.0' - self.real_name = '{} v{} {} {}'.format(env.report_host, version, - tcp_text, ssl_text) + + # If this isn't something a peer or client expects + # then you won't appear in the client's network dialog box + irc_address = (env.coin.IRC_SERVER, env.coin.IRC_PORT) + self.channel = env.coin.IRC_CHANNEL self.prefix = env.coin.IRC_PREFIX + + self.clients = [] self.nick = '{}{}'.format(self.prefix, env.irc_nick if env.irc_nick else double_sha256(env.report_host.encode()) [:5].hex()) - self.channel = env.coin.IRC_CHANNEL - self.irc_server = env.coin.IRC_SERVER - self.irc_port = env.coin.IRC_PORT + self.clients.append( IrcClient(irc_address, self.nick, + env.report_host, + env.report_tcp_port, + env.report_ssl_port) ) + if env.report_host_tor: + self.clients.append( IrcClient(irc_address, self.nick + '_tor', + env.report_host_tor, + env.tcp_port, + env.ssl_port) ) + self.peer_regexp = re.compile('({}[^!]*)!'.format(self.prefix)) self.peers = {} @@ -72,20 +75,23 @@ class IRC(LoggedClass): async def join(self): import irc.client as irc_client - self.logger.info('joining IRC with nick "{}" and real name "{}"' - .format(self.nick, self.real_name)) - reactor = irc_client.Reactor() for event in ['welcome', 'join', 'quit', 'kick', 'whoreply', 'namreply', 'disconnect']: reactor.add_global_handler(event, getattr(self, 'on_' + event)) - connection = reactor.server() + # Note: Multiple nicks in same channel will trigger duplicate events + for client in self.clients: + client.connection = reactor.server() + while True: try: - connection.connect(self.irc_server, self.irc_port, - self.nick, ircname=self.real_name) - connection.set_keepalive(60) + for client in self.clients: + self.logger.info('Joining IRC in {} as "{}" with ' + 'real name "{}"' + .format(self.channel, client.nick, + client.realname)) + client.connect() while True: reactor.process_once() await asyncio.sleep(2) @@ -155,3 +161,30 @@ class IRC(LoggedClass): self.peers[nick] = peer except IndexError: pass + + +class IrcClient(LoggedClass): + + def __init__(self, irc_address, nick, host, tcp_port, ssl_port): + super().__init__() + self.irc_host, self.irc_port = irc_address + self.nick = nick + self.realname = IrcClient.create_realname(host, tcp_port, ssl_port) + self.connection = None + + + def connect(self, keepalive=60): + '''Connect this client to its IRC server''' + self.connection.connect(self.irc_host, self.irc_port, self.nick, + ircname=self.realname) + self.connection.set_keepalive(keepalive) + + + def create_realname(host, tcp_port, ssl_port): + def port_text(letter, port): + return letter if letter in DEFAULT_PORTS + and port == DEFAULT_PORTS[letter] + else letter + str(port) + tcp = ' ' + port_text('t', tcp_port) if tcp_port else '' + ssl = ' ' + port_text('s', ssl_port) if ssl_port else '' + return '{} v{}{}{}'.format(host, VERSION, tcp, ssl) From 33c5bd65aa79df133fd9d6b3d22c89e655925d94 Mon Sep 17 00:00:00 2001 From: Shane Moore Date: Thu, 1 Dec 2016 02:25:21 -0800 Subject: [PATCH 2/3] Fix IRC port bug, more readable --- server/irc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/irc.py b/server/irc.py index 6365fd1..c0d8cc1 100644 --- a/server/irc.py +++ b/server/irc.py @@ -182,9 +182,10 @@ class IrcClient(LoggedClass): def create_realname(host, tcp_port, ssl_port): def port_text(letter, port): - return letter if letter in DEFAULT_PORTS - and port == DEFAULT_PORTS[letter] - else letter + str(port) + if letter in DEFAULT_PORTS and port == DEFAULT_PORTS[letter]: + return letter + else: + return letter + str(port) tcp = ' ' + port_text('t', tcp_port) if tcp_port else '' ssl = ' ' + port_text('s', ssl_port) if ssl_port else '' return '{} v{}{}{}'.format(host, VERSION, tcp, ssl) From 0edff0056de038eb46e0133ef15de48581976732 Mon Sep 17 00:00:00 2001 From: Shane Moore Date: Thu, 1 Dec 2016 03:21:52 -0800 Subject: [PATCH 3/3] Add Tor-specific port options for IRC --- docs/ENV-NOTES | 24 +++++++++++++++--------- server/env.py | 12 ++++++++++-- server/irc.py | 4 ++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/ENV-NOTES b/docs/ENV-NOTES index 32fe2b0..26048a6 100644 --- a/docs/ENV-NOTES +++ b/docs/ENV-NOTES @@ -86,15 +86,21 @@ BANDWIDTH_LIMIT - per-session periodic bandwith usage limit in bytes. If you want IRC connectivity to advertise your node: -IRC - set to anything non-empty -IRC_NICK - the nick to use when connecting to IRC. The default is a - hash of REPORT_HOST. Either way 'E_' will be prepended. -REPORT_HOST - the host to advertise. Defaults to HOST. -REPORT_HOST_TOR - Tor .onion address to advertise. Uses TCP/SSL_PORT rather - - than REPORT_* ports. -REPORT_TCP_PORT - the TCP port to advertise. Defaults to TCP_PORT. - - '0' disables publishing the port for public use. -REPORT_SSL_PORT - the SSL port to advertise. Defaults to SSL_PORT. +IRC - set to anything non-empty +IRC_NICK - the nick to use when connecting to IRC. The default is a + hash of REPORT_HOST. Either way 'E_' will be prepended. +REPORT_HOST - the host to advertise. Defaults to HOST. +REPORT_TCP_PORT - the TCP port to advertise. Defaults to TCP_PORT. + '0' disables publishing the port. +REPORT_SSL_PORT - the SSL port to advertise. Defaults to SSL_PORT. + '0' disables publishing the port. +REPORT_HOST_TOR - Tor .onion address to advertise. Appends '_tor" to nick. +REPORT_TCP_PORT_TOR - the TCP port to advertise for Tor. Defaults to + REPORT_TCP_PORT, unless it is '0', then use TCP_PORT. + '0' disables publishing the port. +REPORT_SSL_PORT_TOR - the SSL port to advertise for Tor. Defaults to + REPORT_SSL_PORT, unless it is '0', then use SSL_PORT. + '0' disables publishing the port. If synchronizing from the Genesis block your performance might change by tweaking the following cache variables. Cache size is only checked diff --git a/server/env.py b/server/env.py index 57d931f..2b875a4 100644 --- a/server/env.py +++ b/server/env.py @@ -51,12 +51,20 @@ class Env(LoggedClass): self.max_session_subs = self.integer('MAX_SESSION_SUBS', 50000) self.bandwidth_limit = self.integer('BANDWIDTH_LIMIT', 2000000) # IRC + self.irc = self.default('IRC', False) + self.irc_nick = self.default('IRC_NICK', None) self.report_tcp_port = self.integer('REPORT_TCP_PORT', self.tcp_port) self.report_ssl_port = self.integer('REPORT_SSL_PORT', self.ssl_port) self.report_host = self.default('REPORT_HOST', self.host) + self.report_tcp_port_tor = self.integer('REPORT_TCP_PORT_TOR', + self.report_tcp_port + if self.report_tcp_port else + self.tcp_port) + self.report_ssl_port_tor = self.integer('REPORT_SSL_PORT_TOR', + self.report_ssl_port + if self.report_ssl_port else + self.ssl_port) self.report_host_tor = self.default('REPORT_HOST_TOR', None) - self.irc_nick = self.default('IRC_NICK', None) - self.irc = self.default('IRC', False) # Debugging self.force_reorg = self.integer('FORCE_REORG', 0) diff --git a/server/irc.py b/server/irc.py index c0d8cc1..fb73da5 100644 --- a/server/irc.py +++ b/server/irc.py @@ -53,8 +53,8 @@ class IRC(LoggedClass): if env.report_host_tor: self.clients.append( IrcClient(irc_address, self.nick + '_tor', env.report_host_tor, - env.tcp_port, - env.ssl_port) ) + env.report_tcp_port_tor, + env.report_ssl_port_tor) ) self.peer_regexp = re.compile('({}[^!]*)!'.format(self.prefix)) self.peers = {}