]> Cypherpunks.ru repositories - govpn.git/blob - src/govpn/transport.go
5085d29285e32f108134533b650e329d9c088ca0
[govpn.git] / src / govpn / 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         "time"
25
26         "golang.org/x/crypto/poly1305"
27         "golang.org/x/crypto/salsa20"
28         "golang.org/x/crypto/xtea"
29 )
30
31 const (
32         NonceSize       = 8
33         NonceBucketSize = 128
34         // S20BS is Salsa20's internal blocksize in bytes
35         S20BS = 64
36         // Maximal amount of bytes transfered with single key (4 GiB)
37         MaxBytesPerKey int64 = 1 << 32
38         // Size of packet's size mark in bytes
39         PktSizeSize = 2
40         // Heartbeat rate, relative to Timeout
41         TimeoutHeartbeat = 4
42 )
43
44 type RemoteConn interface {
45         io.Writer
46         // Can incoming packets be reordered
47         Reorderable() bool
48 }
49
50 type Peer struct {
51         Addr string
52         Id   *PeerId
53         Conn RemoteConn
54
55         // Traffic behaviour
56         NoiseEnable bool
57         CPR         int
58         CPRCycle    time.Duration `json:"-"`
59
60         // Cryptography related
61         Key          *[SSize]byte `json:"-"`
62         NonceOur     uint64       `json:"-"`
63         NonceRecv    uint64       `json:"-"`
64         NonceCipher  *xtea.Cipher `json:"-"`
65         nonceExpect  uint64       `json:"-"`
66         nonceBucket0 map[uint64]struct{}
67         nonceBucket1 map[uint64]struct{}
68         nonceFound   bool
69         nonceBucketN int32
70
71         // Timers
72         Timeout       time.Duration `json:"-"`
73         Established   time.Time
74         LastPing      time.Time
75         LastSent      time.Time
76         willSentCycle time.Time
77
78         // This variables are initialized only once to relief GC
79         buf       []byte
80         tag       *[poly1305.TagSize]byte
81         keyAuth   *[32]byte
82         nonceRecv uint64
83         frame     []byte
84         nonce     []byte
85         pktSize   uint64
86         size      int
87         now       time.Time
88
89         // Statistics
90         BytesIn         int64
91         BytesOut        int64
92         BytesPayloadIn  int64
93         BytesPayloadOut int64
94         FramesIn        int
95         FramesOut       int
96         FramesUnauth    int
97         FramesDup       int
98         HeartbeatRecv   int
99         HeartbeatSent   int
100 }
101
102 func (p *Peer) String() string {
103         return p.Id.String() + ":" + p.Addr
104 }
105
106 // Zero peer's memory state.
107 func (p *Peer) Zero() {
108         sliceZero(p.Key[:])
109         sliceZero(p.tag[:])
110         sliceZero(p.keyAuth[:])
111         sliceZero(p.buf)
112         sliceZero(p.frame)
113         sliceZero(p.nonce)
114 }
115
116 var (
117         Emptiness = make([]byte, 1<<14)
118         taps      = make(map[string]*TAP)
119 )
120
121 // Create TAP listening goroutine.
122 // This function takes required TAP interface name, opens it and allocates
123 // a buffer where all frame data will be written, channel where information
124 // about number of read bytes is sent to, synchronization channel (external
125 // processes tell that read buffer can be used again) and possible channel
126 // opening error.
127 func TAPListen(ifaceName string, timeout time.Duration, cpr int) (*TAP, chan []byte, chan struct{}, chan struct{}, error) {
128         var tap *TAP
129         var err error
130         tap, exists := taps[ifaceName]
131         if !exists {
132                 tap, err = NewTAP(ifaceName)
133                 if err != nil {
134                         return nil, nil, nil, nil, err
135                 }
136                 taps[ifaceName] = tap
137         }
138         sink := make(chan []byte)
139         sinkReady := make(chan struct{})
140         sinkTerminate := make(chan struct{})
141         sinkSkip := make(chan struct{})
142
143         go func() {
144                 cprCycle := cprCycleCalculate(cpr)
145                 if cprCycle != time.Duration(0) {
146                         timeout = cprCycle
147                 } else {
148                         timeout = timeout / TimeoutHeartbeat
149                 }
150                 heartbeat := time.Tick(timeout)
151                 var pkt []byte
152         ListenCycle:
153                 for {
154                         select {
155                         case <-sinkTerminate:
156                                 break ListenCycle
157                         case <-heartbeat:
158                                 go func() { sink <- make([]byte, 0) }()
159                                 continue
160                         case <-sinkSkip:
161                         case <-sinkReady:
162                                 tap.ready <- struct{}{}
163                                 tap.synced = true
164                         }
165                 HeartbeatCatched:
166                         select {
167                         case <-heartbeat:
168                                 go func() { sink <- make([]byte, 0) }()
169                                 goto HeartbeatCatched
170                         case <-sinkTerminate:
171                                 break ListenCycle
172                         case pkt = <-tap.sink:
173                                 tap.synced = false
174                                 sink <- pkt
175                         }
176                 }
177                 close(sink)
178                 close(sinkReady)
179                 close(sinkTerminate)
180         }()
181         if exists && tap.synced {
182                 sinkSkip <- struct{}{}
183         } else {
184                 sinkReady <- struct{}{}
185         }
186         return tap, sink, sinkReady, sinkTerminate, nil
187 }
188
189 func newNonceCipher(key *[32]byte) *xtea.Cipher {
190         nonceKey := make([]byte, 16)
191         salsa20.XORKeyStream(
192                 nonceKey,
193                 make([]byte, 32),
194                 make([]byte, xtea.BlockSize),
195                 key,
196         )
197         ciph, err := xtea.NewCipher(nonceKey)
198         if err != nil {
199                 panic(err)
200         }
201         return ciph
202 }
203
204 func cprCycleCalculate(rate int) time.Duration {
205         if rate == 0 {
206                 return time.Duration(0)
207         }
208         return time.Second / time.Duration(rate*(1<<10)/MTU)
209 }
210
211 func newPeer(isClient bool, addr string, conn RemoteConn, conf *PeerConf, key *[SSize]byte) *Peer {
212         now := time.Now()
213         timeout := conf.Timeout
214         cprCycle := cprCycleCalculate(conf.CPR)
215         noiseEnable := conf.NoiseEnable
216         if conf.CPR > 0 {
217                 noiseEnable = true
218                 timeout = cprCycle
219         } else {
220                 timeout = timeout / TimeoutHeartbeat
221         }
222         peer := Peer{
223                 Addr:        addr,
224                 Conn:        conn,
225                 Timeout:     timeout,
226                 Established: now,
227                 LastPing:    now,
228                 Id:          conf.Id,
229                 NoiseEnable: noiseEnable,
230                 CPR:         conf.CPR,
231                 CPRCycle:    cprCycle,
232                 NonceRecv:   0,
233                 Key:         key,
234                 NonceCipher: newNonceCipher(key),
235                 buf:         make([]byte, MTU+S20BS),
236                 tag:         new([poly1305.TagSize]byte),
237                 keyAuth:     new([SSize]byte),
238                 nonce:       make([]byte, NonceSize),
239         }
240         if isClient {
241                 peer.NonceOur = 1
242                 peer.nonceExpect = 0 + 2
243         } else {
244                 peer.NonceOur = 0
245                 peer.nonceExpect = 1 + 2
246         }
247         if conn.Reorderable() {
248                 peer.nonceBucket0 = make(map[uint64]struct{}, NonceBucketSize)
249                 peer.nonceBucket1 = make(map[uint64]struct{}, NonceBucketSize)
250         }
251         return &peer
252 }
253
254 // Process incoming UDP packet.
255 // ConnListen'es synchronization channel used to tell him that he is
256 // free to receive new packets. Authenticated and decrypted packets
257 // will be written to the interface immediately (except heartbeat ones).
258 func (p *Peer) PktProcess(data []byte, tap io.Writer, ready chan struct{}) bool {
259         p.size = len(data)
260         copy(p.buf, Emptiness)
261         copy(p.tag[:], data[p.size-poly1305.TagSize:])
262         copy(p.buf[S20BS:], data[NonceSize:p.size-poly1305.TagSize])
263         salsa20.XORKeyStream(
264                 p.buf[:S20BS+p.size-poly1305.TagSize],
265                 p.buf[:S20BS+p.size-poly1305.TagSize],
266                 data[:NonceSize],
267                 p.Key,
268         )
269         copy(p.keyAuth[:], p.buf[:SSize])
270         if !poly1305.Verify(p.tag, data[:p.size-poly1305.TagSize], p.keyAuth) {
271                 ready <- struct{}{}
272                 p.FramesUnauth++
273                 return false
274         }
275
276         // Check if received nonce is known to us in either of two buckets.
277         // If yes, then this is ignored duplicate.
278         // Check from the oldest bucket, as in most cases this will result
279         // in constant time check.
280         // If Bucket0 is filled, then it becomes Bucket1.
281         p.NonceCipher.Decrypt(p.buf, data[:NonceSize])
282         ready <- struct{}{}
283
284         p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
285         if p.Conn.Reorderable() {
286                 if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
287                         p.FramesDup++
288                         return false
289                 }
290                 if _, p.nonceFound = p.nonceBucket0[p.NonceRecv]; p.nonceFound {
291                         p.FramesDup++
292                         return false
293                 }
294                 p.nonceBucket0[p.NonceRecv] = struct{}{}
295                 p.nonceBucketN++
296                 if p.nonceBucketN == NonceBucketSize {
297                         p.nonceBucket1 = p.nonceBucket0
298                         p.nonceBucket0 = make(map[uint64]struct{}, NonceBucketSize)
299                         p.nonceBucketN = 0
300                 }
301         } else {
302                 if p.nonceRecv != p.nonceExpect {
303                         p.FramesDup++
304                         return false
305                 }
306                 p.nonceExpect += 2
307         }
308
309         p.FramesIn++
310         p.BytesIn += int64(p.size)
311         p.LastPing = time.Now()
312         p.NonceRecv = p.nonceRecv
313         p.pktSize, _ = binary.Uvarint(p.buf[S20BS : S20BS+PktSizeSize])
314         if p.pktSize == 0 {
315                 p.HeartbeatRecv++
316                 return true
317         }
318         p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
319         p.BytesPayloadIn += int64(p.pktSize)
320         tap.Write(p.frame)
321         return true
322 }
323
324 // Process incoming Ethernet packet.
325 // ready channel is TAPListen's synchronization channel used to tell him
326 // that he is free to receive new packets. Encrypted and authenticated
327 // packets will be sent to remote Peer side immediately.
328 func (p *Peer) EthProcess(data []byte, ready chan struct{}) {
329         p.now = time.Now()
330         p.size = len(data)
331         // If this heartbeat is necessary
332         if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
333                 return
334         }
335         copy(p.buf, Emptiness)
336         if p.size > 0 {
337                 copy(p.buf[S20BS+PktSizeSize:], data)
338                 ready <- struct{}{}
339                 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
340                 p.BytesPayloadOut += int64(p.size)
341         } else {
342                 p.HeartbeatSent++
343         }
344
345         p.NonceOur += 2
346         copy(p.nonce, Emptiness)
347         binary.PutUvarint(p.nonce, p.NonceOur)
348         p.NonceCipher.Encrypt(p.nonce, p.nonce)
349
350         salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
351         copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
352         copy(p.keyAuth[:], p.buf[:SSize])
353         if p.NoiseEnable {
354                 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
355         } else {
356                 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+p.size]
357         }
358         poly1305.Sum(p.tag, p.frame, p.keyAuth)
359
360         p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
361         p.FramesOut++
362
363         if p.CPRCycle != time.Duration(0) {
364                 p.willSentCycle = p.LastSent.Add(p.CPRCycle)
365                 if p.willSentCycle.After(p.now) {
366                         time.Sleep(p.willSentCycle.Sub(p.now))
367                         p.now = p.willSentCycle
368                 }
369         }
370         p.LastSent = p.now
371         p.Conn.Write(append(p.frame, p.tag[:]...))
372 }