From ca2a3574346b569da5bd1c2dc49f39367f8f32b3 Mon Sep 17 00:00:00 2001
From: KillYourTV <killyourtv@i2pmail.org>
Date: Wed, 7 Aug 2013 15:16:10 +0000
Subject: [PATCH] use only 127.0.0.1 as local address

---
 docs/configuration.rst          | 24 ++++++++++++++----------
 src/allmydata/node.py           | 22 +++++++++++++++++-----
 src/allmydata/test/test_node.py | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/docs/configuration.rst b/docs/configuration.rst
index f3db298..384b7cc 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -152,12 +152,18 @@ set the ``tub.location`` option described below.
     You might want to override this value if your node lives behind a
     firewall that is doing inbound port forwarding, or if you are using other
     proxies such that the local IP address or port number is not the same one
-    that remote clients should use to connect. You might also want to control
-    this when using a Tor proxy to avoid revealing your actual IP address
-    through the Introducer announcement.
+    that remote clients should use to connect.
 
-    The value is a comma-separated string of host:port location hints, like
-    this::
+    You might also want to control this when using a Tor or I2P proxy to avoid
+    revealing your actual IP addresses through the Introducer announcement.
+    To hide the node's local IP addresses, use a blank value::
+
+      ``tub.location =``
+
+    Note that this is not the same as omitting ``tub.location``.
+
+    When it is not blank, the value is a comma-separated string of
+    ``host:port`` location hints, like this::
 
       123.45.67.89:8098,tahoe.example.com:8098,127.0.0.1:8098
 
@@ -183,13 +189,11 @@ set the ``tub.location`` option described below.
 
     * Run a node behind a Tor proxy (perhaps via ``torsocks``), in
       client-only mode (i.e. we can make outbound connections, but other
-      nodes will not be able to connect to us). The literal
-      '``unreachable.example.org``' will not resolve, but will serve as a
-      reminder to human observers that this node cannot be reached. "Don't
-      call us.. we'll call you"::
+      nodes will not be able to connect to us). "Don't call us..
+      we'll call you"::
 
         tub.port = 8098
-        tub.location = unreachable.example.org:0
+        tub.location =
 
     * Run a node behind a Tor proxy, and make the server available as a Tor
       "hidden service". (This assumes that other clients are running their
diff --git a/src/allmydata/node.py b/src/allmydata/node.py
index 8873e5c..af0cb55 100644
--- a/src/allmydata/node.py
+++ b/src/allmydata/node.py
@@ -305,7 +305,13 @@ class Node(service.MultiService):
 
         service.MultiService.startService(self)
         d = defer.succeed(None)
-        d.addCallback(lambda res: iputil.get_local_addresses_async())
+        location = self.get_config("node", "tub.location", None)
+        if location is None:
+            d = iputil.get_local_addresses_async()
+        else:
+            # 'tub.location=' or 'tub.location=addr:port'. either way, we
+            # don't need to determine our local addresses
+            d = defer.succeed([])
         d.addCallback(self._setup_tub)
         def _ready(res):
             self.log("%s running" % self.NODETYPE)
@@ -378,10 +384,16 @@ class Node(service.MultiService):
         # next time
         fileutil.write_atomically(self._portnumfile, "%d\n" % portnum, mode="")
 
-        base_location = ",".join([ "%s:%d" % (addr, portnum)
-                                   for addr in local_addresses ])
-        location = self.get_config("node", "tub.location", base_location)
-        self.log("Tub location set to %s" % location)
+        location = self.get_config("node", "tub.location", None)
+        if location is None:
+            location = ",".join([ "%s:%d" % (addr, portnum)
+                                  for addr in local_addresses ])
+        elif location == "":
+            # we'd prefer to have no connection-hints, but foolscap can't
+            # handle that, so use 127.0.0.1
+            location = "127.0.0.1:%d" % portnum
+        # otherwise we use location as-is from tahoe.cfg
+        self.log("Tub location set to '%s'" % location)
         self.tub.setLocation(location)
 
         return self.tub
diff --git a/src/allmydata/test/test_node.py b/src/allmydata/test/test_node.py
index 72d6ef8..2e0e04e 100644
--- a/src/allmydata/test/test_node.py
+++ b/src/allmydata/test/test_node.py
@@ -33,6 +33,41 @@ class TestCase(testutil.SignalMixin, unittest.TestCase):
         d.addCallback(flushEventualQueue)
         return d
 
+    # TODO: should use mock decorator from #1301
+    def test_anonymous_location(self):
+        patcher = patch('allmydata.util.iputil.get_local_addresses_async')
+        mock = patcher.__enter__()
+        try:
+            mock.return_value = ["1.2.3.4"]
+
+            basedir = "test_node/test_anonymous_location"
+            fileutil.make_dirs(basedir)
+            fileutil.write(os.path.join(basedir, 'tahoe.cfg'),
+                           "[node]\n"
+                           "tub.location = \n")
+            # "tub.location=" (i.e. empty string) means create FURL with no
+            # connection-hints. Foolscap can't handle that now, so instead we
+            # make one with only 127.0.0.1
+
+            n = TestNode(basedir)
+            n.setServiceParent(self.parent)
+            d = n.when_tub_ready()
+
+            def _check_addresses(ignored_result):
+                furl = n.tub.registerReference(n)
+                self.failIf("1.2.3.4" in furl, furl)
+                self.failUnless("127.0.0.1" in furl, furl)
+
+            d.addCallback(_check_addresses)
+            def cleanup(res):
+                patcher.__exit__()
+                return res
+            d.addBoth(cleanup)
+            return d
+        except:
+            patcher.__exit__()
+            raise
+
     def test_location(self):
         basedir = "test_node/test_location"
         fileutil.make_dirs(basedir)
-- 
1.8.4.rc1

