]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/peer.go
Various stylistic and grammar fixes
[govpn.git] / src / cypherpunks.ru / govpn / peer.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2017 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         "bytes"
23         "crypto/subtle"
24         "encoding/binary"
25         "io"
26         "log"
27         "sync"
28         "sync/atomic"
29         "time"
30
31         "chacha20"
32         "golang.org/x/crypto/blake2b"
33         "golang.org/x/crypto/poly1305"
34 )
35
36 const (
37         // NonceSize is nonce size
38         NonceSize       = 8
39         NonceBucketSize = 256
40         TagSize         = poly1305.TagSize
41         // S20BS is ChaCha20's internal blocksize in bytes
42         S20BS = 64
43         // MaxBytesPerKey is maximal amount of bytes transferred with single key (4 GiB)
44         MaxBytesPerKey uint64 = 1 << 32
45         // Heartbeat rate, relative to Timeout
46         TimeoutHeartbeat = 4
47         // MinPktLength is minimal valid packet length
48         MinPktLength = 1 + 16 + 8
49         // Padding byte
50         PadByte = byte(0x80)
51 )
52
53 func newNonces(key *[32]byte, i uint64) chan *[NonceSize]byte {
54         macKey := make([]byte, 32)
55         chacha20.XORKeyStream(macKey, make([]byte, 32), new([16]byte), key)
56         mac, err := blake2b.New256(macKey)
57         if err != nil {
58                 panic(err)
59         }
60         sum := make([]byte, mac.Size())
61         nonces := make(chan *[NonceSize]byte, NonceBucketSize*3)
62         go func() {
63                 for {
64                         buf := new([NonceSize]byte)
65                         binary.BigEndian.PutUint64(buf[:], i)
66                         mac.Write(buf[:])
67                         mac.Sum(sum[:0])
68                         copy(buf[:], sum)
69                         nonces <- buf
70                         mac.Reset()
71                         i += 2
72                 }
73         }()
74         return nonces
75 }
76
77 // Peer is a GoVPN peer (client)
78 type Peer struct {
79         // Statistics (they are at the beginning for correct int64 alignment)
80         BytesIn         uint64
81         BytesOut        uint64
82         BytesPayloadIn  uint64
83         BytesPayloadOut uint64
84         FramesIn        uint64
85         FramesOut       uint64
86         FramesUnauth    uint64
87         FramesDup       uint64
88         HeartbeatRecv   uint64
89         HeartbeatSent   uint64
90
91         // Basic
92         Addr string
93         ID   *PeerID
94         Conn io.Writer `json:"-"`
95
96         // Traffic behaviour
97         NoiseEnable bool
98         CPR         int
99         CPRCycle    time.Duration `json:"-"`
100         Encless     bool
101         MTU         int
102
103         key *[SSize]byte
104
105         // Timers
106         Timeout     time.Duration `json:"-"`
107         Established time.Time
108         LastPing    time.Time
109
110         // Receiver
111         BusyR    sync.Mutex `json:"-"`
112         bufR     []byte
113         tagR     *[TagSize]byte
114         keyAuthR *[SSize]byte
115         nonceR   *[16]byte
116         pktSizeR int
117
118         // UDP-related
119         noncesR      chan *[NonceSize]byte
120         nonceRecv    [NonceSize]byte
121         nonceBucketL map[[NonceSize]byte]struct{}
122         nonceBucketM map[[NonceSize]byte]struct{}
123         nonceBucketH map[[NonceSize]byte]struct{}
124
125         // TCP-related
126         NonceExpect  []byte `json:"-"`
127         noncesExpect chan *[NonceSize]byte
128
129         // Transmitter
130         BusyT    sync.Mutex `json:"-"`
131         bufT     []byte
132         tagT     *[TagSize]byte
133         keyAuthT *[SSize]byte
134         nonceT   *[16]byte
135         frameT   []byte
136         noncesT  chan *[NonceSize]byte
137 }
138
139 func (p *Peer) String() string {
140         return p.ID.String() + ":" + p.Addr
141 }
142
143 // Zero peer's memory state.
144 func (p *Peer) Zero() {
145         p.BusyT.Lock()
146         p.BusyR.Lock()
147         SliceZero(p.key[:])
148         SliceZero(p.bufR)
149         SliceZero(p.bufT)
150         SliceZero(p.keyAuthR[:])
151         SliceZero(p.keyAuthT[:])
152         p.BusyT.Unlock()
153         p.BusyR.Unlock()
154 }
155
156 func cprCycleCalculate(conf *PeerConf) time.Duration {
157         if conf.CPR == 0 {
158                 return time.Duration(0)
159         }
160         rate := conf.CPR * 1 << 10
161         if conf.Encless {
162                 rate /= EnclessEnlargeSize + conf.MTU
163         } else {
164                 rate /= conf.MTU
165         }
166         return time.Second / time.Duration(rate)
167 }
168
169 func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[SSize]byte) *Peer {
170         now := time.Now()
171         timeout := conf.Timeout
172
173         cprCycle := cprCycleCalculate(conf)
174         noiseEnable := conf.Noise
175         if conf.CPR > 0 {
176                 noiseEnable = true
177                 timeout = cprCycle
178         } else {
179                 timeout = timeout / TimeoutHeartbeat
180         }
181
182         bufSize := S20BS + 2*conf.MTU
183         if conf.Encless {
184                 bufSize += EnclessEnlargeSize
185                 noiseEnable = true
186         }
187
188         peer := Peer{
189                 Addr: addr,
190                 ID:   conf.ID,
191                 Conn: conn,
192
193                 NoiseEnable: noiseEnable,
194                 CPR:         conf.CPR,
195                 CPRCycle:    cprCycle,
196                 Encless:     conf.Encless,
197                 MTU:         conf.MTU,
198
199                 key: key,
200
201                 Timeout:     timeout,
202                 Established: now,
203                 LastPing:    now,
204
205                 bufR:     make([]byte, bufSize),
206                 bufT:     make([]byte, bufSize),
207                 tagR:     new([TagSize]byte),
208                 tagT:     new([TagSize]byte),
209                 keyAuthR: new([SSize]byte),
210                 nonceR:   new([16]byte),
211                 keyAuthT: new([SSize]byte),
212                 nonceT:   new([16]byte),
213         }
214
215         if isClient {
216                 peer.noncesT = newNonces(peer.key, 1+2)
217                 peer.noncesR = newNonces(peer.key, 0+2)
218                 peer.noncesExpect = newNonces(peer.key, 0+2)
219         } else {
220                 peer.noncesT = newNonces(peer.key, 0+2)
221                 peer.noncesR = newNonces(peer.key, 1+2)
222                 peer.noncesExpect = newNonces(peer.key, 1+2)
223         }
224
225         peer.NonceExpect = make([]byte, NonceSize)
226         nonce := <-peer.noncesExpect
227         copy(peer.NonceExpect, nonce[:])
228
229         var i int
230         peer.nonceBucketL = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
231         for i = 0; i < NonceBucketSize; i++ {
232                 nonce = <-peer.noncesR
233                 peer.nonceBucketL[*nonce] = struct{}{}
234         }
235         peer.nonceBucketM = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
236         for i = 0; i < NonceBucketSize; i++ {
237                 nonce = <-peer.noncesR
238                 peer.nonceBucketM[*nonce] = struct{}{}
239         }
240         peer.nonceBucketH = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
241         for i = 0; i < NonceBucketSize; i++ {
242                 nonce = <-peer.noncesR
243                 peer.nonceBucketH[*nonce] = struct{}{}
244         }
245
246         return &peer
247 }
248
249 // EthProcess processes incoming Ethernet packet.
250 // ready channel is TAPListen's synchronization channel used to tell him
251 // that he is free to receive new packets. Encrypted and authenticated
252 // packets will be sent to remote Peer side immediately.
253 func (p *Peer) EthProcess(data []byte) {
254         if len(data) > p.MTU-1 { // 1 is for padding byte
255                 log.Println("Padded data packet size", len(data)+1, "is bigger than MTU", p.MTU, p)
256                 return
257         }
258         p.BusyT.Lock()
259
260         // Zero size is a heartbeat packet
261         SliceZero(p.bufT)
262         if len(data) == 0 {
263                 p.bufT[S20BS+0] = PadByte
264                 p.HeartbeatSent++
265         } else {
266                 // Copy payload to our internal buffer and we are ready to
267                 // accept the next one
268                 copy(p.bufT[S20BS:], data)
269                 p.bufT[S20BS+len(data)] = PadByte
270                 p.BytesPayloadOut += uint64(len(data))
271         }
272
273         if p.NoiseEnable && !p.Encless {
274                 p.frameT = p.bufT[S20BS : S20BS+p.MTU-TagSize]
275         } else if p.Encless {
276                 p.frameT = p.bufT[S20BS : S20BS+p.MTU]
277         } else {
278                 p.frameT = p.bufT[S20BS : S20BS+len(data)+1+NonceSize]
279         }
280         copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
281         var out []byte
282         copy(p.nonceT[8:], p.frameT[len(p.frameT)-NonceSize:])
283         if p.Encless {
284                 var err error
285                 out, err = EnclessEncode(p.key, p.nonceT, p.frameT[:len(p.frameT)-NonceSize])
286                 if err != nil {
287                         panic(err)
288                 }
289                 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
290         } else {
291                 chacha20.XORKeyStream(
292                         p.bufT[:S20BS+len(p.frameT)-NonceSize],
293                         p.bufT[:S20BS+len(p.frameT)-NonceSize],
294                         p.nonceT,
295                         p.key,
296                 )
297                 copy(p.keyAuthT[:], p.bufT[:SSize])
298                 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
299                 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+TagSize))
300                 out = append(p.tagT[:], p.frameT...)
301         }
302         p.FramesOut++
303         p.Conn.Write(out)
304         p.BusyT.Unlock()
305 }
306
307 // PktProcess processes data of a single packet
308 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
309         if len(data) < MinPktLength {
310                 return false
311         }
312         if !p.Encless && len(data) > len(p.bufR)-S20BS {
313                 return false
314         }
315         var out []byte
316         p.BusyR.Lock()
317         copy(p.nonceR[8:], data[len(data)-NonceSize:])
318         if p.Encless {
319                 var err error
320                 out, err = EnclessDecode(p.key, p.nonceR, data[:len(data)-NonceSize])
321                 if err != nil {
322                         p.FramesUnauth++
323                         p.BusyR.Unlock()
324                         return false
325                 }
326         } else {
327                 for i := 0; i < SSize; i++ {
328                         p.bufR[i] = 0
329                 }
330                 copy(p.bufR[S20BS:], data[TagSize:])
331                 chacha20.XORKeyStream(
332                         p.bufR[:S20BS+len(data)-TagSize-NonceSize],
333                         p.bufR[:S20BS+len(data)-TagSize-NonceSize],
334                         p.nonceR,
335                         p.key,
336                 )
337                 copy(p.keyAuthR[:], p.bufR[:SSize])
338                 copy(p.tagR[:], data[:TagSize])
339                 if !poly1305.Verify(p.tagR, data[TagSize:], p.keyAuthR) {
340                         p.FramesUnauth++
341                         p.BusyR.Unlock()
342                         return false
343                 }
344                 out = p.bufR[S20BS : S20BS+len(data)-TagSize-NonceSize]
345         }
346
347         if reorderable {
348                 copy(p.nonceRecv[:], data[len(data)-NonceSize:])
349                 _, foundL := p.nonceBucketL[p.nonceRecv]
350                 _, foundM := p.nonceBucketM[p.nonceRecv]
351                 _, foundH := p.nonceBucketH[p.nonceRecv]
352                 // If found is none of buckets: either it is too old,
353                 // or too new (many packets were lost)
354                 if !(foundL || foundM || foundH) {
355                         p.FramesDup++
356                         p.BusyR.Unlock()
357                         return false
358                 }
359                 // Delete seen nonce
360                 if foundL {
361                         delete(p.nonceBucketL, p.nonceRecv)
362                 }
363                 if foundM {
364                         delete(p.nonceBucketM, p.nonceRecv)
365                 }
366                 if foundH {
367                         delete(p.nonceBucketH, p.nonceRecv)
368                 }
369                 // If we are dealing with the latest bucket, create the new one
370                 if foundH {
371                         p.nonceBucketL, p.nonceBucketM = p.nonceBucketM, p.nonceBucketH
372                         p.nonceBucketH = make(map[[NonceSize]byte]struct{})
373                         var nonce *[NonceSize]byte
374                         for i := 0; i < NonceBucketSize; i++ {
375                                 nonce = <-p.noncesR
376                                 p.nonceBucketH[*nonce] = struct{}{}
377                         }
378                 }
379         } else {
380                 if subtle.ConstantTimeCompare(data[len(data)-NonceSize:], p.NonceExpect) != 1 {
381                         p.FramesDup++
382                         p.BusyR.Unlock()
383                         return false
384                 }
385                 copy(p.NonceExpect, (<-p.noncesExpect)[:])
386         }
387
388         p.FramesIn++
389         atomic.AddUint64(&p.BytesIn, uint64(len(data)))
390         p.LastPing = time.Now()
391         p.pktSizeR = bytes.LastIndexByte(out, PadByte)
392         if p.pktSizeR == -1 {
393                 p.BusyR.Unlock()
394                 return false
395         }
396         // Validate the pad
397         for i := p.pktSizeR + 1; i < len(out); i++ {
398                 if out[i] != 0 {
399                         p.BusyR.Unlock()
400                         return false
401                 }
402         }
403
404         if p.pktSizeR == 0 {
405                 p.HeartbeatRecv++
406                 p.BusyR.Unlock()
407                 return true
408         }
409         p.BytesPayloadIn += uint64(p.pktSizeR)
410         tap.Write(out[:p.pktSizeR])
411         p.BusyR.Unlock()
412         return true
413 }
414
415 // PeerTapProcessor processes a TUN/TAP peer
416 func PeerTapProcessor(peer *Peer, tap *TAP, terminator chan struct{}) {
417         var data []byte
418         var now time.Time
419         lastSent := time.Now()
420         heartbeat := time.NewTicker(peer.Timeout)
421         if peer.CPRCycle == time.Duration(0) {
422         RawProcessor:
423                 for {
424                         select {
425                         case <-terminator:
426                                 break RawProcessor
427                         case <-heartbeat.C:
428                                 now = time.Now()
429                                 if lastSent.Add(peer.Timeout).Before(now) {
430                                         peer.EthProcess(nil)
431                                         lastSent = now
432                                 }
433                         case data = <-tap.Sink:
434                                 peer.EthProcess(data)
435                                 lastSent = time.Now()
436                         }
437                 }
438         } else {
439         CPRProcessor:
440                 for {
441                         data = nil
442                         select {
443                         case <-terminator:
444                                 break CPRProcessor
445                         case data = <-tap.Sink:
446                                 peer.EthProcess(data)
447                         default:
448                         }
449                         if data == nil {
450                                 peer.EthProcess(nil)
451                         }
452                         time.Sleep(peer.CPRCycle)
453                 }
454         }
455         close(terminator)
456         peer.Zero()
457         heartbeat.Stop()
458 }