]> Cypherpunks.ru repositories - govpn.git/blob - transport.go
6065c5eb219f3411664eded9d1f8965b78d2f2aa
[govpn.git] / transport.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package govpn
20
21 import (
22         "encoding/binary"
23         "io"
24         "log"
25         "net"
26         "time"
27
28         "golang.org/x/crypto/poly1305"
29         "golang.org/x/crypto/salsa20"
30         "golang.org/x/crypto/xtea"
31 )
32
33 const (
34         NonceSize = 8
35         KeySize   = 32
36         // S20BS is Salsa20's internal blocksize in bytes
37         S20BS = 64
38         // Maximal amount of bytes transfered with single key (4 GiB)
39         MaxBytesPerKey int64 = 1 << 32
40         // Size of packet's size mark in bytes
41         PktSizeSize = 2
42         // Heartbeat rate, relative to Timeout
43         TimeoutHeartbeat = 4
44 )
45
46 type UDPPkt struct {
47         Addr *net.UDPAddr
48         Size int
49 }
50
51 type Peer struct {
52         Addr            *net.UDPAddr
53         Id              PeerId
54         Key             *[KeySize]byte `json:"-"`
55         NonceOur        uint64         `json:"-"`
56         NonceRecv       uint64         `json:"-"`
57         NonceCipher     *xtea.Cipher   `json:"-"`
58         Established     time.Time
59         LastPing        time.Time
60         LastSent        time.Time
61         willSentCycle   time.Time
62         buf             []byte
63         tag             *[poly1305.TagSize]byte
64         keyAuth         *[KeySize]byte
65         nonceRecv       uint64
66         frame           []byte
67         nonce           []byte
68         pktSize         uint64
69         BytesIn         int64
70         BytesOut        int64
71         BytesPayloadIn  int64
72         BytesPayloadOut int64
73         FramesIn        int
74         FramesOut       int
75         FramesUnauth    int
76         FramesDup       int
77         HeartbeatRecv   int
78         HeartbeatSent   int
79 }
80
81 func (p *Peer) String() string {
82         return p.Id.String() + ":" + p.Addr.String()
83 }
84
85 // Zero peer's memory state
86 func (p *Peer) Zero() {
87         sliceZero(p.Key[:])
88         sliceZero(p.tag[:])
89         sliceZero(p.keyAuth[:])
90         sliceZero(p.buf)
91         sliceZero(p.frame)
92         sliceZero(p.nonce)
93 }
94
95 var (
96         Emptiness       = make([]byte, 1<<14)
97         taps            = make(map[string]*TAP)
98         heartbeatPeriod time.Duration
99 )
100
101 func heartbeatPeriodGet() time.Duration {
102         if heartbeatPeriod == time.Duration(0) {
103                 heartbeatPeriod = Timeout / TimeoutHeartbeat
104         }
105         return heartbeatPeriod
106 }
107
108 // Create TAP listening goroutine.
109 // This function takes required TAP interface name, opens it and allocates
110 // a buffer where all frame data will be written, channel where information
111 // about number of read bytes is sent to, synchronization channel (external
112 // processes tell that read buffer can be used again) and possible channel
113 // opening error.
114 func TAPListen(ifaceName string) (*TAP, chan []byte, chan struct{}, chan struct{}, error) {
115         var tap *TAP
116         var err error
117         tap, exists := taps[ifaceName]
118         if !exists {
119                 tap, err = NewTAP(ifaceName)
120                 if err != nil {
121                         return nil, nil, nil, nil, err
122                 }
123                 taps[ifaceName] = tap
124         }
125         sink := make(chan []byte)
126         sinkReady := make(chan struct{})
127         sinkTerminate := make(chan struct{})
128         sinkSkip := make(chan struct{})
129
130         go func() {
131                 heartbeat := time.Tick(heartbeatPeriodGet())
132                 var pkt []byte
133         ListenCycle:
134                 for {
135                         select {
136                         case <-sinkTerminate:
137                                 break ListenCycle
138                         case <-heartbeat:
139                                 go func() { sink <- make([]byte, 0) }()
140                                 continue
141                         case <-sinkSkip:
142                         case <-sinkReady:
143                                 tap.ready <- struct{}{}
144                                 tap.synced = true
145                         }
146                 HeartbeatCatched:
147                         select {
148                         case <-heartbeat:
149                                 go func() { sink <- make([]byte, 0) }()
150                                 goto HeartbeatCatched
151                         case <-sinkTerminate:
152                                 break ListenCycle
153                         case pkt = <-tap.sink:
154                                 tap.synced = false
155                                 sink <- pkt
156                         }
157                 }
158                 close(sink)
159                 close(sinkReady)
160                 close(sinkTerminate)
161         }()
162         if exists && tap.synced {
163                 sinkSkip <- struct{}{}
164         } else {
165                 sinkReady <- struct{}{}
166         }
167         return tap, sink, sinkReady, sinkTerminate, nil
168 }
169
170 // Create UDP listening goroutine.
171 // This function takes already listening UDP socket and a buffer where
172 // all UDP packet data will be saved, channel where information about
173 // remote address and number of written bytes are stored, and a channel
174 // used to tell that buffer is ready to be overwritten.
175 func ConnListen(conn *net.UDPConn) (chan UDPPkt, []byte, chan struct{}) {
176         buf := make([]byte, MTU)
177         sink := make(chan UDPPkt)
178         sinkReady := make(chan struct{})
179         go func(conn *net.UDPConn) {
180                 var n int
181                 var addr *net.UDPAddr
182                 var err error
183                 for {
184                         <-sinkReady
185                         conn.SetReadDeadline(time.Now().Add(time.Second))
186                         n, addr, err = conn.ReadFromUDP(buf)
187                         if err != nil {
188                                 // This is needed for ticking the timeouts counter outside
189                                 sink <- UDPPkt{nil, 0}
190                                 continue
191                         }
192                         sink <- UDPPkt{addr, n}
193                 }
194         }(conn)
195         sinkReady <- struct{}{}
196         return sink, buf, sinkReady
197 }
198
199 func newNonceCipher(key *[KeySize]byte) *xtea.Cipher {
200         nonceKey := make([]byte, 16)
201         salsa20.XORKeyStream(
202                 nonceKey,
203                 make([]byte, KeySize),
204                 make([]byte, xtea.BlockSize),
205                 key,
206         )
207         ciph, err := xtea.NewCipher(nonceKey)
208         if err != nil {
209                 panic(err)
210         }
211         return ciph
212 }
213
214 func newPeer(addr *net.UDPAddr, id PeerId, nonce int, key *[KeySize]byte) *Peer {
215         now := time.Now()
216         peer := Peer{
217                 Addr:        addr,
218                 Established: now,
219                 LastPing:    now,
220                 Id:          id,
221                 NonceOur:    uint64(Noncediff + nonce),
222                 NonceRecv:   uint64(Noncediff + 0),
223                 Key:         key,
224                 NonceCipher: newNonceCipher(key),
225                 buf:         make([]byte, MTU+S20BS),
226                 tag:         new([poly1305.TagSize]byte),
227                 keyAuth:     new([KeySize]byte),
228                 nonce:       make([]byte, NonceSize),
229         }
230         return &peer
231 }
232
233 // Process incoming UDP packet.
234 // udpPkt is received data, related to the peer tap interface and
235 // ConnListen'es synchronization channel used to tell him that he is
236 // free to receive new packets. Authenticated and decrypted packets
237 // will be written to the interface immediately (except heartbeat ones).
238 func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
239         size := len(udpPkt)
240         copy(p.buf, Emptiness)
241         copy(p.tag[:], udpPkt[size-poly1305.TagSize:])
242         copy(p.buf[S20BS:], udpPkt[NonceSize:size-poly1305.TagSize])
243         salsa20.XORKeyStream(
244                 p.buf[:S20BS+size-poly1305.TagSize],
245                 p.buf[:S20BS+size-poly1305.TagSize],
246                 udpPkt[:NonceSize],
247                 p.Key,
248         )
249         copy(p.keyAuth[:], p.buf[:KeySize])
250         if !poly1305.Verify(p.tag, udpPkt[:size-poly1305.TagSize], p.keyAuth) {
251                 ready <- struct{}{}
252                 p.FramesUnauth++
253                 return false
254         }
255         p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
256         p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
257         if int(p.NonceRecv)-Noncediff >= 0 && int(p.nonceRecv) < int(p.NonceRecv)-Noncediff {
258                 ready <- struct{}{}
259                 p.FramesDup++
260                 return false
261         }
262         ready <- struct{}{}
263         p.FramesIn++
264         p.BytesIn += int64(size)
265         p.LastPing = time.Now()
266         p.NonceRecv = p.nonceRecv
267         p.pktSize, _ = binary.Uvarint(p.buf[S20BS : S20BS+PktSizeSize])
268         if p.pktSize == 0 {
269                 p.HeartbeatRecv++
270                 return true
271         }
272         p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
273         p.BytesPayloadIn += int64(p.pktSize)
274         tap.Write(p.frame)
275         return true
276 }
277
278 type WriteToer interface {
279         WriteTo([]byte, net.Addr) (int, error)
280 }
281
282 // Process incoming Ethernet packet.
283 // ethPkt is received data, conn is our outgoing connection.
284 // ready channel is TAPListen's synchronization channel used to tell him
285 // that he is free to receive new packets. Encrypted and authenticated
286 // packets will be sent to remote Peer side immediately.
287 func (p *Peer) EthProcess(ethPkt []byte, conn WriteToer, ready chan struct{}) {
288         now := time.Now()
289         size := len(ethPkt)
290         // If this heartbeat is necessary
291         if size == 0 && !p.LastSent.Add(heartbeatPeriodGet()).Before(now) {
292                 return
293         }
294         copy(p.buf, Emptiness)
295         if size > 0 {
296                 copy(p.buf[S20BS+PktSizeSize:], ethPkt)
297                 ready <- struct{}{}
298                 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(size))
299                 p.BytesPayloadOut += int64(size)
300         } else {
301                 p.HeartbeatSent++
302         }
303
304         p.NonceOur += 2
305         copy(p.nonce, Emptiness)
306         binary.PutUvarint(p.nonce, p.NonceOur)
307         p.NonceCipher.Encrypt(p.nonce, p.nonce)
308
309         salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
310         copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
311         copy(p.keyAuth[:], p.buf[:KeySize])
312         if NoiseEnable {
313                 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
314         } else {
315                 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+size]
316         }
317         poly1305.Sum(p.tag, p.frame, p.keyAuth)
318
319         p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
320         p.FramesOut++
321
322         if cprEnable {
323                 p.willSentCycle = p.LastSent.Add(cprCycle)
324                 if p.willSentCycle.After(now) {
325                         time.Sleep(p.willSentCycle.Sub(now))
326                         now = p.willSentCycle
327                 }
328         }
329         p.LastSent = now
330         if _, err := conn.WriteTo(append(p.frame, p.tag[:]...), p.Addr); err != nil {
331                 log.Println("Error sending UDP", err)
332         }
333 }