]> Cypherpunks.ru repositories - govpn.git/blob - src/govpn/transport.go
Move UDP-network related code from the transport file
[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 Peer struct {
46         Addr *net.UDPAddr
47         Id   *PeerId
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.String()
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 *net.UDPAddr, 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                 Timeout:      timeout,
218                 Established:  now,
219                 LastPing:     now,
220                 Id:           conf.Id,
221                 NoiseEnable:  noiseEnable,
222                 CPR:          conf.CPR,
223                 CPRCycle:     cprCycle,
224                 NonceOur:     uint64(nonce),
225                 NonceRecv:    uint64(0),
226                 nonceBucket0: make(map[uint64]struct{}, NonceBucketSize),
227                 nonceBucket1: make(map[uint64]struct{}, NonceBucketSize),
228                 Key:          key,
229                 NonceCipher:  newNonceCipher(key),
230                 buf:          make([]byte, MTU+S20BS),
231                 tag:          new([poly1305.TagSize]byte),
232                 keyAuth:      new([SSize]byte),
233                 nonce:        make([]byte, NonceSize),
234         }
235         return &peer
236 }
237
238 // Process incoming UDP packet.
239 // udpPkt is received data, related to the peer tap interface and
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) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
244         p.size = len(udpPkt)
245         copy(p.buf, Emptiness)
246         copy(p.tag[:], udpPkt[p.size-poly1305.TagSize:])
247         copy(p.buf[S20BS:], udpPkt[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                 udpPkt[:NonceSize],
252                 p.Key,
253         )
254         copy(p.keyAuth[:], p.buf[:SSize])
255         if !poly1305.Verify(p.tag, udpPkt[: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, udpPkt[: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 type WriteToUDPer interface {
301         WriteToUDP([]byte, *net.UDPAddr) (int, error)
302 }
303
304 // Process incoming Ethernet packet.
305 // ethPkt is received data, conn is our outgoing connection.
306 // ready channel is TAPListen's synchronization channel used to tell him
307 // that he is free to receive new packets. Encrypted and authenticated
308 // packets will be sent to remote Peer side immediately.
309 func (p *Peer) EthProcess(ethPkt []byte, conn WriteToUDPer, ready chan struct{}) {
310         p.now = time.Now()
311         p.size = len(ethPkt)
312         // If this heartbeat is necessary
313         if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
314                 return
315         }
316         copy(p.buf, Emptiness)
317         if p.size > 0 {
318                 copy(p.buf[S20BS+PktSizeSize:], ethPkt)
319                 ready <- struct{}{}
320                 binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
321                 p.BytesPayloadOut += int64(p.size)
322         } else {
323                 p.HeartbeatSent++
324         }
325
326         p.NonceOur += 2
327         copy(p.nonce, Emptiness)
328         binary.PutUvarint(p.nonce, p.NonceOur)
329         p.NonceCipher.Encrypt(p.nonce, p.nonce)
330
331         salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
332         copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
333         copy(p.keyAuth[:], p.buf[:SSize])
334         if p.NoiseEnable {
335                 p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
336         } else {
337                 p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+p.size]
338         }
339         poly1305.Sum(p.tag, p.frame, p.keyAuth)
340
341         p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
342         p.FramesOut++
343
344         if p.CPRCycle != time.Duration(0) {
345                 p.willSentCycle = p.LastSent.Add(p.CPRCycle)
346                 if p.willSentCycle.After(p.now) {
347                         time.Sleep(p.willSentCycle.Sub(p.now))
348                         p.now = p.willSentCycle
349                 }
350         }
351         p.LastSent = p.now
352         conn.WriteToUDP(append(p.frame, p.tag[:]...), p.Addr)
353 }