mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-23 14:40:51 +01:00
r11606@catbus: nickm | 2007-01-30 16:52:23 -0500
Write the entry guards section of path-spec; note a possible bug in cirbuitbuild.c; add a const; defer work on torrc.complete to be part of a bigger config documentation reorg. svn:r9465
This commit is contained in:
parent
263a72d7f9
commit
1894e7ea01
3 changed files with 73 additions and 247 deletions
4
doc/TODO
4
doc/TODO
|
@ -69,7 +69,7 @@ R - actually cause the directory.c functions to know about or_port
|
|||
N - DNS improvements
|
||||
. Asynchronous DNS
|
||||
- Make evdns use windows strerror equivalents.
|
||||
- Make sure patches get into libevent.
|
||||
. Make sure patches get into libevent.
|
||||
- Verify that it works well on windows
|
||||
- Debug and re-enable server-side reverse DNS caching
|
||||
|
||||
|
@ -105,7 +105,6 @@ NR. Write path-spec.txt
|
|||
- More prominently, we should have a recommended apps list.
|
||||
- recommend gaim.
|
||||
- unrecommend IE because of ftp:// bug.
|
||||
N - torrc.complete.in needs attention?
|
||||
N - we should add a preamble to tor-design saying it's out of date.
|
||||
N - Document transport and natdport
|
||||
|
||||
|
@ -409,6 +408,7 @@ R - add d64 and fp64 along-side d and fp so people can paste status
|
|||
- Look into generating torrc.{complete|sample}.in, tor.1.in,
|
||||
the HTML manual, and the online config documentation from a single
|
||||
source.
|
||||
- torrc.complete.in needs attention?
|
||||
|
||||
Future version:
|
||||
- Configuration format really wants sections.
|
||||
|
|
|
@ -135,10 +135,11 @@ of their choices.
|
|||
If we fail to build a circuit N times in a X second period (see Section
|
||||
2.3 for how this works), we stop building circuits until the X seconds
|
||||
have elapsed.
|
||||
XXX
|
||||
XXXX
|
||||
|
||||
2.1.6. When to tear down circuits
|
||||
|
||||
XXXX
|
||||
|
||||
2.2. Path selection and constraints
|
||||
|
||||
|
@ -267,37 +268,61 @@ of their choices.
|
|||
|
||||
5. Guard nodes
|
||||
|
||||
XXX writeme
|
||||
We use Guard nodes (also called "helper nodes" in the literature) to
|
||||
prevent certain profiling attacks. Here's the risk: if we choose entry and
|
||||
exit nodes at random, and an attacker controls C out of N servers, then the
|
||||
attacker will control the entry and exit node of any given circuit with
|
||||
probability (C/N)^2. But as we make many different circuits over time,
|
||||
then the probability that the attacker will see a sample of about (C/N)^2
|
||||
of our traffic goes to 1. Since statistical sampling works, the attacker
|
||||
can be sure of learning a profile of our behavior.
|
||||
|
||||
If, on the other hand, we picked an entry node and held it fixed, we would
|
||||
have probability C/N of choosing a bad entry and being profiled, and
|
||||
probability (N-C)/N of choosing a good entry and not being profiled.
|
||||
|
||||
When guard nodes are enabled, Tor maintains an ordered list of entry nodes
|
||||
as our chosen guards, and store this list persistently to disk. If a Guard
|
||||
node becomes unusable, rather than replacing it, Tor adds new guards to the
|
||||
end of the list. When it comes time to choose an entry, Tor chooses at
|
||||
random from among the first NumEntryGuards (default 3) usable guards on the
|
||||
list. If there are not at least 2 usable guards on the list, Tor adds
|
||||
routers until there are, or until there are no more usable routers to add.
|
||||
|
||||
A guard is unusable if any of the following hold:
|
||||
- it is not marked as a Guard by the networkstatuses,
|
||||
- it is not marked Valid (and the user hasn't set AllowInvalid entry)
|
||||
- it is not marked Running
|
||||
- Tor couldn't reach it the last time it tried to connect
|
||||
|
||||
A guard is unusable for a particular circuit if any of the rules for path
|
||||
selection in 2.2 are not met. In particular, if the circuit is "fast"
|
||||
and the guard is not Fast, or if the circuit is "stable" and the guard is
|
||||
not Stable, Tor can't use the guard for that circuit.
|
||||
|
||||
If the guard is excluded because of its status in the networkstatuses for
|
||||
over 30 days, Tor removes it from the list entirely, preserving order.
|
||||
|
||||
If Tor fails to connect to an otherwise usable guard, it retries
|
||||
periodically: every hour for six hours, every for hours for 3 days, every
|
||||
18 hours for a week, and every 36 hours thereafter. Additionally, Tor
|
||||
retries unreachable guards the first time it adds a new guard to the list,
|
||||
since it is possible that the old guards were only marked as unreachable
|
||||
because the network was unreachable or down.
|
||||
|
||||
Tor does not add a guard persistently to the list until the first time we
|
||||
have connected to it successfully.
|
||||
|
||||
6. Testing circuits
|
||||
|
||||
XXXX
|
||||
|
||||
|
||||
|
||||
(From some emails by arma)
|
||||
|
||||
Right now the code exists to pick helper nodes, store our choices to
|
||||
disk, and use them for our entry nodes. But there are three topics
|
||||
to tackle before I'm comfortable turning them on by default. First,
|
||||
how to handle churn: since Tor nodes are not always up, and sometimes
|
||||
disappear forever, we need a plan for replacing missing helpers in a
|
||||
safe way. Second, we need a way to distinguish "the network is down"
|
||||
from "all my helpers are down", also in a safe way. Lastly, we need to
|
||||
examine the situation where a client picks three crummy helper nodes
|
||||
and is forever doomed to a lousy Tor experience. Here's my plan:
|
||||
X. Old notes
|
||||
|
||||
How to handle churn.
|
||||
- Keep track of whether you have ever actually established a
|
||||
connection to each helper. Any helper node in your list that you've
|
||||
never used is ok to drop immediately. Also, we don't save that
|
||||
one to disk.
|
||||
- If all our helpers are down, we need more helper nodes: add a new
|
||||
one to the *end*of our list. Only remove dead ones when they have
|
||||
been gone for a very long time (months).
|
||||
- Pick from the first n (by default 3) helper nodes in your list
|
||||
that are up (according to the network-statuses) and reachable
|
||||
(according to your local firewall config).
|
||||
- This means that order matters when writing/reading them to disk.
|
||||
X.1. Do we actually do this?
|
||||
|
||||
How to deal with network down.
|
||||
- While all helpers are down/unreachable and there are no established
|
||||
|
@ -317,109 +342,10 @@ How to deal with network down.
|
|||
testing circuit, can we get away with converting it to a normal
|
||||
circuit and beginning to use it immediately?)
|
||||
|
||||
How to pick non-sucky helpers.
|
||||
- When we're picking a new helper nodes, don't use ones which aren't
|
||||
reachable according to our local ReachableAddresses configuration.
|
||||
(There's an attack here: if I pick my helper nodes in a very
|
||||
restrictive environment, say "ReachableAddresses 18.0.0.0/255.0.0.0:*",
|
||||
then somebody watching me use the network from another location will
|
||||
guess where I first joined the network. But let's ignore it for now.)
|
||||
- Right now we choose new helpers just like we'd choose any entry
|
||||
node: they must be "stable" (claim >1day uptime) and "fast" (advertise
|
||||
>10kB capacity). In 0.1.1.11-alpha, clients let dirservers define
|
||||
"stable" and "fast" however they like, and they just believe them.
|
||||
So the next step is to make them a function of the current network:
|
||||
e.g. line up all the 'up' nodes in order and declare the top
|
||||
three-quarter to be stable, fast, etc, as long as they meet some
|
||||
minimum too.
|
||||
- If that's not sufficient (it won't be), dirservers should introduce
|
||||
a new status flag: in additional to "stable" and "fast", we should
|
||||
also describe certain nodes as "entry", meaning they are suitable
|
||||
to be chosen as a helper. The first difference would be that we'd
|
||||
demand the top half rather than the top three-quarters. Another
|
||||
requirement would be to look at "mean time between returning" to
|
||||
ensure that these nodes spend most of their time available. (Up for
|
||||
two days straight, once a month, is not good enough.)
|
||||
- Lastly, we need a function, given our current set of helpers and a
|
||||
directory of the rest of the network, that decides when our helper
|
||||
set has become "too crummy" and we need to add more. For example,
|
||||
this could be based on currently advertised capacity of each of
|
||||
our helpers, and it would also be based on the user's preferences
|
||||
of speed vs. security.
|
||||
[Do we actually do any of the above? If so, let's spec it. If not, let's
|
||||
remove it. -NM]
|
||||
|
||||
***
|
||||
|
||||
Lasse wrote:
|
||||
> I am a bit concerned with performance if we are to have e.g. two out of
|
||||
> three helper nodes down or unreachable. How often should Tor check if
|
||||
> they are back up and running?
|
||||
|
||||
Right now Tor believes a threshold of directory servers when deciding
|
||||
whether each server is up. When Tor observes a server to be down
|
||||
(connection failed or building the first hop of the circuit failed),
|
||||
it marks it as down and doesn't try it again, until it gets a new
|
||||
network-status from somebody, at which point it takes a new concensus
|
||||
and marks the appropriate servers as up.
|
||||
|
||||
According to sec 5.1 of dir-spec.txt, the client will try to fetch a new
|
||||
network-status at least every 30 minutes, and more often in certain cases.
|
||||
|
||||
With the proposed scheme, we'll also mark all our helpers as up shortly
|
||||
after the last one is marked down.
|
||||
|
||||
> When should there be
|
||||
> added an extra node to the helper node list? This is kind of an
|
||||
> important threshold?
|
||||
|
||||
I agree, this is an important question. I don't have a good answer yet. Is
|
||||
it terrible, anonymity-wise, to add a new helper every time only one of
|
||||
your helpers is up? Notice that I say add rather than replace -- so you'd
|
||||
only use this fourth helper when one of your main three helpers is down,
|
||||
and if three of your four are down, you'd add a fifth, but only use it
|
||||
when two of the first four are down, etc.
|
||||
|
||||
In fact, this may be smarter than just picking a random node for your
|
||||
testing circuit, because if your network goes up and down a lot, then
|
||||
eventually you have a chance of using any entry node in the network for
|
||||
your testing circuit.
|
||||
|
||||
We have a design choice here. Do we only try to use helpers for the
|
||||
connections that will have streams on them (revealing our communication
|
||||
partners), or do we also want to restrict the overall set of nodes that
|
||||
we'll connect to, to discourage people from enumerating all Tor clients?
|
||||
|
||||
I'm increasingly of the belief that we want to hide our presence too,
|
||||
based on the fact that Steven and George and others keep coming up with
|
||||
attacks that start with "Assuming we know the set of users".
|
||||
|
||||
If so, then here's a revised "How to deal with network down" section:
|
||||
|
||||
1) When a helper is marked down or the helper list shrinks, and as
|
||||
a result the total number of helpers that are either (up and
|
||||
reachable) or (reachable but never connected to) is <= 1, then pick
|
||||
a new helper and add it to the end of the list.
|
||||
[We count nodes that have never been connected to, since otherwise
|
||||
we might keep on adding new nodes before trying any of them. By
|
||||
"reachable" I mean "is allowed by ReachableAddresses".]
|
||||
2) When you fail to connect to a helper that has never been connected
|
||||
to, you remove him from the list right then (and the above rule
|
||||
might kick in).
|
||||
3) When you succeed at connecting to a helper that you've never
|
||||
connected to before, mark all reachable helpers earlier in the list
|
||||
as up, and close that circuit.
|
||||
[We close the circuit, since if the other helpers are now up, we
|
||||
prefer to use them for circuits that will reveal communication
|
||||
partners.]
|
||||
|
||||
This certainly seems simpler. Are there holes that I'm missing?
|
||||
|
||||
> If running from a laptop you will meet different firewall settings, so
|
||||
> how should Helper Nodes settings keep up with moving from an open
|
||||
> ReachableAddresses to a FascistFirewall setting after the helper nodes
|
||||
> have been selected?
|
||||
|
||||
I added the word "reachable" to three places in the above list, and I
|
||||
believe that totally solves this question.
|
||||
X.2. A thing we could do to deal with reachability.
|
||||
|
||||
And as a bonus, it leads to an answer to Nick's attack ("If I pick
|
||||
my helper nodes all on 18.0.0.0:*, then I move, you'll know where I
|
||||
|
@ -429,123 +355,18 @@ more that are reachable for you, and if you move somewhere, it's more
|
|||
likely (though not certain) that some of the originals will become useful.
|
||||
Is that smart or just complex?
|
||||
|
||||
> What happens if(when?) performance of the third node is bad?
|
||||
X.3. Some stuff that worries me about entry guards. 2006 Jun, Nickm.
|
||||
|
||||
My above solution solves this a little bit, in that we always try to
|
||||
have two nodes available. But what if they are both up but bad? I'm not
|
||||
sure. As my previous mail said, we need some function, given our list
|
||||
of helpers and the network directory, that will tell us when we're in a
|
||||
bad situation. I can imagine some simple versions of this function --
|
||||
for example, when both our working helpers are in the bottom half of
|
||||
the nodes, ranked by capacity.
|
||||
It is unlikely for two users to have the same set of entry guards.
|
||||
Observing a user is sufficient to learn its entry guards. So, as we move
|
||||
around, entry guards make us linkable. If we want to change guards when
|
||||
our location (IP? subnet?) changes, we have two bad options. We could
|
||||
- Drop the old guards. But if we go back to our old location,
|
||||
we'll not use our old guards. For a laptop that sometimes gets used
|
||||
from work and sometimes from home, this is pretty fatal.
|
||||
- Remember the old guards as associated with the old location, and use
|
||||
them again if we ever go back to the old location. This would be
|
||||
nasty, since it would force us to record where we've been.
|
||||
|
||||
But the hard part: what's the remedy when we decide there's something
|
||||
to fix? Do we add a third, and now we have two crummy ones and a new
|
||||
one? Or do we drop one or both of the bad ones?
|
||||
|
||||
Perhaps we believe the latest claim from the network-status concensus,
|
||||
and we count a helper the dirservers believe is crummy as "not worth
|
||||
trying" (equivalent to "not reachable under our current ReachableAddresses
|
||||
config") -- and then the above algorithm would end up adding good ones,
|
||||
but we'd go back to the originals if they resume being acceptable? That's
|
||||
an appealing design. I wonder if it will cause the typical Tor user to
|
||||
have a helper node list that comprises most of the network, though. I'm
|
||||
ok with this.
|
||||
|
||||
> Another point you might want to keep in mind, is the possibility to
|
||||
> reuse the code in order to add a second layer helper node (meaning node
|
||||
> number two) to "protect" the first layer (node number one) helper nodes.
|
||||
> These nodes should be tied to each of the first layer nodes. E.g. there
|
||||
> is one helper node list, as described in your mail, for each of the
|
||||
> first layer nodes, following their create/destroy.
|
||||
|
||||
True. Does that require us to add a fourth hop to our path length,
|
||||
since the first hop is from a limited set, the second hop is from a
|
||||
limited set, and the third hop might also be constrained because, say,
|
||||
we're asking for an unusual exit port?
|
||||
|
||||
> Another of the things might worth adding to the to do list is
|
||||
> localization of server (helper) nodes. Making it possible to pick
|
||||
> countries/regions where you do (not) want your helper nodes located. (As
|
||||
> in "HelperNodesLocated us,!eu" etc.) I know this requires the use of
|
||||
> external data and may not be worth it, but it _could_ be integrated at
|
||||
> the directory servers only -- adding a list of node IP's and e.g. a
|
||||
> country/region code to the directory and thus reduce the overhead. (?)
|
||||
> Maybe extending the Family-term?
|
||||
|
||||
I think we are heading towards doing path selection based on geography,
|
||||
but I don't have a good sense yet of how that will actually turn out --
|
||||
that is, with what mechanism Tor clients will learn the information they
|
||||
need. But this seems to be something that is orthogonal to the rest of
|
||||
this discussion, so I look forward to having somebody else solve it for
|
||||
us, and fitting it in when it's ready. :)
|
||||
|
||||
> And I would like to keep an option to pick the first X helper nodes
|
||||
> myself and then let Tor extend this list if these nodes are down (like
|
||||
> EntryNodes in current code). Even if this opens up for some new types of
|
||||
> "relationship" attacks.
|
||||
|
||||
Good idea. Here's how I'd like to name these:
|
||||
|
||||
The "EntryNodes" config option is a list of seed helper nodes. When we
|
||||
read EntryNodes, any node listed in entrynodes but not in the current
|
||||
helper node list gets *pre*pended to the helper node list.
|
||||
|
||||
The "NumEntryNodes" config option (currently called NumHelperNodes)
|
||||
specifies the number of up, reachable, good-enough helper nodes that
|
||||
will make up the pool of possible choices for first hop, counted from
|
||||
the front of the helper node list until we have enough.
|
||||
|
||||
The "UseEntryNodes" config option (currently called UseHelperNodes)
|
||||
tells us to turn on all this helper node behavior. If you set EntryNodes,
|
||||
then this option is implied.
|
||||
|
||||
The "StrictEntryNodes" config option, provided for backward compatibility
|
||||
and for debugging, means a) we replace the helper node list with the
|
||||
current EntryNodes list, and b) whenever we would do an operation that
|
||||
alters the helper node list, we don't. (Yes, this means that if all the
|
||||
helper nodes are down, we lose until we mark them up again. But this is
|
||||
how it behaves now.)
|
||||
|
||||
> I am sure my next point has been asked before, but what about testing
|
||||
> the current speed of the connections when looking for new helper nodes,
|
||||
> not only testing the connectivity? I know this might contribute to a lot
|
||||
> of overhead in the network, but if this only occur e.g. when using
|
||||
> helper nodes as a Hidden Service it might not have that large an impact,
|
||||
> but could help availability for the services?
|
||||
|
||||
If we're just going to be testing them when we're first picking them,
|
||||
then it seems we can do the same thing by letting the directory servers
|
||||
test them. This has the added benefit that all the (behaving) clients
|
||||
use the same data, so they don't end up partitioned by a node that
|
||||
(for example) performs selectively for his victims.
|
||||
|
||||
Another idea would be to periodically keep track of what speeds you get
|
||||
through your helpers, and make decisions from this. The reason we haven't
|
||||
done this yet is because there are a lot of variables -- perhaps the
|
||||
web site is slow, perhaps some other node in the path is slow, perhaps
|
||||
your local network is slow briefly, perhaps you got unlucky, etc. I
|
||||
believe that over time (assuming the user has roughly the same browsing
|
||||
habits) all of these would average out and you'd get a usable answer,
|
||||
but I don't have a good sense of how long it would take to converge,
|
||||
so I don't know whether this would be worthwhile.
|
||||
|
||||
> BTW. I feel confortable with all the terms helper/entry/contact nodes,
|
||||
> but I think you (the developers) should just pick one and stay with it
|
||||
> to avoid confusion.
|
||||
|
||||
I think I'm going to try to co-opt the term 'Entry' node for this
|
||||
purpose. We're going to have to keep referring to helper nodes for the
|
||||
research community for a while though, so they realize that Tor does
|
||||
more than just let users ask for certain entry nodes.
|
||||
|
||||
|
||||
|
||||
============================================================
|
||||
Some stuff that worries me about entry guards. 2006 Jun, Nickm.
|
||||
|
||||
1. It is unlikely for two users to have the same set of entry guards.
|
||||
|
||||
2. Observing a user is sufficient to learn its entry guards.
|
||||
|
||||
3. So, as we move around, we leak our
|
||||
[Do we do any of this now? If not, this should move into 099-misc or
|
||||
098-todo. -NM]
|
||||
|
|
|
@ -1918,7 +1918,7 @@ num_live_entry_guards(void)
|
|||
/** Return 1 if <b>digest</b> matches the identity of any node
|
||||
* in the entry_guards list. Else return 0. */
|
||||
static INLINE int
|
||||
is_an_entry_guard(char *digest)
|
||||
is_an_entry_guard(const char *digest)
|
||||
{
|
||||
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
|
||||
if (!memcmp(digest, entry->identity, DIGEST_LEN))
|
||||
|
@ -2219,6 +2219,11 @@ entry_guard_register_connect_status(const char *digest, int succeeded,
|
|||
r = entry_is_live(e, 0, 1, 1);
|
||||
if (r && !r->is_running) {
|
||||
refuse_conn = 1;
|
||||
/* XXXX012 I think this might be broken; when picking entry nodes,
|
||||
* we only look at unreachable_since and is_time_to_retry, and we
|
||||
* pay no attention to is_running. If this is indeed the case, we
|
||||
* can fix the bug by adding a retry_as_entry flag to
|
||||
* routerinfo_t. -NM */
|
||||
r->is_running = 1;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue