]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/peer.go
24f694557844216cc5610c87978b069dc0a75f27
[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         chacha20InternalBlockSize = 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 := chacha20InternalBlockSize + 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(p.ConfigurationLogFields()).WithFields(
299                         logrus.Fields{
300                                 "func":        logFuncPrefix + "Peer.EthProcess",
301                                 "padding":     paddingSize,
302                                 "packet_size": lenData,
303                         }).Warning("Ignore padded data packet larger than MTU")
304                 return nil
305         }
306         p.BusyT.Lock()
307         defer p.BusyT.Unlock()
308
309         // Zero size is a heartbeat packet
310         SliceZero(p.bufT)
311         if lenData == 0 {
312                 p.bufT[chacha20InternalBlockSize+0] = padByte
313                 p.HeartbeatSent++
314         } else {
315                 // Copy payload to our internal buffer and we are ready to
316                 // accept the next one
317                 copy(p.bufT[chacha20InternalBlockSize:], data)
318                 p.bufT[chacha20InternalBlockSize+lenData] = padByte
319                 p.BytesPayloadOut += uint64(lenData)
320         }
321
322         if p.NoiseEnable && !p.Encless {
323                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU-tagSize]
324         } else if p.Encless {
325                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU]
326         } else {
327                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData+1+NonceSize]
328         }
329         copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
330         var out []byte
331         copy(p.nonceT[8:], p.frameT[len(p.frameT)-NonceSize:])
332         if p.Encless {
333                 var err error
334                 out, err = EnclessEncode(p.key, p.nonceT, p.frameT[:len(p.frameT)-NonceSize])
335                 if err != nil {
336                         return errors.Wrap(err, wrapEnclessEncode)
337                 }
338                 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
339         } else {
340                 chacha20.XORKeyStream(
341                         p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
342                         p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
343                         p.nonceT,
344                         p.key,
345                 )
346                 copy(p.keyAuthT[:], p.bufT[:SSize])
347                 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
348                 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+tagSize))
349                 out = append(p.tagT[:], p.frameT...)
350         }
351         p.FramesOut++
352         _, err := p.Conn.Write(out)
353         return errors.Wrap(err, "p.Conn.Write")
354 }
355
356 // PktProcess processes data of a single packet
357 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
358         lenData := len(data)
359         fields := logrus.Fields{
360                 "func":        logFuncPrefix + "Peer.PktProcess",
361                 "reorderable": reorderable,
362                 "data":        lenData,
363         }
364         if lenData < MinPktLength {
365                 logger.WithFields(p.LogFields()).WithFields(fields).WithField("minimum_packet_Length", MinPktLength).Debug("Ignore packet smaller than allowed minimum")
366                 return false
367         }
368         if !p.Encless && lenData > len(p.bufR)-chacha20InternalBlockSize {
369                 return false
370         }
371         var out []byte
372         p.BusyR.Lock() // TODO use defer to unlock?
373         copy(p.nonceR[8:], data[lenData-NonceSize:])
374         if p.Encless {
375                 var err error
376                 out, err = EnclessDecode(p.key, p.nonceR, data[:lenData-NonceSize])
377                 if err != nil {
378                         logger.WithFields(p.LogFields()).WithError(err).Debug("Failed to decode encless")
379                         p.FramesUnauth++
380                         p.BusyR.Unlock()
381                         return false
382                 }
383         } else {
384                 for i := 0; i < SSize; i++ {
385                         p.bufR[i] = 0
386                 }
387                 copy(p.bufR[chacha20InternalBlockSize:], data[tagSize:])
388                 chacha20.XORKeyStream(
389                         p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
390                         p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
391                         p.nonceR,
392                         p.key,
393                 )
394                 copy(p.keyAuthR[:], p.bufR[:SSize])
395                 copy(p.tagR[:], data[:tagSize])
396                 if !poly1305.Verify(p.tagR, data[tagSize:], p.keyAuthR) {
397                         p.FramesUnauth++
398                         p.BusyR.Unlock()
399                         return false
400                 }
401                 out = p.bufR[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData-tagSize-NonceSize]
402         }
403
404         if reorderable {
405                 copy(p.nonceRecv[:], data[lenData-NonceSize:])
406                 _, foundL := p.nonceBucketL[p.nonceRecv]
407                 _, foundM := p.nonceBucketM[p.nonceRecv]
408                 _, foundH := p.nonceBucketH[p.nonceRecv]
409                 // If found is none of buckets: either it is too old,
410                 // or too new (many packets were lost)
411                 if !(foundL || foundM || foundH) {
412                         p.FramesDup++
413                         p.BusyR.Unlock()
414                         return false
415                 }
416                 // Delete seen nonce
417                 if foundL {
418                         delete(p.nonceBucketL, p.nonceRecv)
419                 }
420                 if foundM {
421                         delete(p.nonceBucketM, p.nonceRecv)
422                 }
423                 if foundH {
424                         delete(p.nonceBucketH, p.nonceRecv)
425                 }
426                 // If we are dealing with the latest bucket, create the new one
427                 if foundH {
428                         p.nonceBucketL, p.nonceBucketM = p.nonceBucketM, p.nonceBucketH
429                         p.nonceBucketH = make(map[[NonceSize]byte]struct{})
430                         var nonce *[NonceSize]byte
431                         for i := 0; i < nonceBucketSize; i++ {
432                                 nonce = <-p.noncesR
433                                 p.nonceBucketH[*nonce] = struct{}{}
434                         }
435                 }
436         } else {
437                 if subtle.ConstantTimeCompare(data[lenData-NonceSize:], p.NonceExpect) != 1 {
438                         p.FramesDup++
439                         p.BusyR.Unlock()
440                         return false
441                 }
442                 copy(p.NonceExpect, (<-p.noncesExpect)[:])
443         }
444
445         p.FramesIn++
446         atomic.AddUint64(&p.BytesIn, uint64(lenData))
447         p.LastPing = time.Now()
448         p.pktSizeR = bytes.LastIndexByte(out, padByte)
449         if p.pktSizeR == -1 {
450                 p.BusyR.Unlock()
451                 return false
452         }
453         // Validate the pad
454         for i := p.pktSizeR + 1; i < len(out); i++ {
455                 if out[i] != 0 {
456                         p.BusyR.Unlock()
457                         return false
458                 }
459         }
460
461         if p.pktSizeR == 0 {
462                 p.HeartbeatRecv++
463                 p.BusyR.Unlock()
464                 return true
465         }
466         p.BytesPayloadIn += uint64(p.pktSizeR)
467         tap.Write(out[:p.pktSizeR])
468         p.BusyR.Unlock()
469         return true
470 }
471
472 // PeerTapProcessor processes a TUN/TAP peer
473 func PeerTapProcessor(peer *Peer, tap *TAP, terminator chan struct{}) {
474         var data []byte
475         var now time.Time
476         var err error
477         fields := logrus.Fields{
478                 "func": logFuncPrefix + "PeerTapProcessor",
479                 "tap":  tap.Name,
480         }
481         lastSent := time.Now()
482         heartbeat := time.NewTicker(peer.Timeout)
483         if peer.CPRCycle == time.Duration(0) {
484         RawProcessor:
485                 for {
486                         select {
487                         case <-terminator:
488                                 break RawProcessor
489                         case <-heartbeat.C:
490                                 now = time.Now()
491                                 if lastSent.Add(peer.Timeout).Before(now) {
492                                         if err = peer.EthProcess(nil); err != nil {
493                                                 logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
494                                         }
495                                         lastSent = now
496                                 }
497                         case data = <-tap.Sink:
498                                 if err = peer.EthProcess(data); err != nil {
499                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
500                                 }
501                                 lastSent = time.Now()
502                         }
503                 }
504         } else {
505         CPRProcessor:
506                 for {
507                         data = nil
508                         select {
509                         case <-terminator:
510                                 break CPRProcessor
511                         case data = <-tap.Sink:
512                                 if err = peer.EthProcess(data); err != nil {
513                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
514                                 }
515                         default:
516                         }
517                         if data == nil {
518                                 if err = peer.EthProcess(nil); err != nil {
519                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
520                                 }
521                         }
522                         time.Sleep(peer.CPRCycle)
523                 }
524         }
525         close(terminator)
526         peer.Zero()
527         heartbeat.Stop()
528 }