Adding even more stuff from the CABAL branch.
This commit is contained in:
parent
191dcd5add
commit
9f2c50e159
6 changed files with 869 additions and 0 deletions
3
cvsusers
Normal file
3
cvsusers
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
zarq:Ivo Timmermans <itimmermans@bigfoot.com>
|
||||||
|
guus:Guus Sliepen <guus@sliepen.warande.net>
|
||||||
|
wsl:Wessel Dankers <wsl@nl.linux.org>
|
354
doc/CONNECTIVITY
Normal file
354
doc/CONNECTIVITY
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
This document describes how nodes in a VPN find and connect to eachother and
|
||||||
|
maintain a stable network.
|
||||||
|
|
||||||
|
Copyright 2001-2002 Guus Sliepen <guus@sliepen.warande.net>
|
||||||
|
|
||||||
|
Permission is granted to make and distribute verbatim copies of
|
||||||
|
this documentation provided the copyright notice and this
|
||||||
|
permission notice are preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of
|
||||||
|
this documentation under the conditions for verbatim copying,
|
||||||
|
provided that the entire resulting derived work is distributed
|
||||||
|
under the terms of a permission notice identical to this one.
|
||||||
|
|
||||||
|
$Id: CONNECTIVITY,v 1.2 2002/04/12 08:25:01 guus Exp $
|
||||||
|
|
||||||
|
1. Problem
|
||||||
|
==========
|
||||||
|
|
||||||
|
We have a set of nodes (A, B, C, ...) that are part of the same VPN. They need
|
||||||
|
to connect to eachother and form a single graph that satisfies the tree
|
||||||
|
property.
|
||||||
|
|
||||||
|
There is the possibility that loops are formed, the offending connections must
|
||||||
|
be eliminated.
|
||||||
|
|
||||||
|
Suppose we start with two smaller graphs that want to form a single larger
|
||||||
|
graph. Both graphs consist of three nodes:
|
||||||
|
|
||||||
|
A-----B-----C
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
D-----E-----F
|
||||||
|
|
||||||
|
It is very well possible that A wants to connect to D, and F wants to connect
|
||||||
|
to C, both at the same time. The following loop will occur:
|
||||||
|
|
||||||
|
A-----B-----C
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
v |
|
||||||
|
D-----E-----F
|
||||||
|
|
||||||
|
The situation described here is totally symmetric, there is no preference to
|
||||||
|
one connection over the other. The problem of resolving the loop, maintaining
|
||||||
|
consistency and stability is therefore not a trivial one.
|
||||||
|
|
||||||
|
What happens when A---D and C---F are connected to eachother? They exchange
|
||||||
|
lists of known hosts. A knows of B and C, and D knows of E and F. The protocol
|
||||||
|
defines ADD_HOST messages, from now on we will say that "node X sends and
|
||||||
|
ADD_HOST(Y) to Z".
|
||||||
|
|
||||||
|
There are two possible scenarios: either both A---D and C---F finish
|
||||||
|
authentication at the same time, or A---D finishes first, so that ADD_HOST
|
||||||
|
messages will reach C and F before they finish authentication.
|
||||||
|
|
||||||
|
1.1 A---D finishes first
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
After A---D authentication finishes the following actions are taken:
|
||||||
|
|
||||||
|
1 A sends ADD_HOST(B) to D
|
||||||
|
A sends ADD_HOST(C) to D
|
||||||
|
D sends ADD_HOST(E) to A
|
||||||
|
D sends ADD_HOST(F) to A
|
||||||
|
|
||||||
|
2 A sends ADD_HOST(D) to B
|
||||||
|
A receives ADD_HOST(E) from D:
|
||||||
|
A sends ADD_HOST(E) to B
|
||||||
|
A receives ADD_HOST(F) from D:
|
||||||
|
A sends ADD_HOST(F) to B
|
||||||
|
D sends ADD_HOST(A) to E
|
||||||
|
D receives ADD_HOST(B) from A:
|
||||||
|
D sends ADD_HOST(B) to E
|
||||||
|
D receives ADD_HOST(C) from A:
|
||||||
|
D sends ADD_HOST(C) to E
|
||||||
|
|
||||||
|
3 B receives ADD_HOST(D) from A,
|
||||||
|
B sends ADD_HOST(D) to C
|
||||||
|
B receives ADD_HOST(E) from A:
|
||||||
|
B sends ADD_HOST(E) to C
|
||||||
|
B receives ADD_HOST(F) from A:
|
||||||
|
B sends ADD_HOST(F) to C
|
||||||
|
E receives ADD_HOST(A) from D:
|
||||||
|
E sends ADD_HOST(A) to F
|
||||||
|
E receives ADD_HOST(B) from D:
|
||||||
|
E sends ADD_HOST(B) to F
|
||||||
|
E receives ADD_HOST(C) from D:
|
||||||
|
E sends ADD_HOST(C) to F
|
||||||
|
|
||||||
|
4 C receives ADD_HOST(D) from B.
|
||||||
|
C receives ADD_HOST(E) from B.
|
||||||
|
C receives ADD_HOST(F) from B.
|
||||||
|
F receives ADD_HOST(A) from E.
|
||||||
|
F receives ADD_HOST(B) from E.
|
||||||
|
F receives ADD_HOST(C) from E.
|
||||||
|
|
||||||
|
Then C---F authentication finishes, the following actions are taken:
|
||||||
|
|
||||||
|
1 C notes that F is already known:
|
||||||
|
Connection is closed.
|
||||||
|
F notes that C is already known:
|
||||||
|
Connection is closed.
|
||||||
|
|
||||||
|
1.2 Both A---D and C---F finish at the same time.
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
1 A sends ADD_HOST(B) to D
|
||||||
|
A sends ADD_HOST(C) to D
|
||||||
|
D sends ADD_HOST(E) to A
|
||||||
|
D sends ADD_HOST(F) to A
|
||||||
|
|
||||||
|
C sends ADD_HOST(A) to F
|
||||||
|
C sends ADD_HOST(B) to F
|
||||||
|
F sends ADD_HOST(D) to C
|
||||||
|
F sends ADD_HOST(E) to C
|
||||||
|
|
||||||
|
2 A sends ADD_HOST(D) to B
|
||||||
|
A receives ADD_HOST(E) from D:
|
||||||
|
A sends ADD_HOST(E) to B
|
||||||
|
A receives ADD_HOST(F) from D:
|
||||||
|
A sends ADD_HOST(F) to B
|
||||||
|
D sends ADD_HOST(A) to E
|
||||||
|
D receives ADD_HOST(B) from A:
|
||||||
|
D sends ADD_HOST(B) to E
|
||||||
|
D receives ADD_HOST(C) from A:
|
||||||
|
D sends ADD_HOST(C) to E
|
||||||
|
|
||||||
|
C sends ADD_HOST(F) to B
|
||||||
|
C receives ADD_HOST(D) from F:
|
||||||
|
A sends ADD_HOST(D) to B
|
||||||
|
C receives ADD_HOST(E) from F:
|
||||||
|
A sends ADD_HOST(E) to B
|
||||||
|
F sends ADD_HOSTS(C) to E
|
||||||
|
F receives ADD_HOST(A) from C:
|
||||||
|
D sends ADD_HOST(A) to E
|
||||||
|
F receives ADD_HOST(B) from C:
|
||||||
|
D sends ADD_HOST(B) to E
|
||||||
|
|
||||||
|
3 B receives ADD_HOST(D) from A,
|
||||||
|
B sends ADD_HOST(D) to C
|
||||||
|
B receives ADD_HOST(E) from A:
|
||||||
|
B sends ADD_HOST(E) to C
|
||||||
|
B receives ADD_HOST(F) from A:
|
||||||
|
B sends ADD_HOST(F) to C
|
||||||
|
E receives ADD_HOST(A) from D:
|
||||||
|
E sends ADD_HOST(A) to F
|
||||||
|
E receives ADD_HOST(B) from D:
|
||||||
|
E sends ADD_HOST(B) to F
|
||||||
|
E receives ADD_HOST(C) from D:
|
||||||
|
E sends ADD_HOST(C) to F
|
||||||
|
|
||||||
|
B receives ADD_HOST(F) from C, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
B receives ADD_HOST(D) from C, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
B receives ADD_HOST(E) from C, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(C) from F, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(A) from F, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(B) from F, and notes that is is already known:
|
||||||
|
<insert solution here>
|
||||||
|
|
||||||
|
4 A receives ADD_HOST(D) from B, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
A receives ADD_HOST(E) from B, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
A receives ADD_HOST(F) from B, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
F receives ADD_HOST(A) from E, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
F receives ADD_HOST(B) from E, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
F receives ADD_HOST(B) from E, and notes that it is already known:
|
||||||
|
<insert solution here>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
1.2.1 Augmenting ADD_HOST
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
A solution would be to augment ADD_HOST with an extra parameter, the nexthop of
|
||||||
|
the added host:
|
||||||
|
|
||||||
|
3 B receives ADD_HOST(D,A) from A,
|
||||||
|
B sends ADD_HOST(D,A) to C
|
||||||
|
B receives ADD_HOST(E,D) from A:
|
||||||
|
B sends ADD_HOST(E,D) to C
|
||||||
|
B receives ADD_HOST(F,E) from A:
|
||||||
|
B sends ADD_HOST(F,E) to C
|
||||||
|
E receives ADD_HOST(A,D) from D:
|
||||||
|
E sends ADD_HOST(A,D) to F
|
||||||
|
E receives ADD_HOST(B,A) from D:
|
||||||
|
E sends ADD_HOST(B,A) to F
|
||||||
|
E receives ADD_HOST(C,B) from D:
|
||||||
|
E sends ADD_HOST(C,B) to F
|
||||||
|
|
||||||
|
B receives ADD_HOST(F,C) from C, and notes that F is already known:
|
||||||
|
<insert solution here>
|
||||||
|
B receives ADD_HOST(D,E) from C, and notes that D is already known:
|
||||||
|
<insert solution here>
|
||||||
|
B receives ADD_HOST(E,F) from C, and notes that E is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(C,F) from F, and notes that C is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(A,B) from F, and notes that A is already known:
|
||||||
|
<insert solution here>
|
||||||
|
E receives ADD_HOST(B,C) from F, and notes that B is already known:
|
||||||
|
<insert solution here>
|
||||||
|
|
||||||
|
So, B and E have to make a choice. Which ADD_HOST is going to win? Fortunately,
|
||||||
|
since the ADD_HOST messages are augmented, they have an extra piece of
|
||||||
|
information they can use to decide in a deterministic way which one is going to
|
||||||
|
win. For example, B got ADD_HOST(F,E) and ADD_HOST(F,C). Since "E" > "C", it
|
||||||
|
could let ADD_HOST(F,E) win.
|
||||||
|
|
||||||
|
B receives ADD_HOST(F,C) from C, and notes that F is already known:
|
||||||
|
since "C" < "E", B ignores ADD_HOST(F,E)
|
||||||
|
B sends ADD_HOST(F,C) to A
|
||||||
|
...
|
||||||
|
E receives ADD_HOST(C,F) from F, and notes that C is already known:
|
||||||
|
since "F" > "B", E removes the ADD_HOST(C,B) in favour of the new one
|
||||||
|
E sends ADD_HOST(C,F) to D
|
||||||
|
|
||||||
|
4 A receives ADD_HOST(F,E) from B, and notes that F is already known:
|
||||||
|
since "E" < "D", A ignores ADD_HOST(F,D).
|
||||||
|
...
|
||||||
|
D receives ADD_HOST(C,F) from E, and notes that C is already known:
|
||||||
|
since "F" > "B", D removes the ADD_HOST(C,B),
|
||||||
|
closes the connection with C, in favour of the new one.
|
||||||
|
|
||||||
|
Ok, time to forget this crap.
|
||||||
|
|
||||||
|
1.2.2
|
||||||
|
-----
|
||||||
|
|
||||||
|
The problem with the current ADD/DEL_HOST technique is that each host only
|
||||||
|
knows the general direction in which to send packets for the other hosts. It
|
||||||
|
really doesn't know much about the true topology of the network, only about
|
||||||
|
it's direct neighbours. With so little information each host cannot make a
|
||||||
|
certain decision which it knows for sure all the others will decide too.
|
||||||
|
|
||||||
|
Let's do something totally different. Instead of notifying every host of the
|
||||||
|
addition of a new host, which is represented by a vertex in a graph, lets send
|
||||||
|
out notifications of new connections, which are the edges in a graph. This is
|
||||||
|
rather cheap, since our graphs are (almost) spanning trees, there is
|
||||||
|
approximately one edge for each vertex in the graph, so we don't need to send
|
||||||
|
more messages. Furthermore, an edge is characterized by two vertices, so we
|
||||||
|
only send a fixed amount of extra information. The size/complexity of the
|
||||||
|
problem therefore does not increase much.
|
||||||
|
|
||||||
|
What is the advantage of notifying each vertex of new edges instead of new
|
||||||
|
vertices? Well, all the vertices now know exactly which connections are made
|
||||||
|
between each host. This was not known with the former schemes.
|
||||||
|
|
||||||
|
Ok back to our problem:
|
||||||
|
|
||||||
|
A-----B-----C
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
D-----E-----F
|
||||||
|
|
||||||
|
Edges are undirected, and are characterised by the vertices it connects, sorted
|
||||||
|
alphabetically, so the edges in the two graphs are:
|
||||||
|
|
||||||
|
(A,B), (B,C), (D,E) and (E,F).
|
||||||
|
|
||||||
|
So again we have that A wants to connect to D, and F wants to connect to C,
|
||||||
|
both at the same time. The following loop will occur:
|
||||||
|
|
||||||
|
A-----B-----C
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
v |
|
||||||
|
D-----E-----F
|
||||||
|
|
||||||
|
Instead of sending ADD_HOSTs, lets assume the hosts send ADD_EDGEs. So, after
|
||||||
|
making the connections:
|
||||||
|
|
||||||
|
1 A sends ADD_EDGE(A,D) to B
|
||||||
|
A sends ADD_EDGE(A,B) to D
|
||||||
|
A sends ADD_EDGE(B,C) to D
|
||||||
|
D sends ADD_EDGE(A,D) to E
|
||||||
|
D sends ADD_EDGE(D,E) to A
|
||||||
|
D sends ADD_EDGE(E,F) to A
|
||||||
|
|
||||||
|
C sends ADD_EDGE(C,F) to B
|
||||||
|
C sends ADD_EDGE(A,B) to F
|
||||||
|
C sends ADD_EDGE(B,C) to F
|
||||||
|
F sends ADD_EDGE(C,F) to E
|
||||||
|
F sends ADD_EDGE(D,E) to C
|
||||||
|
F sends ADD_EDGE(E,F) to C
|
||||||
|
|
||||||
|
2 B receives ADD_EDGE(A,D) from A:
|
||||||
|
B sends ADD_EDGE(A,D) to C
|
||||||
|
B receives ADD_EDGE(D,E) from A:
|
||||||
|
B sends ADD_EDGE(D,E) to C
|
||||||
|
B receives ADD_EDGE(E,F) from A:
|
||||||
|
B sends ADD_EDGE(E,F) to C
|
||||||
|
...
|
||||||
|
|
||||||
|
B receives ADD_EDGE(C,F) from C, notes that both C and F are already known,
|
||||||
|
but that the edge (C,F) was not known, so a loop has been created:
|
||||||
|
<resolve loop here>
|
||||||
|
|
||||||
|
Ok, how to resolve the loop? Remeber, we want to do that in such a way that it
|
||||||
|
is consistent with the way all the other hosts resolve the loop. Here is the
|
||||||
|
things B does when it notices that a loop is going to be formed:
|
||||||
|
|
||||||
|
B performs a Breadth First Search from the first element of the list of all
|
||||||
|
known hosts sorted alfabetically, in this case A, and thereby finds a
|
||||||
|
spanning tree. (This might later be changed into a minimum spanning tree
|
||||||
|
alhorithm, but the key point here is that all hosts do this with exactly the
|
||||||
|
same starting parameters.) All known edges that are not in the spanning tree
|
||||||
|
are marked inactive.
|
||||||
|
|
||||||
|
An edge marked inactive does not mean anything, unless this edge is connected
|
||||||
|
to B itself. In that case, B will stop sending messages over that edge. B might
|
||||||
|
consider closing this edge, but this is not really needed. Keeping it means no
|
||||||
|
DEL_EDGE has to be sent for it, and if another edge is removed (which will
|
||||||
|
quite certainly split the graph if it's a spanning tree), this edge might be
|
||||||
|
reactivated, without the need of sending a new ADD_EDGE for it. On the other
|
||||||
|
hand, we mustn't keep to many inactive edges, because we want to keep the
|
||||||
|
number of known edges linear to the number of hosts (otherwise the size of the
|
||||||
|
problem will grow quadratically).
|
||||||
|
|
||||||
|
So, since B didn't deactivate one of it's own edges, it forwards the
|
||||||
|
ADD_EDGE(C,F) to A, which also does a BFS, and so on, until it reaches F. F of
|
||||||
|
course also does a BFS, notes that is is one of it's own edges. It deactivates
|
||||||
|
the edge (C,F), and consequently will not forward the ADD_EDGE(C,F) to C
|
||||||
|
anymore. In the mean time, C got messages from B which will make C do the same.
|
||||||
|
|
||||||
|
Ok, suppose a DEL_EDGE was sent, and it means an inactive edge has to be
|
||||||
|
reactivated. The vertices connected by that edge must exchange their entire
|
||||||
|
knowledge of edges again, because in the mean time other messages could have
|
||||||
|
been sent, which were not properly forwarded. Take this example:
|
||||||
|
|
||||||
|
X C-----D
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
v | |
|
||||||
|
A-----B- - -E
|
||||||
|
|
||||||
|
The edge (B,E) is inactive. X is trying to make a new connection with A. A
|
||||||
|
sends an ADD_EDGE(A,X) to B, which forwards it to C. At that time, the
|
||||||
|
connection between C and D goes down, so C sends a DEL_EDGE(C,D) to B, and D
|
||||||
|
sends a DEL_EDGE(C,D) to E. If we just allow (B,E) to be reactivated again
|
||||||
|
without anything else, then E and D will never have received the ADD_EDGE(A,X).
|
||||||
|
So, B and E have to exchange edges again, and propagate them to the hosts they
|
||||||
|
already know.
|
175
doc/HOWTO
Normal file
175
doc/HOWTO
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
==============
|
||||||
|
The TINC HOWTO
|
||||||
|
==============
|
||||||
|
|
||||||
|
Wessel Dankers
|
||||||
|
wsl@nl.linux.org
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
Tinc is a system to create a virtual ethernet network on top of an existing
|
||||||
|
infrastructure. This infrastructure can be anything from modem lines to
|
||||||
|
gigabit ethernet networks, as long as they talk IP. Once you install and
|
||||||
|
configure tinc, your host will get an extra IP address, just like it would
|
||||||
|
when you stick an extra ethernet card into it. Using this IP address, it can
|
||||||
|
communicate with all hosts in its virtual network using strong encryption.
|
||||||
|
|
||||||
|
If you install Tinc on a router (and pick your numbers correctly) you can
|
||||||
|
have the router forward all packets. This way you can---instead of
|
||||||
|
connecting hosts---connect entire sites together! Now you need only one
|
||||||
|
outgoing network connection for both internet and intranet.
|
||||||
|
|
||||||
|
Architecture
|
||||||
|
------------
|
||||||
|
When a few Tinc daemons are running they will try to seek contact with
|
||||||
|
eachother. A daemon is all the time connected to a few other daemons,
|
||||||
|
but if traffic is required with a daemon it doesn't know yet, it will
|
||||||
|
instantly contact it and exchange keys. These so-called meta-connections
|
||||||
|
are made over TCP, using encryption of course.
|
||||||
|
|
||||||
|
When actual traffic has to be sent, a daemon checks his connection list to
|
||||||
|
see if the addressee is known (and makes contact with it if neccessary).
|
||||||
|
All packets are then sent using UDP to the other host, just like in a real
|
||||||
|
network. If a packet gets lost, the connection layer of Linux will resend
|
||||||
|
the packet, just like it would over a normal network.
|
||||||
|
|
||||||
|
Once in a while the daemons will renegotiate keys so that even if a cracker
|
||||||
|
breaks one, it'll be of limited use.
|
||||||
|
|
||||||
|
Getting Tinc
|
||||||
|
------------
|
||||||
|
Before you fetch the latest tarball, you might want to check if there's a
|
||||||
|
package for your Linux distribution. One of the main authors is a Debian
|
||||||
|
Developer, so you can expect the Debian packages to be very up to date.
|
||||||
|
|
||||||
|
The official website for Tinc can be found at http://tinc.nl.linux.org/.
|
||||||
|
There you can find Debian packages, RPM's and of course... the tarball!
|
||||||
|
Since we run Doohickey Linux Pro 1.0, for which no package exists (or
|
||||||
|
indeed the distribution itself) we shall compile the package ourselves.
|
||||||
|
|
||||||
|
Building
|
||||||
|
--------
|
||||||
|
The Tinc source adheres to so many standards it makes you head spin.
|
||||||
|
Even the debug messages have been localized! Amazing. Tinc also comes
|
||||||
|
with a configuration script. If you like to see what is there to
|
||||||
|
configure run ./configure --help | more. If you don't have time for such
|
||||||
|
nonsense:
|
||||||
|
|
||||||
|
./configure --sysconfdir=/etc
|
||||||
|
|
||||||
|
This will see if your system is nice enough to run tinc on, and will
|
||||||
|
create some Makefiles and other stuff which will together build tinc.
|
||||||
|
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
|
||||||
|
The first will do the actual build, the second copies all files into place.
|
||||||
|
|
||||||
|
The kernel
|
||||||
|
----------
|
||||||
|
Next you will have to configure the kernel to support the tap device.
|
||||||
|
It is important that you run a recent kernel, but anything after 2.2.16
|
||||||
|
will do. You have to enable both the netlink device AND the ethertap
|
||||||
|
device (in that order). Enable them as modules!
|
||||||
|
Compile, install =) You don't even have to reboot.
|
||||||
|
|
||||||
|
Picking your numbers
|
||||||
|
--------------------
|
||||||
|
The first thing we should do is pick network numbers. Tinc has a very
|
||||||
|
peculiar taste for network numbers, which is caused by the way it routes
|
||||||
|
traffic. However, it turns out to be really handy if you want to use
|
||||||
|
your tinc host as a router for a site.
|
||||||
|
|
||||||
|
The numbers have to be in a range that is not yet in use in your existing,
|
||||||
|
real network! In this example we will use numbers from the 192.168.0/16
|
||||||
|
range. This is standard CIDR notation for all IP addresses from 192.168.0.0
|
||||||
|
to 192.168.255.255. The /16 means that the first 16 bits form the network
|
||||||
|
part.
|
||||||
|
|
||||||
|
It is common practice for Tinc networks to use private (RFC 1918) addresses.
|
||||||
|
This is not necessary, but it would be a waste to use official addresses
|
||||||
|
for a private network!
|
||||||
|
|
||||||
|
In the example we will connect three machines: f00f, fdiv and hlt. We will
|
||||||
|
give each an address, but not just that, also a slice of our address space
|
||||||
|
to play with.
|
||||||
|
|
||||||
|
Host Real address Tinc network
|
||||||
|
---------------------------------------------------
|
||||||
|
f00f 126.202.37.20 192.168.1.1/24
|
||||||
|
fdiv 126.202.37.81 192.168.2.1/24
|
||||||
|
hlt 103.22.1.218 192.168.3.1/24
|
||||||
|
|
||||||
|
It is very important that none of the Tinc netmasks overlap! Note how the
|
||||||
|
192.168.0/16 network covers the entire address space of the three hosts.
|
||||||
|
We will refer to the 192.168.0/16 network as the `umbrella' from now on.
|
||||||
|
As you can see we can fit 256 hosts into this umbrella this way, which is
|
||||||
|
also the practical maximum for tinc. Let's name our VPN 'fubar'.
|
||||||
|
|
||||||
|
The configuration file
|
||||||
|
----------------------
|
||||||
|
Let's create a configuration file for f00f. We have to put it in
|
||||||
|
/etc/tinc/fubar because that's how we named our VPN.
|
||||||
|
|
||||||
|
MyOwnVPNIP = 192.168.1.1/24
|
||||||
|
VpnMask = 255.255.0.0
|
||||||
|
ConnectTo = 126.202.37.81
|
||||||
|
ConnectTo = 103.22.1.218
|
||||||
|
TapDevice = /dev/tap0
|
||||||
|
|
||||||
|
The first two lines tell Tinc about the numbers we have chosen above.
|
||||||
|
Using the ConnectTo lines, the daemon will seek contact with the rest of
|
||||||
|
the umbrella. It's possible to configure any number of ConnectTo lines,
|
||||||
|
you can even omit them so that it just sits and waits until someone else
|
||||||
|
contacts it. Until someone does, the poor daemon won't be able to send
|
||||||
|
any data because it doesn't know where everybody is.
|
||||||
|
The TapDevice is where the tinc daemon will interface with the kernel.
|
||||||
|
|
||||||
|
The passphrases
|
||||||
|
---------------
|
||||||
|
We will have to generate keys for ourselves, and get a key from everybody
|
||||||
|
we want to ConnectTo. All of these go into a directory named
|
||||||
|
/etc/tinc/fubar/passphrases. PROTECT THIS DIRECTORY!
|
||||||
|
|
||||||
|
mkdir -m 700 /etc/tinc/fubar/passphrases
|
||||||
|
|
||||||
|
To generate our own key:
|
||||||
|
|
||||||
|
genauth 1024 >/etc/tinc/fubar/passphrases/local
|
||||||
|
|
||||||
|
You should then proceed to give this key to anyone who wants to ConnectTo
|
||||||
|
you. DO THIS IN A SECURE MANNER! Anyone who has this number can do icky
|
||||||
|
things to the umbrella network! Encrypt it using PGP, GPG or another
|
||||||
|
program using asymmetric keys. Read it over the phone (without anyone
|
||||||
|
listening of course). Send it by snailmail. Write the key down and bring
|
||||||
|
it to your partners personally!
|
||||||
|
|
||||||
|
If you get any keys from your partners, store them under their network
|
||||||
|
number. For example, the key we get from fdiv's network administrator
|
||||||
|
will be stored in /etc/tinc/fubar/passphrases/192.168.2.0 (note the 0).
|
||||||
|
|
||||||
|
Running the daemon
|
||||||
|
------------------
|
||||||
|
If you use a package manager to install Tinc, the startup scripts use a file
|
||||||
|
called /etc/tinc/nets.boot to see which umbrella's exist. It has a line
|
||||||
|
per VPN, and lines starting with a # are ignored. Ours will contain:
|
||||||
|
|
||||||
|
# Example VPN from the HOWTO
|
||||||
|
fubar
|
||||||
|
|
||||||
|
In Debian, /etc/init.d/tinc start will start the daemons.
|
||||||
|
|
||||||
|
If you use Doohickey Linux just like we do, you'll have to edit the systems
|
||||||
|
startup scripts by hand. It should contain something along the lines of:
|
||||||
|
|
||||||
|
insmod ethertap -s --name=tap0 unit=0
|
||||||
|
ifconfig tap0 hw ether fe:fd:c0:a8:01:01
|
||||||
|
ifconfig tap0 192.168.1.1 netmask 255.255.0.0 broadcast 192.168.255.255 -arp
|
||||||
|
|
||||||
|
There are two things to note here! First, the MAC address of the ethertap
|
||||||
|
device is very important. It must start with fe:fd, and end in the
|
||||||
|
hexadecimal representation of the VPN IP number.
|
||||||
|
Second, the netmask of the tap device is set to that of the umbrella!
|
||||||
|
|
||||||
|
--
|
||||||
|
$Id: HOWTO,v 1.6 2002/04/12 08:25:01 guus Exp $
|
83
doc/NETWORKING
Normal file
83
doc/NETWORKING
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
This is the network infrastructure documentation for tinc, a Virtual Private
|
||||||
|
Network daemon.
|
||||||
|
|
||||||
|
Copyright 2001-2002 Guus Sliepen <guus@sliepen.warande.net>
|
||||||
|
|
||||||
|
Permission is granted to make and distribute verbatim copies of
|
||||||
|
this documentation provided the copyright notice and this
|
||||||
|
permission notice are preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of
|
||||||
|
this documentation under the conditions for verbatim copying,
|
||||||
|
provided that the entire resulting derived work is distributed
|
||||||
|
under the terms of a permission notice identical to this one.
|
||||||
|
|
||||||
|
$Id: NETWORKING,v 1.2 2002/04/12 08:25:01 guus Exp $
|
||||||
|
|
||||||
|
1. Packet flow
|
||||||
|
==============
|
||||||
|
|
||||||
|
There are two directions for packets. There are packets received from the tap
|
||||||
|
device that have to be sent out to other tinc daemon, and there are packets
|
||||||
|
that are received from other tinc daemons which have to be send to the tap
|
||||||
|
device. The first direction will be called the outgoing direction, while the
|
||||||
|
latter will be called the incoming direction.
|
||||||
|
|
||||||
|
1.1 Outgoing flow
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
handle_tap_input()
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
route_outgoing()
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
send_packet() ----
|
||||||
|
/ \ / \
|
||||||
|
/ \ | queue
|
||||||
|
V V V /
|
||||||
|
send_tcppacket() send_udppacket()--
|
||||||
|
|
||||||
|
Packets are read from the tap device by handle_tap_input(). The packets will be
|
||||||
|
marked as coming from ourself, and are then handled by route_outgoing(). This
|
||||||
|
function will determine the destination tinc daemon this packet has to be sent
|
||||||
|
to, and in the future it may also determine if this packet has to be broadcast
|
||||||
|
or multicast. route_outgoing() will call send_packet() (in case of
|
||||||
|
broad/multicast several times). send_packet() will check the destination
|
||||||
|
connection_t entry to see if it is a valid destination, and whether it has to
|
||||||
|
be sent via TCP or UDP. It will then either call send_tcppacket() or
|
||||||
|
send_udppacket(). Since a different key is used for UDP packets, which might
|
||||||
|
not be available at that time, send_udppacket() might put the packet in a queue
|
||||||
|
and send a REQ_KEY to the destination tinc daemon. If the key has been retrieved,
|
||||||
|
the packet will be fed to send_udppacket() again.
|
||||||
|
|
||||||
|
1.2 Incoming flow
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
handle_vpn_input()
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
tcppacket_h() receive_udppacket()
|
||||||
|
\ /
|
||||||
|
\ /
|
||||||
|
V V
|
||||||
|
receive_packet()
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
route_incoming()
|
||||||
|
|
|
||||||
|
|
|
||||||
|
V
|
||||||
|
accept_packet()
|
||||||
|
|
||||||
|
Packets from other tinc daemons can be received by tcppacket_h(), for TCP
|
||||||
|
packets, and receive_udppacket() via handle_vpn_input() for UDP packets.
|
||||||
|
receive_packet() actually does not have to do much, except logging and calling
|
||||||
|
route_incoming(), but it's there for symmetry with the scheme for the outgoing
|
||||||
|
flow. route_incoming() will change the MAC header of the packet if necessary to
|
||||||
|
let the kernel accept the packet after it has been sent to the tap device by
|
||||||
|
accept_packet().
|
129
doc/PROTOCOL
Normal file
129
doc/PROTOCOL
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
This is the protocol documentation for tinc, a Virtual Private Network daemon.
|
||||||
|
|
||||||
|
Copyright 2000-2002 Guus Sliepen <guus@sliepen.warande.net>,
|
||||||
|
2000-2002 Ivo Timmmermans <itimmermans@bigfoot.com>
|
||||||
|
|
||||||
|
Permission is granted to make and distribute verbatim copies of
|
||||||
|
this documentation provided the copyright notice and this
|
||||||
|
permission notice are preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of
|
||||||
|
this documentation under the conditions for verbatim copying,
|
||||||
|
provided that the entire resulting derived work is distributed
|
||||||
|
under the terms of a permission notice identical to this one.
|
||||||
|
|
||||||
|
$Id: PROTOCOL,v 1.2 2002/04/12 08:25:01 guus Exp $
|
||||||
|
|
||||||
|
|
||||||
|
1. Protocols used in tinc
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
tinc uses several protocols to function correctly. To enter the
|
||||||
|
network of tinc daemons that make up the virtual private network, tinc
|
||||||
|
makes TCP connections to other tinc daemons. It uses the "meta
|
||||||
|
protocol" for these connections. To exchange packets on the virtual
|
||||||
|
network, UDP connections are made and the "packet protocol" is used.
|
||||||
|
Tinc also needs to exchange network packets with the kernel. This is
|
||||||
|
done using the ethertap device or the universal TUN/TAP device that
|
||||||
|
can be found in various UNIX flavours.
|
||||||
|
|
||||||
|
2. Packet protocol
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Normal packets are sent without any state information, so the layout
|
||||||
|
is pretty basic.
|
||||||
|
|
||||||
|
A data packet can only be sent if the encryption key, cipher and digest are
|
||||||
|
known to both parties, and the connection is activated. If the encryption key
|
||||||
|
is not known, a request is sent to the destination using the meta connection to
|
||||||
|
retreive it.
|
||||||
|
|
||||||
|
0 1 2 3 4 5 6 7 ... 97 98 99 100
|
||||||
|
| seqno | data | MAC |
|
||||||
|
\____________________________________/\_______________/
|
||||||
|
| |
|
||||||
|
encrypted using symmetric cipher digest
|
||||||
|
|
||||||
|
The sequence number prevents replay attacks, the message authentication code
|
||||||
|
prevents altered packets from being accepted.
|
||||||
|
|
||||||
|
3. Meta protocol
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The meta protocol is used to tie all tinc daemons together, and
|
||||||
|
exchange information about which tinc daemon serves which virtual
|
||||||
|
subnet.
|
||||||
|
|
||||||
|
The meta protocol consists of requests that can be sent to the other
|
||||||
|
side. Each request has a unique number and several parameters. All
|
||||||
|
requests are represented in the standard ASCII character set. It is
|
||||||
|
possible to use tools such as telnet or netcat to connect to a tinc
|
||||||
|
daemon and to read and write requests by hand, provided that one
|
||||||
|
understands the numeric codes sent.
|
||||||
|
|
||||||
|
The authentication scheme is described in the SECURITY2 file. After a
|
||||||
|
succesful authentication, the server and the client will exchange all the
|
||||||
|
information about other tinc daemons and subnets they know of, so that both
|
||||||
|
sides (and all the other tinc daemons behind them) have their information
|
||||||
|
synchronised.
|
||||||
|
|
||||||
|
daemon message
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
origin ADD_EDGE node1 12.23.34.45 655 node2 21.32.43.54 655 222 0
|
||||||
|
| | | \___________________/ | +-> options
|
||||||
|
| | | | +----> weight
|
||||||
|
| | | +----------------> see below
|
||||||
|
| | +--> UDP port
|
||||||
|
| +----------> real address
|
||||||
|
+------------------> name of node on one side of the edge
|
||||||
|
|
||||||
|
origin ADD_SUBNET node 192.168.1.0/24
|
||||||
|
| | +--> prefixlength
|
||||||
|
| +--------> IPv4 network address
|
||||||
|
+------------------> owner of this subnet
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
In case a connection between two daemons is closed or broken, DEL_EDGE messages
|
||||||
|
are sent to inform the other daemons of that fact. Each daemon will calculate a
|
||||||
|
new route to the the daemons, or mark them unreachable if there isn't any.
|
||||||
|
|
||||||
|
The keys used to encrypt VPN packets are not sent out directly. This is
|
||||||
|
because it would generate a lot of traffic on VPNs with many daemons, and
|
||||||
|
chances are that not every tinc daemon will ever send a packet to every
|
||||||
|
other daemon. Instead, if a daemon needs a key it sends a request for it
|
||||||
|
via the meta connection of the nearest hop in the direction of the
|
||||||
|
destination. If any hop on the way has already learned the key, it will
|
||||||
|
act as a proxy and forward its copy back to the requestor.
|
||||||
|
|
||||||
|
daemon message
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
daemon REQ_KEY origin destination
|
||||||
|
| +--> name of the tinc daemon it wants the key from
|
||||||
|
+----------> name of the daemon that wants the key
|
||||||
|
|
||||||
|
daemon ANS_KEY origin destination 4ae0b0a82d6e0078 91 64 4
|
||||||
|
| | \______________/ | | +--> MAC length
|
||||||
|
| | | | +-----> digest algorithm
|
||||||
|
| | | +--------> cipher algorithm
|
||||||
|
| | +--> 128 bits key
|
||||||
|
| +--> name of the daemon that wants the key
|
||||||
|
+----------> name of the daemon that uses this key
|
||||||
|
|
||||||
|
daemon KEY_CHANGED origin
|
||||||
|
+--> daemon that has changed it's packet key
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
There is also a mechanism to check if hosts are still alive. Since network
|
||||||
|
failures or a crash can cause a daemon to be killed without properly
|
||||||
|
shutting down the TCP connection, this is necessary to keep an up to date
|
||||||
|
connection list. Pings are sent at regular intervals, except when there
|
||||||
|
is also some other traffic.
|
||||||
|
|
||||||
|
daemon message
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
origin PING
|
||||||
|
dest. PONG
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This basically covers everything that is sent over the meta connection by
|
||||||
|
tinc.
|
125
doc/SECURITY2
Normal file
125
doc/SECURITY2
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
This is the security documentation for tinc, a Virtual Private Network daemon.
|
||||||
|
|
||||||
|
Copyright 2001-2002 Guus Sliepen <guus@sliepen.warande.net>,
|
||||||
|
2001-2002 Wessel Dankers <wsl@nl.linux.org>
|
||||||
|
|
||||||
|
Permission is granted to make and distribute verbatim copies of
|
||||||
|
this documentation provided the copyright notice and this
|
||||||
|
permission notice are preserved on all copies.
|
||||||
|
|
||||||
|
Permission is granted to copy and distribute modified versions of
|
||||||
|
this documentation under the conditions for verbatim copying,
|
||||||
|
provided that the entire resulting derived work is distributed
|
||||||
|
under the terms of a permission notice identical to this one.
|
||||||
|
|
||||||
|
$Id: SECURITY2,v 1.2 2002/04/12 08:25:01 guus Exp $
|
||||||
|
|
||||||
|
Proposed new authentication scheme
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
A new scheme for authentication in tinc has been devised, which offers some
|
||||||
|
improvements over the protocol used in 1.0pre2 and 1.0pre3. Explanation is
|
||||||
|
below.
|
||||||
|
|
||||||
|
daemon message
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
client <attempts connection>
|
||||||
|
|
||||||
|
server <accepts connection>
|
||||||
|
|
||||||
|
client ID client 12
|
||||||
|
| +---> version
|
||||||
|
+-------> name of tinc daemon
|
||||||
|
|
||||||
|
server ID server 12
|
||||||
|
| +---> version
|
||||||
|
+-------> name of tinc daemon
|
||||||
|
|
||||||
|
client META_KEY 5f0823a93e35b69e...7086ec7866ce582b
|
||||||
|
\_________________________________/
|
||||||
|
+-> RSAKEYLEN bits totally random string S1,
|
||||||
|
encrypted with server's public RSA key
|
||||||
|
|
||||||
|
server META_KEY 6ab9c1640388f8f0...45d1a07f8a672630
|
||||||
|
\_________________________________/
|
||||||
|
+-> RSAKEYLEN bits totally random string S2,
|
||||||
|
encrypted with client's public RSA key
|
||||||
|
|
||||||
|
From now on:
|
||||||
|
- the client will symmetrically encrypt outgoing traffic using S1
|
||||||
|
- the server will symmetrically encrypt outgoing traffic using S2
|
||||||
|
|
||||||
|
client CHALLENGE da02add1817c1920989ba6ae2a49cecbda0
|
||||||
|
\_________________________________/
|
||||||
|
+-> CHALLEN bits totally random string H1
|
||||||
|
|
||||||
|
server CHALLENGE 57fb4b2ccd70d6bb35a64c142f47e61d57f
|
||||||
|
\_________________________________/
|
||||||
|
+-> CHALLEN bits totally random string H2
|
||||||
|
|
||||||
|
client CHAL_REPLY 816a86
|
||||||
|
+-> 160 bits SHA1 of H2
|
||||||
|
|
||||||
|
server CHAL_REPLY 928ffe
|
||||||
|
+-> 160 bits SHA1 of H1
|
||||||
|
|
||||||
|
After the correct challenge replies are recieved, both ends have proved
|
||||||
|
their identity. Further information is exchanged.
|
||||||
|
|
||||||
|
client ACK 655 12.23.34.45 123 0
|
||||||
|
| | | +-> options
|
||||||
|
| | +----> estimated weight
|
||||||
|
| +------------> IP address of server as seen by client
|
||||||
|
+--------------------> UDP port of client
|
||||||
|
|
||||||
|
server ACK 655 21.32.43.54 321 0
|
||||||
|
| | | +-> options
|
||||||
|
| | +----> estimated weight
|
||||||
|
| +------------> IP address of client as seen by server
|
||||||
|
+--------------------> UDP port of server
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This new scheme has several improvements, both in efficiency and security.
|
||||||
|
|
||||||
|
First of all, the server sends exactly the same kind of messages over the wire
|
||||||
|
as the client. The previous versions of tinc first authenticated the client,
|
||||||
|
and then the server. This scheme even allows both sides to send their messages
|
||||||
|
simultaneously, there is no need to wait for the other to send something first.
|
||||||
|
This means that any calculations that need to be done upon sending or receiving
|
||||||
|
a message can also be done in parallel. This is especially important when doing
|
||||||
|
RSA encryption/decryption. Given that these calculations are the main part of
|
||||||
|
the CPU time spent for the authentication, speed is improved by a factor 2.
|
||||||
|
|
||||||
|
Second, only one RSA encrypted message is sent instead of two. This reduces the
|
||||||
|
amount of information attackers can see (and thus use for a crypto attack). It
|
||||||
|
also improves speed by a factor two, making the total speedup a factor 4.
|
||||||
|
|
||||||
|
Third, and most important:
|
||||||
|
|
||||||
|
The symmetric cipher keys are exchanged first, the challenge is done
|
||||||
|
afterwards. In the previous authentication scheme, because a man-in-the-middle
|
||||||
|
could pass the challenge/chal_reply phase (by just copying the messages between
|
||||||
|
the two real tinc daemons), but no information was exchanged that was really
|
||||||
|
needed to read the rest of the messages, the challenge/chal_reply phase was of
|
||||||
|
no real use. The man-in-the-middle was only stopped by the fact that only after
|
||||||
|
the ACK messages were encrypted with the symmetric cipher. Potentially, it
|
||||||
|
could even send it's own symmetric key to the server (if it knew the server's
|
||||||
|
public key) and read some of the metadata the server would send it (it was
|
||||||
|
impossible for the mitm to read actual network packets though). The new scheme
|
||||||
|
however prevents this.
|
||||||
|
|
||||||
|
This new scheme makes sure that first of all, symmetric keys are exchanged. The
|
||||||
|
rest of the messages are then encrypted with the symmetric cipher. Then, each
|
||||||
|
side can only read received messages if they have their private key. The
|
||||||
|
challenge is there to let the other side know that the private key is really
|
||||||
|
known, because a challenge reply can only be sent back if the challenge is
|
||||||
|
decrypted correctly, and that can only be done with knowledge of the private
|
||||||
|
key.
|
||||||
|
|
||||||
|
Fourth: the first thing that is send via the symmetric cipher encrypted
|
||||||
|
connection is a totally random string, so that there is no known plaintext (for
|
||||||
|
an attacker) in the beginning of the encrypted stream.
|
||||||
|
|
||||||
|
Some things to be discussed:
|
||||||
|
|
||||||
|
- What should CHALLEN be? Same as RSAKEYLEN? 256 bits? More/less?
|
Loading…
Reference in a new issue