mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-04-07 10:56:49 +00:00
Merge branch '1010-config-flag'
This commit is contained in:
commit
4b21f605ad
@ -324,6 +324,23 @@ set the ``tub.location`` option described below.
|
||||
used for files that usually (on a Unix system) go into ``/tmp``. The
|
||||
string will be interpreted relative to the node's base directory.
|
||||
|
||||
``reveal-IP-address = (boolean, optional, defaults to True)``
|
||||
|
||||
This is a safety flag. If False, any of the following configuration
|
||||
problems will cause ``tahoe start`` to throw a PrivacyError instead of
|
||||
starting the node:
|
||||
|
||||
* ``[node] tub.location`` contains any ``tcp:`` hints
|
||||
|
||||
* ``[node] tub.location`` uses ``AUTO``, or is missing/empty (because
|
||||
that defaults to AUTO)
|
||||
|
||||
* ``[connections] tcp =`` is set to ``tcp`` (or left as the default),
|
||||
rather than being set to ``tor``
|
||||
|
||||
These configuration problems would reveal the node's IP address to
|
||||
servers and external networks.
|
||||
|
||||
|
||||
Connection Management
|
||||
=====================
|
||||
@ -334,6 +351,10 @@ also controls when Tor and I2P are used: for all TCP connections (to hide
|
||||
your IP address), or only when necessary (just for servers which declare that
|
||||
they need Tor, because they use ``.onion`` addresses).
|
||||
|
||||
Note that if you want to protect your node's IP address, you should set
|
||||
``[node] reveal-IP-address = False``, which will refuse to launch the node if
|
||||
any of the other configuration settings might violate this privacy property.
|
||||
|
||||
``[connections]``
|
||||
-----------------
|
||||
|
||||
|
@ -14,6 +14,21 @@ from allmydata.util.fileutil import abspath_expanduser_unicode
|
||||
from allmydata.util.encodingutil import get_filesystem_encoding, quote_output
|
||||
from allmydata.util import configutil
|
||||
|
||||
def _import_tor():
|
||||
# this exists to be overridden by unit tests
|
||||
try:
|
||||
from foolscap.connections import tor
|
||||
return tor
|
||||
except ImportError: # pragma: no cover
|
||||
return None
|
||||
|
||||
def _import_i2p():
|
||||
try:
|
||||
from foolscap.connections import i2p
|
||||
return i2p
|
||||
except ImportError: # pragma: no cover
|
||||
return None
|
||||
|
||||
# Add our application versions to the data that Foolscap's LogPublisher
|
||||
# reports.
|
||||
for thing, things_version in get_package_versions().iteritems():
|
||||
@ -61,6 +76,9 @@ class UnescapedHashError(Exception):
|
||||
return ("The configuration entry %s contained an unescaped '#' character."
|
||||
% quote_output("[%s]%s = %s" % self.args))
|
||||
|
||||
class PrivacyError(Exception):
|
||||
"""reveal-IP-address = false, but the node is configured in such a way
|
||||
that the IP address could be revealed"""
|
||||
|
||||
class Node(service.MultiService):
|
||||
# this implements common functionality of both Client nodes and Introducer
|
||||
@ -84,6 +102,7 @@ class Node(service.MultiService):
|
||||
assert type(self.nickname) is unicode
|
||||
|
||||
self.init_tempdir()
|
||||
self.check_privacy()
|
||||
self.init_connections()
|
||||
self.set_tub_options()
|
||||
self.create_main_tub()
|
||||
@ -166,6 +185,10 @@ class Node(service.MultiService):
|
||||
twlog.msg(e)
|
||||
raise e
|
||||
|
||||
def check_privacy(self):
|
||||
self._reveal_ip = self.get_config("node", "reveal-IP-address", True,
|
||||
boolean=True)
|
||||
|
||||
def _make_tcp_handler(self):
|
||||
# this is always available
|
||||
from foolscap.connections.tcp import default
|
||||
@ -175,9 +198,8 @@ class Node(service.MultiService):
|
||||
enabled = self.get_config("tor", "enable", True, boolean=True)
|
||||
if not enabled:
|
||||
return None
|
||||
try:
|
||||
from foolscap.connections import tor
|
||||
except ImportError:
|
||||
tor = _import_tor()
|
||||
if not tor:
|
||||
return None
|
||||
|
||||
if self.get_config("tor", "launch", False, boolean=True):
|
||||
@ -215,9 +237,8 @@ class Node(service.MultiService):
|
||||
enabled = self.get_config("i2p", "enable", True, boolean=True)
|
||||
if not enabled:
|
||||
return None
|
||||
try:
|
||||
from foolscap.connections import i2p
|
||||
except ImportError:
|
||||
i2p = _import_i2p()
|
||||
if not i2p:
|
||||
return None
|
||||
|
||||
samport = self.get_config("i2p", "sam.port", None)
|
||||
@ -259,8 +280,17 @@ class Node(service.MultiService):
|
||||
raise ValueError("'tahoe.cfg [connections] tcp='"
|
||||
" uses unknown handler type '%s'"
|
||||
% tcp_handler_name)
|
||||
if not handlers[tcp_handler_name]:
|
||||
raise ValueError("'tahoe.cfg [connections] tcp=' uses "
|
||||
"unavailable/unimportable handler type '%s'. "
|
||||
"Please pip install tahoe-lafs[%s] to fix."
|
||||
% (tcp_handler_name, tcp_handler_name))
|
||||
self._default_connection_handlers["tcp"] = tcp_handler_name
|
||||
|
||||
if not self._reveal_ip:
|
||||
if self._default_connection_handlers["tcp"] == "tcp":
|
||||
raise PrivacyError("tcp = tcp, must be set to 'tor'")
|
||||
|
||||
def set_tub_options(self):
|
||||
self.tub_options = {
|
||||
"logLocalFailures": True,
|
||||
@ -321,6 +351,8 @@ class Node(service.MultiService):
|
||||
# addresses. Don't probe for local addresses unless necessary.
|
||||
split_location = location.split(",")
|
||||
if "AUTO" in split_location:
|
||||
if not self._reveal_ip:
|
||||
raise PrivacyError("tub.location uses AUTO")
|
||||
local_addresses = iputil.get_local_addresses_sync()
|
||||
# tubport must be like "tcp:12345" or "tcp:12345:morestuff"
|
||||
local_portnum = int(tubport.split(":")[1])
|
||||
@ -330,6 +362,10 @@ class Node(service.MultiService):
|
||||
new_locations.extend(["tcp:%s:%d" % (ip, local_portnum)
|
||||
for ip in local_addresses])
|
||||
else:
|
||||
if not self._reveal_ip:
|
||||
hint_type = loc.split(":")[0]
|
||||
if hint_type == "tcp":
|
||||
raise PrivacyError("tub.location includes tcp: hint")
|
||||
new_locations.append(loc)
|
||||
return ",".join(new_locations)
|
||||
|
||||
|
@ -5,12 +5,13 @@ from twisted.trial import unittest
|
||||
from twisted.internet import reactor, endpoints
|
||||
from ConfigParser import SafeConfigParser
|
||||
from foolscap.connections import tcp
|
||||
from ..node import Node
|
||||
from ..node import Node, PrivacyError
|
||||
|
||||
class FakeNode(Node):
|
||||
def __init__(self, config_str):
|
||||
self.config = SafeConfigParser()
|
||||
self.config.readfp(BytesIO(config_str))
|
||||
self._reveal_ip = True
|
||||
|
||||
BASECONFIG = ("[client]\n"
|
||||
"introducer.furl = \n"
|
||||
@ -29,6 +30,12 @@ class Tor(unittest.TestCase):
|
||||
h = n._make_tor_handler()
|
||||
self.assertEqual(h, None)
|
||||
|
||||
def test_unimportable(self):
|
||||
n = FakeNode(BASECONFIG)
|
||||
with mock.patch("allmydata.node._import_tor", return_value=None):
|
||||
h = n._make_tor_handler()
|
||||
self.assertEqual(h, None)
|
||||
|
||||
def test_default(self):
|
||||
n = FakeNode(BASECONFIG)
|
||||
h1 = mock.Mock()
|
||||
@ -109,6 +116,12 @@ class I2P(unittest.TestCase):
|
||||
h = n._make_i2p_handler()
|
||||
self.assertEqual(h, None)
|
||||
|
||||
def test_unimportable(self):
|
||||
n = FakeNode(BASECONFIG)
|
||||
with mock.patch("allmydata.node._import_i2p", return_value=None):
|
||||
h = n._make_i2p_handler()
|
||||
self.assertEqual(h, None)
|
||||
|
||||
def test_default(self):
|
||||
n = FakeNode(BASECONFIG)
|
||||
h1 = mock.Mock()
|
||||
@ -204,8 +217,72 @@ class Connections(unittest.TestCase):
|
||||
self.assertEqual(n._default_connection_handlers["tor"], "tor")
|
||||
self.assertEqual(n._default_connection_handlers["i2p"], "i2p")
|
||||
|
||||
def test_tor_unimportable(self):
|
||||
n = FakeNode(BASECONFIG+"[connections]\ntcp = tor\n")
|
||||
with mock.patch("allmydata.node._import_tor", return_value=None):
|
||||
e = self.assertRaises(ValueError, n.init_connections)
|
||||
self.assertEqual(str(e),
|
||||
"'tahoe.cfg [connections] tcp='"
|
||||
" uses unavailable/unimportable handler type 'tor'."
|
||||
" Please pip install tahoe-lafs[tor] to fix.")
|
||||
|
||||
def test_unknown(self):
|
||||
n = FakeNode(BASECONFIG+"[connections]\ntcp = unknown\n")
|
||||
e = self.assertRaises(ValueError, n.init_connections)
|
||||
self.assertIn("'tahoe.cfg [connections] tcp='", str(e))
|
||||
self.assertIn("uses unknown handler type 'unknown'", str(e))
|
||||
|
||||
class Privacy(unittest.TestCase):
|
||||
def test_flag(self):
|
||||
n = FakeNode(BASECONFIG)
|
||||
n.check_privacy()
|
||||
self.assertTrue(n._reveal_ip)
|
||||
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = true\n")
|
||||
n.check_privacy()
|
||||
self.assertTrue(n._reveal_ip)
|
||||
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n")
|
||||
n.check_privacy()
|
||||
self.assertFalse(n._reveal_ip)
|
||||
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-ip-address = false\n")
|
||||
n.check_privacy()
|
||||
self.assertFalse(n._reveal_ip)
|
||||
|
||||
def test_connections(self):
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n")
|
||||
n.check_privacy()
|
||||
e = self.assertRaises(PrivacyError, n.init_connections)
|
||||
self.assertEqual(str(e), "tcp = tcp, must be set to 'tor'")
|
||||
|
||||
def test_tub_location_auto(self):
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n")
|
||||
n._portnumfile = "missing"
|
||||
n.check_privacy()
|
||||
e = self.assertRaises(PrivacyError, n.get_tub_location, None)
|
||||
self.assertEqual(str(e), "tub.location uses AUTO")
|
||||
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n" +
|
||||
"tub.location = AUTO\n")
|
||||
n._portnumfile = "missing"
|
||||
n.check_privacy()
|
||||
e = self.assertRaises(PrivacyError, n.get_tub_location, None)
|
||||
self.assertEqual(str(e), "tub.location uses AUTO")
|
||||
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n" +
|
||||
"tub.location = AUTO,tcp:hostname:1234\n")
|
||||
n._portnumfile = "missing"
|
||||
n.check_privacy()
|
||||
e = self.assertRaises(PrivacyError, n.get_tub_location, None)
|
||||
self.assertEqual(str(e), "tub.location uses AUTO")
|
||||
|
||||
def test_tub_location_tcp(self):
|
||||
n = FakeNode(BASECONFIG+"[node]\nreveal-IP-address = false\n" +
|
||||
"tub.location = tcp:hostname:1234\n")
|
||||
n._portnumfile = "missing"
|
||||
n.check_privacy()
|
||||
e = self.assertRaises(PrivacyError, n.get_tub_location, None)
|
||||
self.assertEqual(str(e), "tub.location includes tcp: hint")
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user