]> Cypherpunks.ru repositories - govpn.git/blob - src/govpn/transport.go
Replace -noncediff with the hash keeping up to 256 seen nonces
[govpn.git] / src / govpn / transport.go
1 /*
2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2015 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         "encoding/binary"
23         "io"
24         "net"
25         "time"
26
27         "golang.org/x/crypto/poly1305"
28         "golang.org/x/crypto/salsa20"
29         "golang.org/x/crypto/xtea"
30 )
31
32 const (
33         NonceSize       = 8
34         NonceBucketSize = 128
35         // S20BS is Salsa20's internal blocksize in bytes
36         S20BS = 64
37         // Maximal amount of bytes transfered with single key (4 GiB)
38         MaxBytesPerKey int64 = 1 << 32
39         // Size of packet's size mark in bytes
40         PktSizeSize = 2
41         // Heartbeat rate, relative to Timeout
42         TimeoutHeartbeat = 4
43 )
44
45 type UDPPkt struct {
46         Addr *net.UDPAddr
47         Size int
48 }
49
50 type Peer struct {
51         Addr *net.UDPAddr
52         Id   *PeerId
53
54         // Traffic behaviour
55         NoiseEnable bool
56         CPR         int
57         CPRCycle    time.Duration `json:"-"`
58
59         // Cryptography related
60         Key          *[SSize]byte `json:"-"`
61         NonceOur     uint64       `json:"-"`
62         NonceRecv    uint64       `json:"-"`
63         NonceCipher  *xtea.Cipher `json:"-"`
64         nonceBucket0 map[uint64]struct{}
65         nonceBucket1 map[uint64]struct{}
66         nonceFound   bool
67         nonceBucketN int32
68
69         // Timers
70         Timeout       time.Duration `json:"-"`
71         Established   time.Time
72         LastPing      time.Time
73         LastSent      time.Time
74         willSentCycle time.Time
75
76         // This variables are initialized only once to relief GC
77         buf       []byte
78         tag       *[poly1305.TagSize]byte
79         keyAuth   *[32]byte
80         nonceRecv uint64
81         frame     []byte
82         nonce     []byte
83         pktSize   uint64
84         size      int
85         now       time.Time
86
87         // Statistics
88         BytesIn         int64
89         BytesOut        int64
90         BytesPayloadIn  int64
91         BytesPayloadOut int64
92         FramesIn        int
93         FramesOut       int
94         FramesUnauth    int
95         FramesDup       int
96         HeartbeatRecv   int
97         HeartbeatSent   int
98 }
99
100 func (p *Peer) String() string {
101         return p.Id.String() + ":" + p.Addr.String()
102 }
103
104 // Zero peer's memory state.
105 func (p *Peer) Zero() {
106         sliceZero(p.Key[:])
107         sliceZero(p.tag[:])
108         sliceZero(p.keyAuth[:])
109         sliceZero(p.buf)
110         sliceZero(p.frame)
111         sliceZero(p.nonce)
112 }
113
114 var (
115         Emptiness = make([]byte, 1<<14)
116         taps      = make(map[string]*TAP)
117 )
118
119 // Create TAP listening goroutine.
120 // This function takes required TAP interface name, opens it and allocates
121 // a buffer where all frame data will be written, channel where information
122 // about number of read bytes is sent to, synchronization channel (external
123 // processes tell that read buffer can be used again) and possible channel
124 // opening error.
125 func TAPListen(ifaceName string, timeout time.Duration, cpr int) (*TAP, chan []byte, chan struct{}, chan struct{}, error) {
126         var tap *TAP
127         var err error
128         tap, exists := taps[ifaceName]
129         if !exists {
130                 tap, err = NewTAP(ifaceName)
131                 if err != nil {
132                         return nil, nil, nil, nil, err
133                 }
134                 taps[ifaceName] = tap
135         }
136         sink := make(chan []byte)
137         sinkReady := make(chan struct{})
138         sinkTerminate := make(chan struct{})
139         sinkSkip := make(chan struct{})
140
141         go func() {
142                 cprCycle := cprCycleCalculate(cpr)
143                 if cprCycle != time.Duration(0) {
144                         timeout = cprCycle
145                 } else {
146                         timeout = timeout / TimeoutHeartbeat
147                 }
148                 heartbeat := time.Tick(timeout)
149                 var pkt []byte
150         ListenCycle:
151                 for {
152                         select {
153                         case <-sinkTerminate:
154                                 break ListenCycle
155                         case <-heartbeat:
156                                 go func() { sink <- make([]byte, 0) }()
157                                 continue
158                         case <-sinkSkip:
159                         case <-sinkReady:
160                                 tap.ready <- struct{}{}
161                                 tap.synced = true
162                         }
163                 HeartbeatCatched:
164                         select {
165                         case <-heartbeat:
166                                 go func() { sink <- make([]byte, 0) }()
167                                 goto HeartbeatCatched
168                         case <-sinkTerminate:
169                                 break ListenCycle
170                         case pkt = <-tap.sink:
171                                 tap.synced = false
172                                 sink <- pkt
173                         }
174                 }
175                 close(sink)
176                 close(sinkReady)
177                 close(sinkTerminate)
178         }()
179         if exists && tap.synced {
180                 sinkSkip <- struct{}{}
181         } else {
182                 sinkReady <- struct{}{}
183         }
184         return tap, sink, sinkReady, sinkTerminate, nil
185 }
186
187 // Create UDP listening goroutine.
188 // This function takes already listening UDP socket and a buffer where
189 // all UDP packet data will be saved, channel where information about
190 // remote address and number of written bytes are stored, and a channel
191 // used to tell that buffer is ready to be overwritten.
192 func ConnListen(conn *net.UDPConn) (chan UDPPkt, []byte, chan struct{}) {
193         buf := make([]byte, MTU)
194         sink := make(chan UDPPkt)
195         sinkReady := make(chan struct{})
196         go func(conn *net.UDPConn) {
197                 var n int
198                 var addr *net.UDPAddr
199                 var err error
200                 for {
201                         <-sinkReady
202                         conn.SetReadDeadline(time.Now().Add(time.Second))
203                         n, addr, err = conn.ReadFromUDP(buf)
204                         if err != nil {
205                                 // This is needed for ticking the timeouts counter outside
206                                 sink <- UDPPkt{nil, 0}
207                                 continue
208                         }
209                         sink <- UDPPkt{addr, n}
210                 }
211         }(conn)
212         sinkReady <- struct{}{}
213         return sink, buf, sinkReady
214 }
215
216 func newNonceCipher(key *[32]byte) *xtea.Cipher {
217         nonceKey := make([]byte, 16)
218         salsa20.XORKeyStream(
219                 nonceKey,
220                 make([]byte, 32),
221                 make([]byte, xtea.BlockSize),
222                 key,
223         )
224         ciph, err := xtea.NewCipher(nonceKey)
225         if err != nil {
226                 panic(err)
227         }
228         return ciph
229 }
230
231 func cprCycleCalculate(rate int) time.Duration {
232         if rate == 0 {
233                 return time.Duration(0)
234         }
235         return time.Second / time.Duration(rate*(1<<10)/MTU)
236 }
237
238 func newPeer(addr *net.UDPAddr, conf *PeerConf, nonce int, key *[SSize]byte) *Peer {
239         now := time.Now()
240         timeout := conf.Timeout
241         cprCycle := cprCycleCalculate(conf.CPR)
242         noiseEnable := conf.NoiseEnable
243         if conf.CPR > 0 {
244                 noiseEnable = true
245                 timeout = cprCycle
246         } else {
247                 timeout = timeout / TimeoutHeartbeat
248         }
249         peer := Peer{
250                 Addr:         addr,
251                 Timeout:      timeout,
252                 Established:  now,
253                 LastPing:     now,
254                 Id:           conf.Id,
255                 NoiseEnable:  noiseEnable,
256                 CPR:          conf.CPR,
257                 CPRCycle:     cprCycle,
258                 NonceOur:     uint64(nonce),
259                 NonceRecv:    uint64(0),
260                 nonceBucket0: make(map[uint64]struct{}, NonceBucketSize),
261                 nonceBucket1: make(map[uint64]struct{}, NonceBucketSize),
262                 Key:          key,
263                 NonceCipher:  newNonceCipher(key),
264                 buf:          make([]byte, MTU+S20BS),
265                 tag:          new([poly1305.TagSize]byte),
266                 keyAuth:      new([SSize]byte),
267                 nonce:        make([]byte, NonceSize),
268         }
269         return &peer
270 }
271
272 // Process incoming UDP packet.
273 // udpPkt is received data, related to the peer tap interface and
274 // ConnListen'es synchronization channel used to tell him that he is
275 // free to receive new packets. Authenticated and decrypted packets
276 // will be written to the interface immediately (except heartbeat ones).
277 func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
278         p.size = len(udpPkt)
279         copy(p.buf, Emptiness)
280         copy(p.tag[:], udpPkt[p.size-poly1305.TagSize:])
281         copy(p.buf[S20BS:], udpPkt[NonceSize:p.size-poly1305.TagSize])
282         salsa20.XORKeyStream(
283                 p.buf[:S20BS+p.size-poly1305.TagSize],
284                 p.buf[:S20BS+p.size-poly1305.TagSize],
285                 udpPkt[:NonceSize],
286                 p.Key,
287         )
288         copy(p.keyAuth[:], p.buf[:SSize])
289         if !poly1305.Verify(p.tag, udpPkt[:p.size-poly1305.TagSize], p.keyAuth) {
290                 ready <- struct{}{}
291                 p.FramesUnauth++
292                 return false
293         }
294
295         // Check if received nonce is known to us in either of two buckets.
296         // If yes, then this is ignored duplicate.
297         // Check from the oldest bucket, as in most cases this will result
298         // in constant time check.
299         // If Bucket0 is filled, then it becomes Bucket1.
300         p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
301         ready <- struct{}{}
302         p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
303         if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
304                 p.FramesDup++
305                 return false
306         }
307         if _, p.nonceFound = p.nonceBucket0[p.NonceRecv]; p.nonceFound {
308                 p.FramesDup++
309                 return false
310         }
311         p.nonceBucket0[p.NonceRecv] = struct{}{}
312         p.nonceBucketN++
313         if p.nonceBucketN == NonceBucketSize {
314                 p.nonceBucket1 = p.nonceBucket0
315                 p.nonceBucket0 = make(map[uint64]struct{}, NonceBucketSize)
316                 p.nonceBucketN = 0
317         }
318
319         p.FramesIn++
320         p.BytesIn += int64(p.size)
321         p.LastPing = time.Now()
322         p.NonceRecv = p.nonceRecv
323         p.pktSize, _ = binary.Uvarint(p.buf[S20BS : S20BS+PktSizeSize])
324         if p.pktSize == 0 {
325                 p.HeartbeatRecv++
326                 return true
327         }
328         p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
329         p.BytesPayloadIn += int64(p.pktSize)
330         tap.Write(p.frame)
331         return true
332 }
333
334 type WriteToUDPer interface {
335         WriteToUDP([]byte, *net.UDPAddr) (int, error)
336 }
337
338 // Process incoming Ethernet packet.
339 // ethPkt is received data, conn is our outgoing connection.
340 // ready channel is TAPListen's synchronization channel used to tell him
341 // that he is free to receive new packets. Encrypted and authenticated
342 // packets will be sent to remote Peer side immediately.
343 func (p *Peer) EthProcess(ethPkt []byte, conn WriteToUDPer, ready chan struct{}) {
344         p.now = time.Now()
345         p.size = len(ethPkt)
346         // If this heartbeat is necessary
347         if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
348                 return
349         }
350         copy(p.buf, Emptiness)
351         if p.size > 0 {
352                 copy(p.buf[S20BS+PktSizeSize:], ethPkt)
353                 ready <- struct{}{}
354                 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
355                 p.BytesPayloadOut += int64(p.size)
356         } else {
357                 p.HeartbeatSent++
358         }
359
360         p.NonceOur += 2
361         copy(p.nonce, Emptiness)
362         binary.PutUvarint(p.nonce, p.NonceOur)
363         p.NonceCipher.Encrypt(p.nonce, p.nonce)
364
365         salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
366         copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
367         copy(p.keyAuth[:], p.buf[:SSize])
368         if p.NoiseEnable {
369                 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
370         } else {
371                 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+p.size]
372         }
373         poly1305.Sum(p.tag, p.frame, p.keyAuth)
374
375         p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
376         p.FramesOut++
377
378         if p.CPRCycle != time.Duration(0) {
379                 p.willSentCycle = p.LastSent.Add(p.CPRCycle)
380                 if p.willSentCycle.After(p.now) {
381                         time.Sleep(p.willSentCycle.Sub(p.now))
382                         p.now = p.willSentCycle
383                 }
384         }
385         p.LastSent = p.now
386         conn.WriteToUDP(append(p.frame, p.tag[:]...), p.Addr)
387 }