From 9976bd439ac50be56908f11f3e3bd0896641c8f7 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Wed, 12 Nov 2008 18:44:58 -0700 Subject: [PATCH] tahoe.cfg: add tub.location, to override the location hints we include in our FURL. This replaces advertised_ip_addresses, which doesn't remain useful enough to retain it. Helps with #517 (Tor). --- NEWS | 7 +- docs/configuration.txt | 104 ++++++++++++++++++++++----- src/allmydata/node.py | 30 ++------ src/allmydata/scripts/create_node.py | 2 +- src/allmydata/test/test_node.py | 36 ++++------ 5 files changed, 111 insertions(+), 68 deletions(-) diff --git a/NEWS b/NEWS index d12e50db..3302133c 100644 --- a/NEWS +++ b/NEWS @@ -53,9 +53,10 @@ connection. docs/frontends/webapi.txt has details. The Tahoe node is now configured with a single INI-format file, named "tahoe.cfg", in the node's base directory. Most of the previous multiple-separate-files are still read for backwards compatibility (the -embedded SSH debug server is the exception), but new directives will only be -added to tahoe.cfg . The "tahoe create-client" command will create a -tahoe.cfg for you, with sample values commented out. (ticket #518) +embedded SSH debug server and the advertised_ip_addresses files are the +exceptions), but new directives will only be added to tahoe.cfg . The "tahoe +create-client" command will create a tahoe.cfg for you, with sample values +commented out. (ticket #518) tahoe.cfg now has controls for the foolscap "keepalive" and "disconnect" timeouts (#521). diff --git a/docs/configuration.txt b/docs/configuration.txt index 2bfdc481..2d92fef1 100644 --- a/docs/configuration.txt +++ b/docs/configuration.txt @@ -77,22 +77,83 @@ tub.port = (integer, optional) port. The port will be written to a separate file (named client.port or introducer.port), so that subsequent runs will re-use the same port. -advertised_ip_addresses = (comma-separated host[:port] string, optional) +tub.location = (string, optional) - The node normally uses tools like 'ifconfig' to determine the set of IP - addresses on which it can be reached from nodes both near and far. The node - introduces itself to the rest of the grid with a FURL that contains a series - of (ipaddr, port) pairs which other nodes will use to contact this one. By - providing this file, you can add to this list. This can be useful if your - node is running behind a firewall, but you have created a port-forwarding to - allow the outside world to access it. Each line must have a dotted-quad IP - address and an optional :portnum specification, like: + In addition to running as a client, each Tahoe node also runs as a server, + listening for connections from other Tahoe clients. The node announces its + location by publishing a "FURL" (a string with some connection hints) to the + Introducer. The string it publishes can be found in + $BASEDIR/private/storage.furl . The "tub.location" configuration controls + what location is published in this announcement. - 123.45.67.89 - 44.55.66.77:8098 + If you don't provide tub.location, the node will try to figure out a useful + one by itself, by using tools like 'ifconfig' to determine the set of IP + addresses on which it can be reached from nodes both near and far. It will + also include the TCP port number on which it is listening (either the one + specified by tub.port, or whichever port was assigned by the kernel when + tub.port is left unspecified). - Lines that do not provide a port number will use the same client.port as the - automatically-discovered addresses. + 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. + + 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 + + A few examples: + + Emulate default behavior, assuming your host has IP address 123.45.67.89 + and the kernel-allocated port number was 8098: + + tub.port = 8098 + tub.location = 123.45.67.89:8098,127.0.0.1:8098 + + Use a DNS name so you can change the IP address more easily: + + tub.port = 8098 + tub.location = tahoe.example.com:8098 + + Run a node behind a firewall (which has an external IP address) that has + been configured to forward port 7912 to our internal node's port 8098: + + tub.port = 8098 + tub.location = external-firewall.example.com:7912 + + Run a node behind a Tor proxy (perhaps via tsocks), 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": + + tub.port = 8098 + tub.location = unreachable.example.org:0 + + 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 node + with tsocks, such that they are prepared to connect to a .onion address). + The hidden service must first be configured in Tor, by giving it a local + port number and then obtaining a .onion name, using something in the torrc + file like: + + HiddenServiceDir /var/lib/tor/hidden_services/tahoe + HiddenServicePort 29212 127.0.0.1:8098 + + once Tor is restarted, the .onion hostname will be in + /var/lib/tor/hidden_services/tahoe/hostname . Then set up your tahoe.cfg + like: + + tub.port = 8098 + tub.location = ualhejtq2p7ohfbb.onion:29212 + + Most users will not need to set tub.location . + + Note that the old 'advertised_ip_addresses' file from earlier releases is no + longer supported. Tahoe 1.3.0 and later will ignore this file. log_gatherer.furl = (FURL, optional) @@ -345,7 +406,7 @@ exists, it will take precedence over the corresponding item in tahoe.cfg . [node]tub.port : BASEDIR/client.port (for Clients, not Introducers) [node]tub.port : BASEDIR/introducer.port (for Introducers, not Clients) (note that, unlike other keys, tahoe.cfg overrides the *.port file) -[node]advertised_ip_addresses : BASEDIR/advertised_ip_addresses (one per line) +[node]tub.location : replaces BASEDIR/advertised_ip_addresses [node]log_gatherer.furl : BASEDIR/log_gatherer.furl (one per line) [node]timeout.keepalive : BASEDIR/keepalive_timeout [node]timeout.disconnect : BASEDIR/disconnect_timeout @@ -367,6 +428,13 @@ file provided the ssh public keys to accept. Support for these files has been removed completely. To ssh into your Tahoe node, add [node]ssh.port and [node].ssh_authorized_keys_file statements to your tahoe.cfg . +Likewise, the functionality of [node]tub.location is a variant of the +now-unsupported BASEDIR/advertised_ip_addresses . The old file was additive +(the addresses specified in advertised_ip_addresses were used in addition to +any that were automatically discovered), whereas the new tahoe.cfg directive +is not (tub.location is used verbatim). + + == Example == The following is a sample tahoe.cfg file, containing values for all keys @@ -374,8 +442,10 @@ described above. Note that this is not a recommended configuration (most of these are not the default values), merely a legal one. [node] -port = 34912 -advertised_ip_addresses = 123.45.67.89,44.55.66.77:8098 +nickname = Bob's Tahoe Node +tub.port = 34912 +tub.location = 123.45.67.89:8098,44.55.66.77:8098 +web.port = 8123 log_gatherer.furl = pb://soklj4y7eok5c3xkmjeqpw@192.168.69.247:44801/eqpwqtzm timeout.keepalive = 240 timeout.disconnect = 1800 @@ -384,8 +454,6 @@ ssh.authorized_keys_file = ~/.ssh/authorized_keys [client] introducer.furl = pb://ok45ssoklj4y7eok5c3xkmj@tahoe.example:44801/ii3uumo -nickname = Bob's Tahoe Node -web.port = 8123 helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@helper.tahoe.example:7054/kk8lhr [storage] diff --git a/src/allmydata/node.py b/src/allmydata/node.py index 0ba5899c..da4b860c 100644 --- a/src/allmydata/node.py +++ b/src/allmydata/node.py @@ -50,7 +50,6 @@ class Node(service.MultiService): NODETYPE = "unknown NODETYPE" PORTNUMFILE = None CERTFILE = "node.pem" - LOCAL_IP_FILE = "advertised_ip_addresses" def __init__(self, basedir="."): service.MultiService.__init__(self) @@ -116,21 +115,6 @@ class Node(service.MultiService): except EnvironmentError: pass - try: - addresses = [] - ipfile = os.path.join(self.basedir, self.LOCAL_IP_FILE) - tubport = int(self.get_config("node", "tub.port", "0")) - for addrline in open(ipfile, "rU"): - mo = ADDR_RE.search(addrline) - if mo: - (addr, dummy, aportnum,) = mo.groups() - if aportnum is None: - aportnum = tubport - addresses.append("%s:%d" % (addr, int(aportnum),)) - self.set_config("node", "advertised_ip_addresses", - ",".join(addresses)) - except EnvironmentError: - pass copy("keepalive_timeout", "node", "timeout.keepalive") copy("disconnect_timeout", "node", "timeout.disconnect") @@ -320,18 +304,16 @@ class Node(service.MultiService): # running, which means after startService. l = self.tub.getListeners()[0] portnum = l.getPortnum() - # record which port we're listening on, so we can grab the same one next time + # record which port we're listening on, so we can grab the same one + # next time open(self._portnumfile, "w").write("%d\n" % portnum) - addresses = [ "%s:%d" % (addr, portnum,) for addr in local_addresses ] - extra_addresses = self.get_config("node", "advertised_ip_addresses", "") - if extra_addresses: - extra_addresses = extra_addresses.split(",") - addresses.extend(extra_addresses) - - location = ",".join(addresses) + 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) self.tub.setLocation(location) + return self.tub def when_tub_ready(self): diff --git a/src/allmydata/scripts/create_node.py b/src/allmydata/scripts/create_node.py index 798a1ccc..b7938280 100644 --- a/src/allmydata/scripts/create_node.py +++ b/src/allmydata/scripts/create_node.py @@ -73,7 +73,7 @@ def write_node_config(c, config): c.write("web.port = %s\n" % webport) c.write("web.static = public_html\n") c.write("#tub.port =\n") - c.write("#advertised_ip_addresses =\n") + c.write("#tub.location = \n") c.write("#log_gatherer.furl =\n") c.write("#timeout.keepalive =\n") c.write("#timeout.disconnect =\n") diff --git a/src/allmydata/test/test_node.py b/src/allmydata/test/test_node.py index 391883eb..1542402b 100644 --- a/src/allmydata/test/test_node.py +++ b/src/allmydata/test/test_node.py @@ -29,11 +29,12 @@ class TestCase(unittest.TestCase, testutil.SignalMixin): d.addCallback(flushEventualQueue) return d - def test_advertised_ip_addresses(self): - basedir = "test_node/test_advertised_ip_addresses" + def test_location(self): + basedir = "test_node/test_location" fileutil.make_dirs(basedir) - f = open(os.path.join(basedir, 'advertised_ip_addresses'),'w') - f.write('1.2.3.4:5') + f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt') + f.write("[node]\n") + f.write("tub.location = 1.2.3.4:5\n") f.close() n = TestNode(basedir) @@ -47,31 +48,22 @@ class TestCase(unittest.TestCase, testutil.SignalMixin): d.addCallback(_check_addresses) return d - def test_advertised_ip_addresses2(self): - basedir = "test_node/test_advertised_ip_addresses2" + def test_location2(self): + basedir = "test_node/test_location2" fileutil.make_dirs(basedir) + f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt') + f.write("[node]\n") + f.write("tub.location = 1.2.3.4:5,example.org:8091\n") + f.close() n = TestNode(basedir) n.setServiceParent(self.parent) d = n.when_tub_ready() - # this lets the 'port' file get written - d.addCallback(lambda res: n.disownServiceParent()) - def _new_node(res): - f = open(os.path.join(basedir, 'advertised_ip_addresses'),'w') - f.write('1.2.3.4\n') - f.write("6.7.8.9\n") - f.close() - n2 = self.node = TestNode(basedir) - n2.setServiceParent(self.parent) - return n2.when_tub_ready() - d.addCallback(_new_node) def _check_addresses(ignored_result): - portfile = os.path.join(basedir, self.node.PORTNUMFILE) - port = int(open(portfile, "r").read().strip()) - furl = self.node.tub.registerReference(n) - self.failUnless(("1.2.3.4:%d" % port) in furl, furl) - self.failUnless(("6.7.8.9:%d" % port) in furl, furl) + furl = n.tub.registerReference(n) + self.failUnless("1.2.3.4:5" in furl, furl) + self.failUnless("example.org:8091" in furl, furl) d.addCallback(_check_addresses) return d -- 2.45.2