Closes #1538. Refactors 'onionservicesonly' to 'onlynet=onion', prevents bootstrapping from non-onion nodes when true, and prevents bootstrapping from any node but the trusted peer (when set) #1694

Open
sgj3 wants to merge 2 commits from sgj3/issue1538 into v0.6
4 changed files with 64 additions and 19 deletions

View File

@ -358,6 +358,11 @@ class SettingsDialog(QtGui.QDialog):
if proxytype_index > 2: # last literal proxytype in ui if proxytype_index > 2: # last literal proxytype in ui
start_proxyconfig() start_proxyconfig()
onionOnly_deprecated = BMConfigParser().safeGetBoolean(
"bitmessagesettings", "onionservicesonly")
onionOnly = BMConfigParser().safeGet(
"bitmessagesettings", "onlynet") == "onion"
onionOnly = onionOnly or onionOnly_deprecated
self.config.set('bitmessagesettings', 'socksauthentication', str( self.config.set('bitmessagesettings', 'socksauthentication', str(
self.checkBoxAuthentication.isChecked())) self.checkBoxAuthentication.isChecked()))
self.config.set('bitmessagesettings', 'sockshostname', str( self.config.set('bitmessagesettings', 'sockshostname', str(
@ -371,10 +376,20 @@ class SettingsDialog(QtGui.QDialog):
self.config.set('bitmessagesettings', 'sockslisten', str( self.config.set('bitmessagesettings', 'sockslisten', str(
self.checkBoxSocksListen.isChecked())) self.checkBoxSocksListen.isChecked()))
if self.checkBoxOnionOnly.isChecked() \ if self.checkBoxOnionOnly.isChecked() \
and not self.config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'): and not onionOnly:
self.net_restart_needed = True self.net_restart_needed = True
self.config.set('bitmessagesettings', 'onionservicesonly', str( if self.checkBoxOnionOnly.isChecked():
self.checkBoxOnionOnly.isChecked())) self.config.set('bitmessagesettings', 'onlynet', 'onion')
else:
try:
return self.config.remove_option('bitmessagesettings', 'onlynet')
except ConfigParser.NoOptionError:
pass
# Remove deprecated onionservicesonly option if it exists:
try:
return self.config.remove_option('bitmessagesettings', 'onionservicesonly')
except ConfigParser.NoOptionError:
pass
try: try:
# Rounding to integers just for aesthetics # Rounding to integers just for aesthetics
self.config.set('bitmessagesettings', 'maxdownloadrate', str( self.config.set('bitmessagesettings', 'maxdownloadrate', str(

View File

@ -31,8 +31,11 @@ def chooseConnection(stream):
"""Returns an appropriate connection""" """Returns an appropriate connection"""
haveOnion = BMConfigParser().safeGet( haveOnion = BMConfigParser().safeGet(
"bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' "bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS'
onionOnly = BMConfigParser().safeGetBoolean( onionOnly_deprecated = BMConfigParser().safeGetBoolean(
"bitmessagesettings", "onionservicesonly") "bitmessagesettings", "onionservicesonly")
onionOnly = BMConfigParser().safeGet(
"bitmessagesettings", "onlynet") == "onion"
onionOnly = onionOnly or onionOnly_deprecated
try: try:
retval = portCheckerQueue.get(False) retval = portCheckerQueue.get(False)
portCheckerQueue.task_done() portCheckerQueue.task_done()

View File

@ -51,6 +51,12 @@ class BMConnectionPool(object):
BMConfigParser().safeGetInt( BMConfigParser().safeGetInt(
"bitmessagesettings", "maxuploadrate") "bitmessagesettings", "maxuploadrate")
) )
onionOnly_deprecated = BMConfigParser().safeGetBoolean(
"bitmessagesettings", "onionservicesonly")
onionOnly = BMConfigParser().safeGet(
"bitmessagesettings", "onlynet") == "onion"
self.onionOnly = onionOnly or onionOnly_deprecated
self.outboundConnections = {} self.outboundConnections = {}
self.inboundConnections = {} self.inboundConnections = {}
self.listeningSockets = {} self.listeningSockets = {}
@ -205,17 +211,17 @@ class BMConnectionPool(object):
def startBootstrappers(self): def startBootstrappers(self):
"""Run the process of resolving bootstrap hostnames""" """Run the process of resolving bootstrap hostnames"""
onion_seed = 'quzwelsuziwqgpt2.onion' # FIXME onion bootstrap server is down
proxy_type = BMConfigParser().safeGet( proxy_type = BMConfigParser().safeGet(
'bitmessagesettings', 'socksproxytype') 'bitmessagesettings', 'socksproxytype')
# A plugins may be added here # A plugins may be added here
hostname = None hostname = None
port = 8444
if not proxy_type or proxy_type == 'none': if not proxy_type or proxy_type == 'none':
connection_base = TCPConnection connection_base = TCPConnection
elif proxy_type == 'SOCKS5': elif proxy_type == 'SOCKS5':
connection_base = Socks5BMConnection connection_base = Socks5BMConnection
hostname = helper_random.randomchoice([
'quzwelsuziwqgpt2.onion', None
])
elif proxy_type == 'SOCKS4a': elif proxy_type == 'SOCKS4a':
connection_base = Socks4aBMConnection # FIXME: I cannot test connection_base = Socks4aBMConnection # FIXME: I cannot test
else: else:
@ -223,12 +229,21 @@ class BMConnectionPool(object):
# is handled in bitmessagemain before starting the connectionpool # is handled in bitmessagemain before starting the connectionpool
return return
bootstrapper = bootstrap(connection_base) if self.trustedPeer is not None:
if not hostname: hostname = self.trustedPeer.host
port = self.trustedPeer.port
elif proxy_type == "SOCKS5" or self.onionOnly:
if self.onionOnly:
hostname = onion_seed
else:
hostname = helper_random.randomchoice([
onion_seed, None])
if hostname is None:
port = helper_random.randomchoice([8080, 8444]) port = helper_random.randomchoice([8080, 8444])
hostname = 'bootstrap%s.bitmessage.org' % port hostname = 'bootstrap%s.bitmessage.org' % port
else:
port = 8444 bootstrapper = bootstrap(connection_base)
self.addConnection(bootstrapper(hostname, port)) self.addConnection(bootstrapper(hostname, port))
def loop(self): # pylint: disable=too-many-branches,too-many-statements def loop(self): # pylint: disable=too-many-branches,too-many-statements

View File

@ -194,14 +194,7 @@ class TestCore(unittest.TestCase):
start_proxyconfig() start_proxyconfig()
self._check_bootstrap() self._check_bootstrap()
@unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test') def _check_exclusively_onion_networking(self):
def test_onionservicesonly(self): # this should start after bootstrap
"""
set onionservicesonly, wait for 3 connections and check them all
are onions
"""
BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true')
self._initiate_bootstrap() self._initiate_bootstrap()
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
for _ in range(360): for _ in range(360):
@ -218,6 +211,25 @@ class TestCore(unittest.TestCase):
% peer.host) % peer.host)
self.fail('Failed to connect to at least 3 nodes within 360 sec') self.fail('Failed to connect to at least 3 nodes within 360 sec')
@unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test')
def test_onionservicesonly(self): # this should start after bootstrap
"""
set onionservicesonly (deprecated), wait for 3 connections and check
that all are onions
"""
BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true')
self._check_exclusively_onion_networking()
@unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test')
def test_onlynetonion(self): # this should start after bootstrap
"""
set onlynet=onion, wait for 3 connections and check that all are onions
"""
BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
BMConfigParser().set('bitmessagesettings', 'onlynet', 'onion')
self._check_exclusively_onion_networking()
@staticmethod @staticmethod
def _decode_msg(data, pattern): def _decode_msg(data, pattern):
proto = BMProto() proto = BMProto()