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