On 08/11/2014 10:28 AM, Guus Sliepen wrote:
To my dismay, I realized that my original proposal for transporting node
identifiers in UDP packets using a simple cleartext header is not viable
because it would introduce a nasty security vulnerability allowing an
external attacker to trick any node into sending packets to *any* IP address
(including addresses outside the graph). Details can be found at the end of
the "unauthenticated relay header" section in the doc.
This is true. Actually, a MITM than can change the source IP address
could already do tricks like that, but the damage he could do would be
limited. With the unauthenticated forwarding header, a MITM could cause
many packets to be sent to an IP address of its choice. The way to limit
the attack would be for tinc to restart PMTU discovery immediately when
the source address changed, and not allow any packets to be forwarded
that are larger than the discovered minimum MTU. This might actually
make sense even in the case of normal direct packets, since if the
source IP address of a node really changes, it might also change the
PMTU, and having to wait for the PingTimeout before we detect this is
not so nice.
That's a very good idea! It would indeed make the attack impossible
because B would try to negotiate an MTU with Y before relaying packets
to it, and of course that would fail since Y is not A and thus cannot
respond to these packets. I also agree that it makes sense to do this in
general, not just in the context of relaying. We might be able to do
without the huge overhead of SPTPS/SPTPS after all.
Therefore I believe Guus' SPTPS-in-SPTPS idea is the only viable one when it
comes to the UDP packet format for relaying.
Regarding the node identifiers, the document lists all ideas that were
brought up.
After carefully weighing the tradeoffs, and realizing that I was probably a
little too concerned about overhead (10 bytes is only 0.6% of a MTU-sized
packet after all...), I would vote for the following:
Node identifiers: hash-based identifier, 48-bit hash, no conflict
resolution.
One way to do conflict resolution in as stateless way as possible is to
split the hash in an 8 bit salt and a 40 bit hash of the name and the
salt. The salt is normally 0. Have the sender check (this only has to
be done when node_add() is called) whether the whole 48-bit identifier
is unique, if not increment the salt and recalculate the 40 bit hash
until it does not conflict anymore with any other node's identifier.
(Well, it should be done in such a way that it's deterministic and all
nodes converge to the same identifiers.)
If there are no conflicts, then this gives you a stable mapping between
node names and identifiers, albeit with a slightly smaller hash space.
Once you do get conflicts, almost all names still keep the same mapping
to an identifier, and only the conflicting node names will see a
temporary disruption until all nodes get their acts straight, but at
least it recovers from hash conflicts.
Maybe I'm paranoid.
I guess that would be an hybrid of the "hash-based" proposal and the
"deterministic node index" proposal where the node index is only between
nodes having the same hash, and the index would be used as the salt
(which doesn't really need to be a salt, by the way - it could simply be
some number appended to the node hash).
I have the same reservations about this than for conflict resolution:
the problem is that the conflict resolution behavior would get triggered
very rarely, which means it would not get much testing in the field.
That said, I do agree that it is a much simpler solution compared to my
stateful conflict resolution proposal so it might not be that big of a
problem. I guess this makes sense if it allows us to make node
identifiers significantly smaller (with 48-bit it just doesn't matter,
the chances of collision are simply too small for the added complexity
to be worth it). But still, going from 48-bit node identifiers to as low
as 24-bit would only reduce overhead by 0.3 percentage points on a
MTU-sized packet, so meh... Honestly I doubt this is worth the effort.
Wire format: SPTPS in SPTPS with cleartext signed node identifiers;
identifiers would also appear in direct (non-relayed) packets as well to
make unknown-source-address key selection faster at the receiving end.
Yes, that would be very good to have, but as soon as there is an 1.0
node in the network you'd still have to check the source address of
packets to determine if it's from that one.
Indeed, but what tinc would do is, it would try to blindly decode a
source identifier first and see if it refers to an existing node; if it
does, the packet is assumed to come from an 1.1 node and the source is
recognized instantly, if it doesn't, then it would fall back to the
usual 1.0 mechanism.
(Of course, that means that when a 1.0 node sends a packet to a 1.1
node, there is a very small chance that it could get "unlucky" and
accidentally "land" on a valid source node identifier value. I believe
this is fine since it would only result in extremely small packet loss
that would be impossible to notice)
--
Etienne Dechamps
_______________________________________________
tinc mailing list
[email protected]
http://www.tinc-vpn.org/cgi-bin/mailman/listinfo/tinc