One answer here might be to let other applications modify Tor's config without needing to learn how to modify the torrc file.
For example, we could imagine a 'tor-bridge' debian package that just adds a torrc.d/bridge-torrc file. Then you could become a bridge without needing a controller and without needing a text editor. We could also imagine a tor-relay deb.
Weasel, what do you think of this idea? Are debs like this a good idea, or is this approach bad precedent because it would bloat the number of total debs in the world too far?
It might also be useful for controllers like Vidalia on OSes where the Tor deb runs as a daemon and doesn't run as the user. In those cases we've talked about having Vidalia launch a script that prompts the user for her root password and then moves the new torrc file into place. Having it move its torrc into a Vidalia-specific name might keep things saner -- and might be doable without root if the torrc.d directory is owned by a group that the Vidalia deb puts the user into, as we might need to do to get ControlSocket going. On the other hand, ultimately it might instead just complicate the issue further once there are two controllers that each write their own config file.
If we do it, we'd want to sort out what to do if lines in different config files contradict each other.
{{{
| debs with just a single config file won't fly
| also, files/dirs in /etc/ being user writable is obviously bad too. it's a privileged escalation attack waiting to happen
| also, yes. conflicts are an issue
| I still think it's a good idea tho. for instance the debian-defaults patch could just be a config file snippet then
|> in what way will they not fly?
| ftp-master will never accept them
| packages cause an overhead. for a single file that's probably too much overhead.
weasel> it probably shouldn't read a hardcoded torrc.d but instead there should be an include directive that can include other files, including handling wildcards
The specific reason I requested this functionality is because I want to be able to easily maintain a centralized list of rogue ExitNodes which can easily pushed out to other servers running tor. (See ticket legacy/trac#3143 (moved).)
But there are obviously other reasons why one might want to dynamically add/change configuration/performance options, while maintaining a base configuration. Some of these changes might even be made frequently.
Right now, I am just using the "-f" option with a simple script which assembles the new configuration to achieve what I want, but being able to dump everything into a directory would be great (either with a hard-coded torrc.d directory, or an include option).
> on tor-relays there is a person talking about the /var/run/tor/control file.am i correct in thinking this is something some package script makes, not toritself?<weasel> arma: on 0.2.2.x debian packages, it's tor's control socket.> oh ho> does it go wherever $piddir is?<weasel> it goes to /var/run/tor. which is also where pid is.> perhaps this person who wants a tor config option for it is asking for areasonable thing<weasel> it's not a config option.<weasel> that's because ControlSocket is something that tor's config stuffappends to rather than replaces.<weasel> and because tor doesn't do tor.d/* style configuration, so I have topatch the settings the package should have into the binary
We outlined some benefits that would have a /etc/tor/torrc.d directory
full of configuration snippets:
The 'tor' package will not (or less) need patches to change the
default settings.
It would make it much easier to implement example setups
(relays, exit relays, bridges) either through a debconf question
or through a system script like 'tor-setup-relay'.
Tails developers will only need to drop a very small extra
configuration file instead of having to rewrite the whole, which
should ease development and reviewing.
Other packages which need a hidden service to work (e.g. 'onioncat')
would be able to create it automatically by installing the proper
configuration snippet. That would enable them to work right after being
installed.
The include directive was asked on legacy/trac#2863 (moved), btw - might be considered a duplicate.
Having a tor.d directory is an okay idea. You'll need a fairly rigorous definition of what order the files in it are read, and how they interact with torrc and the defaults_torrc (if any). (Make sure you understand how the defaults-torrc logic works here before designing anything; make sure it can be reused.)
I think this way would be good:
defaults_torrc gets overruled by /etc/tor/torrc gets overruled by /etc/tor.d/10_something gets overruled by /etc/tor.d/20_somethingelse.
The same in other words:
defaults_torrc: lowest priority
/etc/tor/torrc: normal priority
/etc/tor/tor.d: highest priority
Sourcing /etc/tor.d/ in lexical order, i.e. first source /etc/tor.d/10_something, then source /etc/tor.d/20_somethingelse. If /etc/tor.d/10_something contains "CookieAuthentication 0" and /etc/tor.d/20_somethingelse contains "CookieAuthentication 1", then "CookieAuthentication 1" will win.
This is the way it usually works on Linux for folders such as /etc/profile.d, and the run-parts(8) tool works the same way.
Please use the same indentation style as the rest of Tor.
strcpy? Please, no. We don't want heap overflows.
In fact, please don't use strcpy in any other program that's supposed to be secure.
Please no bubble sorts, insertion sorts, or other inefficient reimplementations of algorithms that are supposed to be O(n lg n). Just use smartlist_sort() or smartlist_sort_strings().
Rather than hardwiring "/etc/", try using CONFDIR ?
If we can't get FN_FILE from file_status(), why skip the file? Shouldn't we warn?
Nothing in this code frees dirlist or its contents.
Rather than making a fake command line and passing it to load_torrc_from_disk(), why not refactor the code into two functions: one to find the right configuration file, and the other to read and parse it. That way, this code could only send the second one.
Some more fundamental issues
I thought that the semantics of options_init_from_string were that it replaced the current configuration with cf_defaults+cf. But that appears to means that, in this code, the original torrc file is completely replaced with the first file in /etc/tor.d/, then by the second, then by the third, and so on. (Is this tested?)
It seems that for an ordinary Tor user, there's no way to override this stuff. If the system has an /etc/tor.d, I can't override those options even with "-f my_torrc", since the torrc is considered second, and the /etc/tor.d contents are considered last. There is no way to override that directory with another one, either. I don't think that can be the right way to do it, can it?
I thought that the semantics of options_init_from_string were that it replaced the current configuration with cf_defaults+cf. But that appears to means that, in this code, the original torrc file is completely replaced with the first file in /etc/tor.d/, then by the second, then by the third, and so on. (Is this tested?)
I did not mean, if /etc/tor.d/10_something contains "CookieAuthentication 1" and /etc/tor.d/20_somethingelse contains no line containing "CookieAuthentication", that /etc/tor.d/10_something is completely disregarded. The idea was that configuration fragments are joined together in a predictable order. (Bao, please see above.)
It seems that for an ordinary Tor user, there's no way to override this stuff. If the system has an /etc/tor.d, I can't override those options even with "-f my_torrc", since the torrc is considered second, and the /etc/tor.d contents are considered last. There is no way to override that directory with another one, either. I don't think that can be the right way to do it, can it?
This is a valid concern and no one considered that earlier. There is a solution.
At the moment in the Tor manual (man tor), there is...
-f FILE
Specify a new configuration file to contain further Tor configuration options. (Default: $HOME/.torrc, or /etc/tor/torrc if that file is not found)
and...
--defaults-torrc FILE
Specify a file in which to find default values for Tor options. The contents of this file are overridden by those in the regular configuration file, and by those on the command line. (Default: /etc/tor/torrc-defaults.)
I suggest adding..
--fragments FOLDER
Specify a folder to contain further Tor configuration file fragments. (Default: $HOME/.tor.d, or /etc/tor.d/ if that file is not found)
This should allow an ordinary Tor user to override it.
One crazy idea I had was to require that these files start with a two-digit number, since that's how everybody will do it anyway. Then we could define the priority of torrc to be (say) 50, and of the defaults-torrc to be 00, and of the command line to be 100.
One crazy idea I had was to require that these files start with a two-digit number, since that's how everybody will do it anyway. Then we could define the priority of torrc to be (say) 50, and of the defaults-torrc to be 00, and of the command line to be 100.
How about this code snippet? I gotta to run this through you guys before I add it to the ticket. I read all the configuration files and parse them at once. The default and "-f" files got first priority. /etc/tor.d got last priority.
This needs more work than I can give it, but I should say some stuff:
It would be a good idea to learn how to do safe string handling in C. strcat is just as bad as strcpy. I do not want heap overflows in tor.
"/etc/tor.d" is still hardwired.
It still uses a fake command line.
It fails badly if smartlist_len(dirlist) is greater than CHAR_MAX. Why would you ever use a char for that?
concatenating files is probably not the right approach.
These are just the basic issues; there are lots of comments and design discussions I made above that are still unfixed. I think this whole thing needs a total rewrite.
Regarding the usefulness of this I would like to add: for creating a Tor centric Debian blend, the tor.d directory would be required. It would allow Whonix (or Tails in case they're interested, can't speak for them) to become a Debian blend.
An alternative method (Debian-only) is to modify the tor initscript to read /etc/tor/*.torrc and add the appropriate -f args. This would likely be easier to write and pass review than C code.
I was mistaken about how -f worked; I thought you could pass multiple, since the man page says "Specify a new configuration file to contain further Tor configuration options.". Actually, it might be better to implement this, than to have tor decide the sort-order for parsing torrc in a directory.
An alternative method (Debian-only) is to modify the tor initscript to read /etc/tor/*.torrc and add the appropriate -f args. This would likely be easier to write and pass review than C code.
You make it sound really difficult. Is it? Would someone capable of C and remotely familiar with the Tor codebase need more than two hours for this small feature?
than to have tor decide the sort-order
This sounds complicated. Just do it the standard way, in lexical order.
The above patch is a refactoring that retains the same current behaviour. However, it makes future completion of this bug much easier. (I am already working on top of it.)
In order to implement multiple -f options, would be a 2-line diff on top of this patch. In order to implement a -d option would take some more effort. In both cases, some additional work is needed to make get_torrc_fname work properly, since that assumes we only ever read from one single torrc file.
edit: it looks like git-format-patch messed up the commit message formatting. :( hopefully it's still readable.
Nick suggested this task as something useful to do at the Reykjavik hack day. Testing took me longer than it should have, but this patch changes options_init_from_torrc so that it:
Reads the torrc-defaults file, if any exists
Reads in lexicographic order all config files in the tor.d directory, if it exists. List options are cumulative across the files in this category.
No. In particular, the test cases added don't test the logic that checks for CONFDIR/tor.d. I couldn't think of an automated way to cover this with an unprivileged test process. Any suggestions? (I did test this in a VM with a setuid script)
Maybe have CONFDIR be an argument to the functions that use it, and write a unit test (a la the stuff in test_config.c) that tries it with a cooked value to replace CONFDIR when testing those functions?
Other quick notes:
"make check-spaces" enforces some of our coding style rules
Maybe have CONFDIR be an argument to the functions that use it, and write a unit test (a la the stuff in test_config.c) that tries it with a cooked value to replace CONFDIR when testing those functions?
OK, just added a new patch that has full branch coverage of the changed code.
"make check-spaces" enforces some of our coding style rules
And makes this happy, too.
Was there going to be a ~/.tor.d/ as well?
Is there a compelling reason to have this? I was thinking:
A local install will change CONFDIR,
if a user knows to make a ~/.tor.d/ s/he could also just pass -d ~/.tor.d
But if there's a good reason, it's not hard to add.
(I pointed Sebastian here because he's been working on a patch to make approved-routers more reasonable, and maybe turning it into more torrc options, which one can put in a separate file using the feature described here, would be a nice way forward.)