Reading and Writing Live Tor Configuration

TorConfig

class txtorcon.TorConfig(control=None)

This class abstracts out Tor’s config, and can be used both to create torrc files from nothing and track live configuration of a Tor instance.

Also, it gives easy access to all the configuration options present. This is initialized at “bootstrap” time, providing attribute-based access thereafter. Note that after you set some number of items, you need to do a save() before these are sent to Tor (and then they will be done as one SETCONF).

You may also use this class to construct a configuration from scratch (e.g. to give to txtorcon.launch_tor()). In this case, values are reflected right away. (If we’re not bootstrapped to a Tor, this is the mode).

Note that you do not need to call save() if you’re just using TorConfig to create a .torrc file or for input to launch_tor().

This class also listens for CONF_CHANGED events to update the cached data in the event other controllers (etc) changed it.

There is a lot of magic attribute stuff going on in here (which might be a bad idea, overall) but the intent is that you can just set Tor options and it will all Just Work. For config items that take multiple values, set that to a list. For example:

conf = TorConfig(...)
conf.SOCKSPort = [9050, 1337]
conf.HiddenServices.append(HiddenService(...))

(Incoming objects, like lists, are intercepted and wrapped).

FIXME: when is CONF_CHANGED introduced in Tor? Can we do anything like it for prior versions?

FIXME:

  • HiddenServiceOptions is special: GETCONF on it returns several (well, two) values. Besides adding the two keys ‘by hand’ do we need to do anything special? Can’t we just depend on users doing ‘conf.hiddenservicedir = foo’ AND ‘conf.hiddenserviceport = bar’ before a save() ?

  • once I determine a value is default, is there any way to actually get what this value is?

HiddenService

class txtorcon.HiddenService(config, thedir, ports, auth=[], ver=2, group_readable=0)

Because hidden service configuration is handled specially by Tor, we wrap the config in this class. This corresponds to the HiddenServiceDir, HiddenServicePort, HiddenServiceVersion and HiddenServiceAuthorizeClient lines from the config. If you want multiple HiddenServicePort lines, simply append more strings to the ports member.

To create an additional hidden service, append a new instance of this class to the config (ignore the conf argument):

state.hiddenservices.append(HiddenService('/path/to/dir', ['80 127.0.0.1:1234']))

config is the TorConfig to which this will belong, thedir corresponds to ‘HiddenServiceDir’ and will ultimately contain a ‘hostname’ and ‘private_key’ file, ports is a list of lines corresponding to HiddenServicePort (like ‘80 127.0.0.1:1234’ to advertise a hidden service at port 80 and redirect it internally on 127.0.0.1:1234). auth corresponds to the HiddenServiceAuthenticateClient lines and can be either a string or a list of strings (like ‘basic client0,client1’ or ‘stealth client5,client6’) and ver corresponds to HiddenServiceVersion and is always 2 right now.

XXX FIXME can we avoid having to pass the config object somehow? Like provide a factory-function on TorConfig for users instead?