From: Guus Sliepen Date: Fri, 12 Apr 2002 08:25:01 +0000 (+0000) Subject: Adding even more stuff from the CABAL branch. X-Git-Tag: import-tinc-1.1~822 X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=9f2c50e159caea1884c6a7aaa33f8098539ae0f5;p=meshlink Adding even more stuff from the CABAL branch. --- diff --git a/cvsusers b/cvsusers new file mode 100644 index 00000000..3d1d2d33 --- /dev/null +++ b/cvsusers @@ -0,0 +1,3 @@ +zarq:Ivo Timmermans +guus:Guus Sliepen +wsl:Wessel Dankers diff --git a/doc/CONNECTIVITY b/doc/CONNECTIVITY new file mode 100644 index 00000000..09f1230c --- /dev/null +++ b/doc/CONNECTIVITY @@ -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 + + 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: + + B receives ADD_HOST(D) from C, and notes that is is already known: + + B receives ADD_HOST(E) from C, and notes that is is already known: + + E receives ADD_HOST(C) from F, and notes that is is already known: + + E receives ADD_HOST(A) from F, and notes that is is already known: + + E receives ADD_HOST(B) from F, and notes that is is already known: + + + 4 A receives ADD_HOST(D) from B, and notes that it is already known: + + A receives ADD_HOST(E) from B, and notes that it is already known: + + A receives ADD_HOST(F) from B, and notes that it is already known: + + F receives ADD_HOST(A) from E, and notes that it is already known: + + F receives ADD_HOST(B) from E, and notes that it is already known: + + F receives ADD_HOST(B) from E, and notes that it is already known: + + + ... + +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: + + B receives ADD_HOST(D,E) from C, and notes that D is already known: + + B receives ADD_HOST(E,F) from C, and notes that E is already known: + + E receives ADD_HOST(C,F) from F, and notes that C is already known: + + E receives ADD_HOST(A,B) from F, and notes that A is already known: + + E receives ADD_HOST(B,C) from F, and notes that B is already known: + + +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: + + +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. diff --git a/doc/HOWTO b/doc/HOWTO new file mode 100644 index 00000000..e1b6edfe --- /dev/null +++ b/doc/HOWTO @@ -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 $ diff --git a/doc/NETWORKING b/doc/NETWORKING new file mode 100644 index 00000000..902ed4e1 --- /dev/null +++ b/doc/NETWORKING @@ -0,0 +1,83 @@ +This is the network infrastructure documentation for tinc, a Virtual Private +Network daemon. + + Copyright 2001-2002 Guus Sliepen + + 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(). diff --git a/doc/PROTOCOL b/doc/PROTOCOL new file mode 100644 index 00000000..66544f10 --- /dev/null +++ b/doc/PROTOCOL @@ -0,0 +1,129 @@ +This is the protocol documentation for tinc, a Virtual Private Network daemon. + + Copyright 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmmermans + + 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. diff --git a/doc/SECURITY2 b/doc/SECURITY2 new file mode 100644 index 00000000..b73d34b2 --- /dev/null +++ b/doc/SECURITY2 @@ -0,0 +1,125 @@ +This is the security documentation for tinc, a Virtual Private Network daemon. + + Copyright 2001-2002 Guus Sliepen , + 2001-2002 Wessel Dankers + + 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 + +server + +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?