From 320524910da8c945e1a85a87548f2baef3c0683b Mon Sep 17 00:00:00 2001 From: meejah Date: Sun, 30 Sep 2018 00:16:51 -0600 Subject: [PATCH 1/8] release note --- docs/releases.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/releases.rst b/docs/releases.rst index 8de19077..2d589dd9 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -21,6 +21,9 @@ unreleased `git master `_ *will likely become v19.0.0* + * `non_anonymous=` flag for :func:`txtorcon.launch` + + v18.3.0 ------- From 272eb4ea3bf606de135604a973d14db545c04190 Mon Sep 17 00:00:00 2001 From: meejah Date: Sun, 30 Sep 2018 00:14:31 -0600 Subject: [PATCH 2/8] non-anonymous mode for launch() --- txtorcon/controller.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/txtorcon/controller.py b/txtorcon/controller.py index a1004a15..5fc6017e 100644 --- a/txtorcon/controller.py +++ b/txtorcon/controller.py @@ -55,6 +55,7 @@ def launch(reactor, control_port=None, data_directory=None, socks_port=None, + non_anonymous_mode=None, stdout=None, stderr=None, timeout=None, @@ -110,6 +111,14 @@ def launch(reactor, faster. If ``None`` (the default), we create a tempdir for this **and delete it on exit**. It is recommended you pass something here. + :param non_anonymous_mode: sets the Tor options + `HiddenServiceSingleHopMode` and + `HiddenServiceNonAnonymousMode` to 1 and un-sets any + `SOCKSPort` config, thus putting this Tor client into + "non-anonymous mode" which allows starting so-called Single + Onion services -- which use single-hop circuits to rendezvous + points. See WARNINGs in Tor manual! + :param stdout: a file-like object to which we write anything that Tor prints on stdout (just needs to support write()). @@ -221,9 +230,18 @@ def launch(reactor, except KeyError: socks_port = None - if socks_port is None: - socks_port = yield available_tcp_port(reactor) - config.SOCKSPort = socks_port + if non_anonymous_mode: + if socks_port is not None: + raise ValueError( + "Cannot use SOCKS options with non_anonymous_mode=True" + ) + config.HiddenServiceNonAnonymousMode = 1 + config.HiddenServiceSingleHopMode = 1 + config.SOCKSPort = 0 + else: + if socks_port is None: + socks_port = yield available_tcp_port(reactor) + config.SOCKSPort = socks_port try: our_user = user or config.User @@ -350,6 +368,7 @@ def launch(reactor, config.protocol, _tor_config=config, _process_proto=process_protocol, + _non_anonymous=True if non_anonymous_mode else False, ) ) @@ -474,7 +493,7 @@ def main(reactor): print(port.getHost()) """ - def __init__(self, reactor, control_protocol, _tor_config=None, _process_proto=None): + def __init__(self, reactor, control_protocol, _tor_config=None, _process_proto=None, _non_anonymous=None): """ don't instantiate this class yourself -- instead use the factory methods :func:`txtorcon.launch` or :func:`txtorcon.connect` @@ -487,6 +506,8 @@ def __init__(self, reactor, control_protocol, _tor_config=None, _process_proto=N # cache our preferred socks port (please use # self._default_socks_endpoint() to get one) self._socks_endpoint = None + # True if we've turned on non-anonymous mode / Onion services + self._non_anonymous = _non_anonymous @inlineCallbacks def quit(self): @@ -552,6 +573,10 @@ def web_agent(self, pool=None, socks_endpoint=None): :param pool: passed on to the Agent (as ``pool=``) """ + if self._non_anonymous: + raise Exception( + "Cannot use web_agent when in non_anonymous mode" + ) # local import since not all platforms have this from txtorcon import web @@ -932,6 +957,10 @@ def _default_socks_endpoint(self): (which might mean setting one up in our attacked Tor if it doesn't have one) """ + if self._non_anonymous: + raise Exception( + "Cannot use SOCKS when in non_anonymous mode" + ) if self._socks_endpoint is None: self._socks_endpoint = yield _create_socks_endpoint(self._reactor, self._protocol) returnValue(self._socks_endpoint) From 555bf48ee71d6103506aca2e784bbf49b9057d84 Mon Sep 17 00:00:00 2001 From: meejah Date: Sun, 30 Sep 2018 00:14:36 -0600 Subject: [PATCH 3/8] whitespace --- txtorcon/onion.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/txtorcon/onion.py b/txtorcon/onion.py index 6817a84d..52650d49 100644 --- a/txtorcon/onion.py +++ b/txtorcon/onion.py @@ -170,7 +170,11 @@ class FilesystemOnionService(object): @staticmethod @defer.inlineCallbacks - def create(reactor, config, hsdir, ports, version=3, group_readable=False, progress=None, await_all_uploads=None): + def create(reactor, config, hsdir, ports, + version=3, + group_readable=False, + progress=None, + await_all_uploads=None): """ returns a new FilesystemOnionService after adding it to the provided config and ensuring at least one of its descriptors @@ -1076,7 +1080,12 @@ class FilesystemAuthenticatedOnionService(object): @staticmethod @defer.inlineCallbacks - def create(reactor, config, hsdir, ports, auth=None, version=3, group_readable=False, progress=None, await_all_uploads=None): + def create(reactor, config, hsdir, ports, + auth=None, + version=3, + group_readable=False, + progress=None, + await_all_uploads=None): """ returns a new FilesystemAuthenticatedOnionService after adding it to the provided config and ensureing at least one of its From 6459300e385aef143d2e70b139e5fa45cf3af6ba Mon Sep 17 00:00:00 2001 From: meejah Date: Sun, 30 Sep 2018 01:42:54 -0600 Subject: [PATCH 4/8] tests for non-anonymous mode --- test/test_controller.py | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/test_controller.py b/test/test_controller.py index 618f2d17..41ed508a 100644 --- a/test/test_controller.py +++ b/test/test_controller.py @@ -236,6 +236,20 @@ def test_launch_tor_unix_controlport_no_directory(self): ) self.assertTrue("must exist" in str(ctx.exception)) + @defer.inlineCallbacks + def test_launch_tor_non_anonymous_and_socks(self): + reactor = FakeReactor(self, Mock(), None, [9050]) + with self.assertRaises(ValueError) as ctx: + yield launch( + reactor, + non_anonymous_mode=True, + socks_port=1234, + tor_binary="/bin/echo", + stdout=Mock(), + stderr=Mock(), + ) + self.assertIn("Cannot use SOCKS", str(ctx.exception)) + @patch('txtorcon.controller.find_tor_binary', return_value='/bin/echo') @defer.inlineCallbacks def test_launch_fails(self, ftb): @@ -290,6 +304,35 @@ def foo(*args, **kw): tor = yield launch(reactor, _tor_config=config) self.assertTrue(isinstance(tor, Tor)) + @patch('txtorcon.controller.find_tor_binary', return_value='/bin/echo') + @patch('txtorcon.controller.TorProcessProtocol') + @defer.inlineCallbacks + def test_successful_launch_non_anonymous(self, tpp, ftb): + trans = FakeProcessTransport() + reactor = FakeReactor(self, trans, lambda p: None, [1, 2, 3]) + config = TorConfig() + + def boot(arg=None): + config.post_bootstrap.callback(config) + config.__dict__['bootstrap'] = Mock(side_effect=boot) + config.__dict__['attach_protocol'] = Mock(return_value=defer.succeed(None)) + + def foo(*args, **kw): + rtn = Mock() + rtn.post_bootstrap = defer.succeed(None) + rtn.when_connected = Mock(return_value=defer.succeed(rtn)) + return rtn + tpp.side_effect = foo + + tor = yield launch(reactor, _tor_config=config, non_anonymous_mode=True) + self.assertTrue(isinstance(tor, Tor)) + self.assertTrue(config.HiddenServiceNonAnonymousMode) + + with self.assertRaises(Exception): + yield tor.web_agent() + with self.assertRaises(Exception): + yield tor.dns_resolve('meejah.ca') + @defer.inlineCallbacks def test_quit(self): tor = Tor(Mock(), Mock()) From b159efc6c498469c723d94dfe169d33446edd34e Mon Sep 17 00:00:00 2001 From: meejah Date: Sun, 30 Sep 2018 01:54:09 -0600 Subject: [PATCH 5/8] release note --- docs/releases.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases.rst b/docs/releases.rst index 2d589dd9..4d1abd92 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -38,7 +38,7 @@ v18.2.0 * add `privateKeyFile=` option to endpoint parser (ticket 313) * use `privateKey=` option properly in endpoint parser * support `NonAnonymous` mode for `ADD_ONION` via `single_hop=` kwarg - + * support `non_anonymous_mode=` for :func:`txtorcon.launch` v18.1.0 ------- From 29e5111fb94ba45c0fb2ae93a4564d7087481166 Mon Sep 17 00:00:00 2001 From: meejah Date: Mon, 1 Oct 2018 14:02:19 -0600 Subject: [PATCH 6/8] whitespace --- docs/releases.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases.rst b/docs/releases.rst index 4d1abd92..1bd33383 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -40,6 +40,7 @@ v18.2.0 * support `NonAnonymous` mode for `ADD_ONION` via `single_hop=` kwarg * support `non_anonymous_mode=` for :func:`txtorcon.launch` + v18.1.0 ------- From 6fa00b8b5d74be957e45defa9a0135fc6b7907a4 Mon Sep 17 00:00:00 2001 From: meejah Date: Mon, 1 Oct 2018 15:27:14 -0600 Subject: [PATCH 7/8] better description --- docs/releases.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/releases.rst b/docs/releases.rst index 1bd33383..6c7a2207 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -21,7 +21,7 @@ unreleased `git master `_ *will likely become v19.0.0* - * `non_anonymous=` flag for :func:`txtorcon.launch` + * support `non_anonymous_mode=` for :func:`txtorcon.launch` v18.3.0 @@ -38,7 +38,6 @@ v18.2.0 * add `privateKeyFile=` option to endpoint parser (ticket 313) * use `privateKey=` option properly in endpoint parser * support `NonAnonymous` mode for `ADD_ONION` via `single_hop=` kwarg - * support `non_anonymous_mode=` for :func:`txtorcon.launch` v18.1.0 From 15ce355c579bb43ade5f5a2bee52eb671347a955 Mon Sep 17 00:00:00 2001 From: meejah Date: Mon, 8 Oct 2018 10:59:11 -0600 Subject: [PATCH 8/8] release note --- docs/releases.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases.rst b/docs/releases.rst index 6c7a2207..0f0b7b7e 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -21,7 +21,7 @@ unreleased `git master `_ *will likely become v19.0.0* - * support `non_anonymous_mode=` for :func:`txtorcon.launch` + * introduce `non_anonymous_mode=` kwarg for :func:`txtorcon.launch` v18.3.0