]> Cypherpunks.ru repositories - govpn.git/blob - src/cypherpunks.ru/govpn/peer.go
54bef040ea1cece2d9f65a4a5acf24a0b6171fb1
[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 return a logrus compatible Fields to identity a single peer in logs
143 func (p *Peer) LogFields() logrus.Fields {
144         return logrus.Fields{
145                 logPrefixPeer + "addr":        p.Addr,
146                 logPrefixPeer + "id":          p.ID.String(),
147                 logPrefixPeer + "established": p.Established.String(),
148                 logPrefixPeer + "last_ping":   p.LastPing.String(),
149         }
150 }
151
152 // ConfigurationLogFields return a logrus compatible Fields with the settings of
153 // a single peer. Complement LogFields() for extra debugging details.
154 func (p *Peer) ConfigurationLogFields() logrus.Fields {
155         return logrus.Fields{
156                 logPrefixPeer + "timeout":  p.Timeout.String(),
157                 logPrefixPeer + "protocol": p.Protocol.String(),
158                 logPrefixPeer + "noise":    p.NoiseEnable,
159                 logPrefixPeer + "cpr":      p.CPR,
160                 logPrefixPeer + "mtu":      p.MTU,
161                 logPrefixPeer + "encless":  p.Encless,
162         }
163 }
164
165 func (p *Peer) String() string {
166         return p.ID.String() + ":" + p.Addr
167 }
168
169 // Zero peer's memory state.
170 func (p *Peer) Zero() {
171         p.BusyT.Lock()
172         p.BusyR.Lock()
173         SliceZero(p.key[:])
174         SliceZero(p.bufR)
175         SliceZero(p.bufT)
176         SliceZero(p.keyAuthR[:])
177         SliceZero(p.keyAuthT[:])
178         p.BusyT.Unlock()
179         p.BusyR.Unlock()
180 }
181
182 func cprCycleCalculate(conf *PeerConf) time.Duration {
183         if conf.CPR == 0 {
184                 return time.Duration(0)
185         }
186         rate := conf.CPR * 1 << 10
187         if conf.Encless {
188                 rate /= EnclessEnlargeSize + conf.MTU
189         } else {
190                 rate /= conf.MTU
191         }
192         return time.Second / time.Duration(rate)
193 }
194
195 func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[SSize]byte) (*Peer, error) {
196         now := time.Now()
197         timeout := conf.Timeout
198
199         cprCycle := cprCycleCalculate(conf)
200         noiseEnable := conf.Noise
201         if conf.CPR > 0 {
202                 noiseEnable = true
203                 timeout = cprCycle
204         } else {
205                 timeout = timeout / timeoutHeartbeat
206         }
207
208         bufSize := chacha20InternalBlockSize + 2*conf.MTU
209         if conf.Encless {
210                 bufSize += EnclessEnlargeSize
211                 noiseEnable = true
212         }
213
214         peer := Peer{
215                 Addr: addr,
216                 ID:   conf.ID,
217                 Conn: conn,
218
219                 NoiseEnable: noiseEnable,
220                 CPR:         conf.CPR,
221                 CPRCycle:    cprCycle,
222                 Encless:     conf.Encless,
223                 MTU:         conf.MTU,
224
225                 key: key,
226
227                 Timeout:     timeout,
228                 Established: now,
229                 LastPing:    now,
230
231                 bufR:     make([]byte, bufSize),
232                 bufT:     make([]byte, bufSize),
233                 tagR:     new([tagSize]byte),
234                 tagT:     new([tagSize]byte),
235                 keyAuthR: new([SSize]byte),
236                 nonceR:   new([16]byte),
237                 keyAuthT: new([SSize]byte),
238                 nonceT:   new([16]byte),
239         }
240
241         var err error
242         if isClient {
243                 if peer.noncesT, err = newNonces(peer.key, 1+2); err != nil {
244                         return nil, err
245                 }
246                 if peer.noncesR, err = newNonces(peer.key, 0+2); err != nil {
247                         return nil, err
248                 }
249                 if peer.noncesExpect, err = newNonces(peer.key, 0+2); err != nil {
250                         return nil, err
251                 }
252         } else {
253                 if peer.noncesT, err = newNonces(peer.key, 0+2); err != nil {
254                         return nil, err
255                 }
256                 if peer.noncesR, err = newNonces(peer.key, 1+2); err != nil {
257                         return nil, err
258                 }
259                 if peer.noncesExpect, err = newNonces(peer.key, 1+2); err != nil {
260                         return nil, err
261                 }
262         }
263
264         peer.NonceExpect = make([]byte, NonceSize)
265         nonce := <-peer.noncesExpect
266         copy(peer.NonceExpect, nonce[:])
267
268         var i int
269         peer.nonceBucketL = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
270         for i = 0; i < nonceBucketSize; i++ {
271                 nonce = <-peer.noncesR
272                 peer.nonceBucketL[*nonce] = struct{}{}
273         }
274         peer.nonceBucketM = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
275         for i = 0; i < nonceBucketSize; i++ {
276                 nonce = <-peer.noncesR
277                 peer.nonceBucketM[*nonce] = struct{}{}
278         }
279         peer.nonceBucketH = make(map[[NonceSize]byte]struct{}, nonceBucketSize)
280         for i = 0; i < nonceBucketSize; i++ {
281                 nonce = <-peer.noncesR
282                 peer.nonceBucketH[*nonce] = struct{}{}
283         }
284
285         return &peer, nil
286 }
287
288 // EthProcess processes incoming Ethernet packet.
289 // ready channel is TAPListen's synchronization channel used to tell him
290 // that he is free to receive new packets. Encrypted and authenticated
291 // packets will be sent to remote Peer side immediately.
292 func (p *Peer) EthProcess(data []byte) error {
293         const paddingSize = 1
294         lenData := len(data)
295         if lenData > p.MTU-paddingSize {
296                 logger.WithFields(p.LogFields()).WithFields(p.ConfigurationLogFields()).WithFields(
297                         logrus.Fields{
298                                 "func":        logFuncPrefix + "Peer.EthProcess",
299                                 "padding":     paddingSize,
300                                 "packet_size": lenData,
301                         }).Warning("Ignore padded data packet larger than MTU")
302                 return nil
303         }
304         p.BusyT.Lock()
305         defer p.BusyT.Unlock()
306
307         // Zero size is a heartbeat packet
308         SliceZero(p.bufT)
309         if lenData == 0 {
310                 p.bufT[chacha20InternalBlockSize+0] = padByte
311                 p.HeartbeatSent++
312         } else {
313                 // Copy payload to our internal buffer and we are ready to
314                 // accept the next one
315                 copy(p.bufT[chacha20InternalBlockSize:], data)
316                 p.bufT[chacha20InternalBlockSize+lenData] = padByte
317                 p.BytesPayloadOut += uint64(lenData)
318         }
319
320         if p.NoiseEnable && !p.Encless {
321                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU-tagSize]
322         } else if p.Encless {
323                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU]
324         } else {
325                 p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData+1+NonceSize]
326         }
327         copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
328         var out []byte
329         copy(p.nonceT[8:], p.frameT[len(p.frameT)-NonceSize:])
330         if p.Encless {
331                 var err error
332                 out, err = EnclessEncode(p.key, p.nonceT, p.frameT[:len(p.frameT)-NonceSize])
333                 if err != nil {
334                         return errors.Wrap(err, wrapEnclessEncode)
335                 }
336                 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
337         } else {
338                 chacha20.XORKeyStream(
339                         p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
340                         p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
341                         p.nonceT,
342                         p.key,
343                 )
344                 copy(p.keyAuthT[:], p.bufT[:SSize])
345                 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
346                 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+tagSize))
347                 out = append(p.tagT[:], p.frameT...)
348         }
349         p.FramesOut++
350         _, err := p.Conn.Write(out)
351         return errors.Wrap(err, "p.Conn.Write")
352 }
353
354 // PktProcess processes data of a single packet
355 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
356         lenData := len(data)
357         fields := logrus.Fields{
358                 "func":        logFuncPrefix + "Peer.PktProcess",
359                 "reorderable": reorderable,
360                 "data":        lenData,
361         }
362         if lenData < MinPktLength {
363                 logger.WithFields(p.LogFields()).WithFields(fields).WithField("minimum_packet_Length", MinPktLength).Debug("Ignore packet smaller than allowed minimum")
364                 return false
365         }
366         if !p.Encless && lenData > len(p.bufR)-chacha20InternalBlockSize {
367                 return false
368         }
369         var out []byte
370         p.BusyR.Lock() // TODO use defer to unlock?
371         copy(p.nonceR[8:], data[lenData-NonceSize:])
372         if p.Encless {
373                 var err error
374                 out, err = EnclessDecode(p.key, p.nonceR, data[:lenData-NonceSize])
375                 if err != nil {
376                         logger.WithFields(p.LogFields()).WithError(err).Debug("Failed to decode encless")
377                         p.FramesUnauth++
378                         p.BusyR.Unlock()
379                         return false
380                 }
381         } else {
382                 for i := 0; i < SSize; i++ {
383                         p.bufR[i] = 0
384                 }
385                 copy(p.bufR[chacha20InternalBlockSize:], data[tagSize:])
386                 chacha20.XORKeyStream(
387                         p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
388                         p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
389                         p.nonceR,
390                         p.key,
391                 )
392                 copy(p.keyAuthR[:], p.bufR[:SSize])
393                 copy(p.tagR[:], data[:tagSize])
394                 if !poly1305.Verify(p.tagR, data[tagSize:], p.keyAuthR) {
395                         p.FramesUnauth++
396                         p.BusyR.Unlock()
397                         return false
398                 }
399                 out = p.bufR[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData-tagSize-NonceSize]
400         }
401
402         if reorderable {
403                 copy(p.nonceRecv[:], data[lenData-NonceSize:])
404                 _, foundL := p.nonceBucketL[p.nonceRecv]
405                 _, foundM := p.nonceBucketM[p.nonceRecv]
406                 _, foundH := p.nonceBucketH[p.nonceRecv]
407                 // If found is none of buckets: either it is too old,
408                 // or too new (many packets were lost)
409                 if !(foundL || foundM || foundH) {
410                         p.FramesDup++
411                         p.BusyR.Unlock()
412                         return false
413                 }
414                 // Delete seen nonce
415                 if foundL {
416                         delete(p.nonceBucketL, p.nonceRecv)
417                 }
418                 if foundM {
419                         delete(p.nonceBucketM, p.nonceRecv)
420                 }
421                 if foundH {
422                         delete(p.nonceBucketH, p.nonceRecv)
423                 }
424                 // If we are dealing with the latest bucket, create the new one
425                 if foundH {
426                         p.nonceBucketL, p.nonceBucketM = p.nonceBucketM, p.nonceBucketH
427                         p.nonceBucketH = make(map[[NonceSize]byte]struct{})
428                         var nonce *[NonceSize]byte
429                         for i := 0; i < nonceBucketSize; i++ {
430                                 nonce = <-p.noncesR
431                                 p.nonceBucketH[*nonce] = struct{}{}
432                         }
433                 }
434         } else {
435                 if subtle.ConstantTimeCompare(data[lenData-NonceSize:], p.NonceExpect) != 1 {
436                         p.FramesDup++
437                         p.BusyR.Unlock()
438                         return false
439                 }
440                 copy(p.NonceExpect, (<-p.noncesExpect)[:])
441         }
442
443         p.FramesIn++
444         atomic.AddUint64(&p.BytesIn, uint64(lenData))
445         p.LastPing = time.Now()
446         p.pktSizeR = bytes.LastIndexByte(out, padByte)
447         if p.pktSizeR == -1 {
448                 p.BusyR.Unlock()
449                 return false
450         }
451         // Validate the pad
452         for i := p.pktSizeR + 1; i < len(out); i++ {
453                 if out[i] != 0 {
454                         p.BusyR.Unlock()
455                         return false
456                 }
457         }
458
459         if p.pktSizeR == 0 {
460                 p.HeartbeatRecv++
461                 p.BusyR.Unlock()
462                 return true
463         }
464         p.BytesPayloadIn += uint64(p.pktSizeR)
465         tap.Write(out[:p.pktSizeR])
466         p.BusyR.Unlock()
467         return true
468 }
469
470 // PeerTapProcessor processes a TUN/TAP peer
471 func PeerTapProcessor(peer *Peer, tap *TAP, terminator chan struct{}) {
472         var data []byte
473         var now time.Time
474         var err error
475         fields := logrus.Fields{
476                 "func": logFuncPrefix + "PeerTapProcessor",
477                 "tap":  tap.Name,
478         }
479         lastSent := time.Now()
480         heartbeat := time.NewTicker(peer.Timeout)
481         if peer.CPRCycle == time.Duration(0) {
482         RawProcessor:
483                 for {
484                         select {
485                         case <-terminator:
486                                 break RawProcessor
487                         case <-heartbeat.C:
488                                 now = time.Now()
489                                 if lastSent.Add(peer.Timeout).Before(now) {
490                                         if err = peer.EthProcess(nil); err != nil {
491                                                 logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
492                                         }
493                                         lastSent = now
494                                 }
495                         case data = <-tap.Sink:
496                                 if err = peer.EthProcess(data); err != nil {
497                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
498                                 }
499                                 lastSent = time.Now()
500                         }
501                 }
502         } else {
503         CPRProcessor:
504                 for {
505                         data = nil
506                         select {
507                         case <-terminator:
508                                 break CPRProcessor
509                         case data = <-tap.Sink:
510                                 if err = peer.EthProcess(data); err != nil {
511                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
512                                 }
513                         default:
514                         }
515                         if data == nil {
516                                 if err = peer.EthProcess(nil); err != nil {
517                                         logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
518                                 }
519                         }
520                         time.Sleep(peer.CPRCycle)
521                 }
522         }
523         close(terminator)
524         peer.Zero()
525         heartbeat.Stop()
526 }