]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/peer.go
3856208d01a4bb38aa12a713648a1844dad8e0ad
[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         "sync"
27         "sync/atomic"
28         "time"
29
30         "chacha20"
31         "github.com/Sirupsen/logrus"
32         "github.com/pkg/errors"
33         "golang.org/x/crypto/blake2b"
34         "golang.org/x/crypto/poly1305"
35 )
36
37 const (
38         // NonceSize is nonce size
39         NonceSize       = 8
40         nonceBucketSize = 256
41         tagSize         = poly1305.TagSize
42         CC20IBS         = 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         logPrefixPeer = "peer_"
53 )
54
55 func newNonces(key *[32]byte, i uint64) (chan *[NonceSize]byte, error) {
56         macKey := make([]byte, 32)
57         chacha20.XORKeyStream(macKey, make([]byte, 32), new([16]byte), key)
58         mac, err := blake2b.New256(macKey)
59         if err != nil {
60                 panic(err)
61         }
62         sum := make([]byte, mac.Size())
63         nonces := make(chan *[NonceSize]byte, nonceBucketSize*3)
64         go func() {
65                 for {
66                         buf := new([NonceSize]byte)
67                         binary.BigEndian.PutUint64(buf[:], i)
68                         mac.Write(buf[:])
69                         mac.Sum(sum[:0])
70                         copy(buf[:], sum)
71                         nonces <- buf
72                         mac.Reset()
73                         i += 2
74                 }
75         }()
76         return nonces, nil
77 }
78
79 // Peer is a GoVPN peer (client)
80 type Peer struct {
81         // Statistics (they are at the beginning for correct int64 alignment)
82         BytesIn         uint64
83         BytesOut        uint64
84         BytesPayloadIn  uint64
85         BytesPayloadOut uint64
86         FramesIn        uint64
87         FramesOut       uint64
88         FramesUnauth    uint64
89         FramesDup       uint64
90         HeartbeatRecv   uint64
91         HeartbeatSent   uint64
92
93         // Basic
94         Addr     string
95         ID       *PeerID
96         Conn     io.Writer `json:"-"`
97         Protocol Protocol
98
99         // Traffic behaviour
100         NoiseEnable bool
101         CPR         int
102         CPRCycle    time.Duration `json:"-"`
103         Encless     bool
104         MTU         int
105
106         key *[SSize]byte
107
108         // Timers
109         Timeout     time.Duration `json:"-"`
110         Established time.Time
111         LastPing    time.Time
112
113         // Receiver
114         BusyR    sync.Mutex `json:"-"`
115         bufR     []byte
116         tagR     *[tagSize]byte
117         keyAuthR *[SSize]byte
118         nonceR   *[16]byte
119         pktSizeR int
120
121         // UDP-related
122         noncesR      chan *[NonceSize]byte
123         nonceRecv    [NonceSize]byte
124         nonceBucketL map[[NonceSize]byte]struct{}
125         nonceBucketM map[[NonceSize]byte]struct{}
126         nonceBucketH map[[NonceSize]byte]struct{}
127
128         // TCP-related
129         NonceExpect  []byte `json:"-"`
130         noncesExpect chan *[NonceSize]byte
131
132         // Transmitter
133         BusyT    sync.Mutex `json:"-"`
134         bufT     []byte
135         tagT     *[tagSize]byte
136         keyAuthT *[SSize]byte
137         nonceT   *[16]byte
138         frameT   []byte
139         noncesT  chan *[NonceSize]byte
140 }
141
142 // LogFields returns a logrus compatible Fields to identity a single
143 // peer in logs
144 func (p *Peer) LogFields() logrus.Fields {
145         return logrus.Fields{
146                 logPrefixPeer + "addr":        p.Addr,
147                 logPrefixPeer + "id":          p.ID.String(),
148                 logPrefixPeer + "established": p.Established.String(),
149                 logPrefixPeer + "last_ping":   p.LastPing.String(),
150         }
151 }
152
153 // ConfigurationLogFields returns a logrus compatible Fields with the
154 // settings of a single peer. Complement LogFields() for extra debugging
155 // details.
156 func (p *Peer) ConfigurationLogFields() logrus.Fields {
157         return logrus.Fields{
158                 logPrefixPeer + "timeout":  p.Timeout.String(),
159                 logPrefixPeer + "protocol": p.Protocol.String(),
160                 logPrefixPeer + "noise":    p.NoiseEnable,
161                 logPrefixPeer + "cpr":      p.CPR,
162                 logPrefixPeer + "mtu":      p.MTU,
163                 logPrefixPeer + "encless":  p.Encless,
164         }
165 }
166
167 func (p *Peer) String() string {
168         return p.ID.String() + ":" + p.Addr
169 }
170
171 // Zero peer's memory state.
172 func (p *Peer) Zero() {
173         p.BusyT.Lock()
174         p.BusyR.Lock()
175         SliceZero(p.key[:])
176         SliceZero(p.bufR)
177         SliceZero(p.bufT)
178         SliceZero(p.keyAuthR[:])
179         SliceZero(p.keyAuthT[:])
180         p.BusyT.Unlock()
181         p.BusyR.Unlock()
182 }
183
184 func cprCycleCalculate(conf *PeerConf) time.Duration {
185         if conf.CPR == 0 {
186                 return time.Duration(0)
187         }
188         rate := conf.CPR * 1 << 10
189         if conf.Encless {
190                 rate /= EnclessEnlargeSize + conf.MTU
191         } else {
192                 rate /= conf.MTU
193         }
194         return time.Second / time.Duration(rate)
195 }
196
197 func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[SSize]byte) (*Peer, error) {
198         now := time.Now()
199         timeout := conf.Timeout
200
201         cprCycle := cprCycleCalculate(conf)
202         noiseEnable := conf.Noise
203         if conf.CPR > 0 {
204                 noiseEnable = true
205                 timeout = cprCycle
206         } else {
207                 timeout = timeout / timeoutHeartbeat
208         }
209
210         bufSize := CC20IBS + 2*conf.MTU
211         if conf.Encless {
212                 bufSize += EnclessEnlargeSize
213                 noiseEnable = true
214         }
215
216         peer := Peer{
217                 Addr: addr,
218                 ID:   conf.ID,
219                 Conn: conn,
220
221                 NoiseEnable: noiseEnable,
222                 CPR:         conf.CPR,
223                 CPRCycle:    cprCycle,
224                 Encless:     conf.Encless,
225                 MTU:         conf.MTU,
226
227                 key: key,
228
229                 Timeout:     timeout,
230                 Established: now,
231                 LastPing:    now,
232
233                 bufR:     make([]byte, bufSize),
234                 bufT:     make([]byte, bufSize),
235                 tagR:     new([tagSize]byte),
236                 tagT:     new([tagSize]byte),
237                 keyAuthR: new([SSize]byte),
238                 nonceR:   new([16]byte),
239                 keyAuthT: new([SSize]byte),
240                 nonceT:   new([16]byte),
241         }
242
243         var err error
244         if isClient {
245                 if peer.noncesT, err = newNonces(peer.key, 1+2); err != nil {
246                         return nil, err
247                 }
248                 if peer.noncesR, err = newNonces(peer.key, 0+2); err != nil {
249                         return nil, err
250                 }
251                 if peer.noncesExpect, err = newNonces(peer.key, 0+2); err != nil {
252                         return nil, err
253                 }
254         } else {
255                 if peer.noncesT, err = newNonces(peer.key, 0+2); err != nil {
256                         return nil, err
257                 }
258                 if peer.noncesR, err = newNonces(peer.key, 1+2); err != nil {
259                         return nil, err
260                 }
261                 if peer.noncesExpect, err = newNonces(peer.key, 1+2); err != nil {
262                         return nil, err
263                 }
264         }
265
266         peer.NonceExpect = make([]byte, NonceSize)
267         nonce := <-peer.noncesExpect
268         copy(peer.NonceExpect, nonce[:])
269
270         var i int
271         peer.nonceBucketL = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
272         for i = 0; i < nonceBucketSize; i++ {
273                 nonce = <-peer.noncesR
274                 peer.nonceBucketL[*nonce] = struct{}{}
275         }
276         peer.nonceBucketM = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
277         for i = 0; i < nonceBucketSize; i++ {
278                 nonce = <-peer.noncesR
279                 peer.nonceBucketM[*nonce] = struct{}{}
280         }
281         peer.nonceBucketH = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
282         for i = 0; i < nonceBucketSize; i++ {
283                 nonce = <-peer.noncesR
284                 peer.nonceBucketH[*nonce] = struct{}{}
285         }
286
287         return &peer, nil
288 }
289
290 // EthProcess processes incoming Ethernet packet.
291 // ready channel is TAPListen's synchronization channel used to tell him
292 // that he is free to receive new packets. Encrypted and authenticated
293 // packets will be sent to remote Peer side immediately.
294 func (p *Peer) EthProcess(data []byte) error {
295         const paddingSize = 1
296         lenData := len(data)
297         if lenData > p.MTU-paddingSize {
298                 logger.WithFields(p.LogFields()).WithFields(
299                         p.ConfigurationLogFields(),
300                 ).WithFields(
301                         logrus.Fields{
302                                 "func":        logFuncPrefix + "Peer.EthProcess",
303                                 "padding":     paddingSize,
304                                 "packet_size": lenData,
305                         }).Warning("Ignore padded data packet larger than MTU")
306                 return nil
307         }
308         p.BusyT.Lock()
309         defer p.BusyT.Unlock()
310
311         // Zero size is a heartbeat packet
312         SliceZero(p.bufT)
313         if lenData == 0 {
314                 p.bufT[CC20IBS+0] = padByte
315                 p.HeartbeatSent++
316         } else {
317                 // Copy payload to our internal buffer and we are ready to
318                 // accept the next one
319                 copy(p.bufT[CC20IBS:], data)
320                 p.bufT[CC20IBS+lenData] = padByte
321                 p.BytesPayloadOut += uint64(lenData)
322         }
323
324         if p.NoiseEnable && !p.Encless {
325                 p.frameT = p.bufT[CC20IBS : CC20IBS+p.MTU-tagSize]
326         } else if p.Encless {
327                 p.frameT = p.bufT[CC20IBS : CC20IBS+p.MTU]
328         } else {
329                 p.frameT = p.bufT[CC20IBS : CC20IBS+lenData+1+NonceSize]
330         }
331         copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
332         var out []byte
333         copy(p.nonceT[8:], p.frameT[len(p.frameT)-NonceSize:])
334         if p.Encless {
335                 var err error
336                 out, err = EnclessEncode(p.key, p.nonceT, p.frameT[:len(p.frameT)-NonceSize])
337                 if err != nil {
338                         return errors.Wrap(err, wrapEnclessEncode)
339                 }
340                 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
341         } else {
342                 chacha20.XORKeyStream(
343                         p.bufT[:CC20IBS+len(p.frameT)-NonceSize],
344                         p.bufT[:CC20IBS+len(p.frameT)-NonceSize],
345                         p.nonceT,
346                         p.key,
347                 )
348                 copy(p.keyAuthT[:], p.bufT[:SSize])
349                 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
350                 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+tagSize))
351                 out = append(p.tagT[:], p.frameT...)
352         }
353         p.FramesOut++
354         _, err := p.Conn.Write(out)
355         return errors.Wrap(err, "p.Conn.Write")
356 }
357
358 // PktProcess processes data of a single packet
359 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
360         lenData := len(data)
361         fields := logrus.Fields{
362                 "func":        logFuncPrefix + "Peer.PktProcess",
363                 "reorderable": reorderable,
364                 "data":        lenData,
365         }
366         if lenData < MinPktLength {
367                 logger.WithFields(p.LogFields()).WithFields(fields).WithField(
368                         "minimum_packet_Length", MinPktLength,
369                 ).Debug("Ignore packet smaller than allowed minimum")
370                 return false
371         }
372         if !p.Encless && lenData > len(p.bufR)-CC20IBS {
373                 return false
374         }
375         var out []byte
376         p.BusyR.Lock() // TODO use defer to unlock?
377         copy(p.nonceR[8:], data[lenData-NonceSize:])
378         if p.Encless {
379                 var err error
380                 out, err = EnclessDecode(p.key, p.nonceR, data[:lenData-NonceSize])
381                 if err != nil {
382                         logger.WithFields(p.LogFields()).WithError(err).Debug("Failed to decode encless")
383                         p.FramesUnauth++
384                         p.BusyR.Unlock()
385                         return false
386                 }
387         } else {
388                 for i := 0; i < SSize; i++ {
389                         p.bufR[i] = 0
390                 }
391                 copy(p.bufR[CC20IBS:], data[tagSize:])
392                 chacha20.XORKeyStream(
393                         p.bufR[:CC20IBS+lenData-tagSize-NonceSize],
394                         p.bufR[:CC20IBS+lenData-tagSize-NonceSize],
395                         p.nonceR,
396                         p.key,
397                 )
398                 copy(p.keyAuthR[:], p.bufR[:SSize])
399                 copy(p.tagR[:], data[:tagSize])
400                 if !poly1305.Verify(p.tagR, data[tagSize:], p.keyAuthR) {
401                         p.FramesUnauth++
402                         p.BusyR.Unlock()
403                         return false
404                 }
405                 out = p.bufR[CC20IBS : CC20IBS+lenData-tagSize-NonceSize]
406         }
407
408         if reorderable {
409                 copy(p.nonceRecv[:], data[lenData-NonceSize:])
410                 _, foundL := p.nonceBucketL[p.nonceRecv]
411                 _, foundM := p.nonceBucketM[p.nonceRecv]
412                 _, foundH := p.nonceBucketH[p.nonceRecv]
413                 // If found is none of buckets: either it is too old,
414                 // or too new (many packets were lost)
415                 if !(foundL || foundM || foundH) {
416                         p.FramesDup++
417                         p.BusyR.Unlock()
418                         return false
419                 }
420                 // Delete seen nonce
421                 if foundL {
422                         delete(p.nonceBucketL, p.nonceRecv)
423                 }
424                 if foundM {
425                         delete(p.nonceBucketM, p.nonceRecv)
426                 }
427                 if foundH {
428                         delete(p.nonceBucketH, p.nonceRecv)
429                 }
430                 // If we are dealing with the latest bucket, create the new one
431                 if foundH {
432                         p.nonceBucketL, p.nonceBucketM = p.nonceBucketM, p.nonceBucketH
433                         p.nonceBucketH = make(map[[NonceSize]byte]struct{})
434                         var nonce *[NonceSize]byte
435                         for i := 0; i < nonceBucketSize; i++ {
436                                 nonce = <-p.noncesR
437                                 p.nonceBucketH[*nonce] = struct{}{}
438                         }
439                 }
440         } else {
441                 if subtle.ConstantTimeCompare(data[lenData-NonceSize:], p.NonceExpect) != 1 {
442                         p.FramesDup++
443                         p.BusyR.Unlock()
444                         return false
445                 }
446                 copy(p.NonceExpect, (<-p.noncesExpect)[:])
447         }
448
449         p.FramesIn++
450         atomic.AddUint64(&p.BytesIn, uint64(lenData))
451         p.LastPing = time.Now()
452         p.pktSizeR = bytes.LastIndexByte(out, padByte)
453         if p.pktSizeR == -1 {
454                 p.BusyR.Unlock()
455                 return false
456         }
457         // Validate the pad
458         for i := p.pktSizeR + 1; i < len(out); i++ {
459                 if out[i] != 0 {
460                         p.BusyR.Unlock()
461                         return false
462                 }
463         }
464
465         if p.pktSizeR == 0 {
466                 p.HeartbeatRecv++
467                 p.BusyR.Unlock()
468                 return true
469         }
470         p.BytesPayloadIn += uint64(p.pktSizeR)
471         tap.Write(out[:p.pktSizeR])
472         p.BusyR.Unlock()
473         return true
474 }
475
476 // PeerTapProcessor processes a TUN/TAP peer
477 func PeerTapProcessor(peer *Peer, tap *TAP, terminator chan struct{}) {
478         var data []byte
479         var now time.Time
480         var err error
481         fields := logrus.Fields{
482                 "func": logFuncPrefix + "PeerTapProcessor",
483                 "tap":  tap.Name,
484         }
485         lastSent := time.Now()
486         heartbeat := time.NewTicker(peer.Timeout)
487         if peer.CPRCycle == time.Duration(0) {
488         RawProcessor:
489                 for {
490                         select {
491                         case <-terminator:
492                                 break RawProcessor
493                         case <-heartbeat.C:
494                                 now = time.Now()
495                                 if lastSent.Add(peer.Timeout).Before(now) {
496                                         if err = peer.EthProcess(nil); err != nil {
497                                                 logger.WithFields(
498                                                         fields,
499                                                 ).WithFields(
500                                                         peer.LogFields(),
501                                                 ).WithError(err).Warn(
502                                                         "Can't process nil ethernet packet",
503                                                 )
504                                         }
505                                         lastSent = now
506                                 }
507                         case data = <-tap.Sink:
508                                 if err = peer.EthProcess(data); err != nil {
509                                         logger.WithFields(fields).WithFields(
510                                                 peer.LogFields(),
511                                         ).WithError(err).Warn("Can't process ethernet packet")
512                                 }
513                                 lastSent = time.Now()
514                         }
515                 }
516         } else {
517         CPRProcessor:
518                 for {
519                         data = nil
520                         select {
521                         case <-terminator:
522                                 break CPRProcessor
523                         case data = <-tap.Sink:
524                                 if err = peer.EthProcess(data); err != nil {
525                                         logger.WithFields(fields).WithFields(
526                                                 peer.LogFields(),
527                                         ).WithError(err).Warn("Can't process ethernet packet")
528                                 }
529                         default:
530                         }
531                         if data == nil {
532                                 if err = peer.EthProcess(nil); err != nil {
533                                         logger.WithFields(fields).WithFields(
534                                                 peer.LogFields(),
535                                         ).WithError(err).Warn("Can't process nil ethernet packet")
536                                 }
537                         }
538                         time.Sleep(peer.CPRCycle)
539                 }
540         }
541         close(terminator)
542         peer.Zero()
543         heartbeat.Stop()
544 }