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