2 GoVPN -- simple secure free software virtual private network daemon
3 Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
30 "golang.org/x/crypto/poly1305"
31 "golang.org/x/crypto/salsa20"
32 "golang.org/x/crypto/xtea"
38 TagSize = poly1305.TagSize
39 // S20BS is Salsa20's internal blocksize in bytes
41 // Maximal amount of bytes transfered with single key (4 GiB)
42 MaxBytesPerKey uint64 = 1 << 32
43 // Heartbeat rate, relative to Timeout
45 // Minimal valid packet length
46 MinPktLength = 1 + 16 + 8
51 func newNonceCipher(key *[32]byte) *xtea.Cipher {
52 nonceKey := make([]byte, 16)
56 make([]byte, xtea.BlockSize),
59 ciph, err := xtea.NewCipher(nonceKey)
67 // Statistics (they are at the beginning for correct int64 alignment)
71 BytesPayloadOut uint64
82 Conn io.Writer `json:"-"`
87 CPRCycle time.Duration `json:"-"`
91 // Cryptography related
92 Key *[SSize]byte `json:"-"`
93 NonceCipher *xtea.Cipher `json:"-"`
97 NonceExpect uint64 `json:"-"`
98 nonceBucket0 map[uint64]struct{}
99 nonceBucket1 map[uint64]struct{}
105 Timeout time.Duration `json:"-"`
106 Established time.Time
109 willSentCycle time.Time
112 BusyR sync.Mutex `json:"-"`
115 keyAuthR *[SSize]byte
119 BusyT sync.Mutex `json:"-"`
122 keyAuthT *[SSize]byte
127 func (p *Peer) String() string {
128 return p.Id.String() + ":" + p.Addr
131 // Zero peer's memory state.
132 func (p *Peer) Zero() {
138 SliceZero(p.keyAuthR[:])
139 SliceZero(p.keyAuthT[:])
144 func (p *Peer) NonceExpectation(buf []byte) {
145 binary.BigEndian.PutUint64(buf, p.NonceExpect)
146 p.NonceCipher.Encrypt(buf, buf)
149 func cprCycleCalculate(conf *PeerConf) time.Duration {
151 return time.Duration(0)
153 rate := conf.CPR * 1 << 10
155 rate /= EnclessEnlargeSize + conf.MTU
159 return time.Second / time.Duration(rate)
162 func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[SSize]byte) *Peer {
164 timeout := conf.Timeout
166 cprCycle := cprCycleCalculate(conf)
167 noiseEnable := conf.Noise
172 timeout = timeout / TimeoutHeartbeat
175 bufSize := S20BS + 2*conf.MTU
177 bufSize += EnclessEnlargeSize
185 NoiseEnable: noiseEnable,
188 Encless: conf.Encless,
192 NonceCipher: newNonceCipher(key),
193 nonceBucket0: make(map[uint64]struct{}, NonceBucketSize),
194 nonceBucket1: make(map[uint64]struct{}, NonceBucketSize),
200 bufR: make([]byte, bufSize),
201 bufT: make([]byte, bufSize),
202 tagR: new([TagSize]byte),
203 tagT: new([TagSize]byte),
204 keyAuthR: new([SSize]byte),
205 keyAuthT: new([SSize]byte),
209 peer.NonceExpect = 0 + 2
212 peer.NonceExpect = 1 + 2
218 // Process incoming Ethernet packet.
219 // ready channel is TAPListen's synchronization channel used to tell him
220 // that he is free to receive new packets. Encrypted and authenticated
221 // packets will be sent to remote Peer side immediately.
222 func (p *Peer) EthProcess(data []byte) {
223 if len(data) > p.MTU-1 { // 1 is for padding byte
224 log.Println("Padded data packet size", len(data)+1, "is bigger than MTU", p.MTU, p)
230 // Zero size is a heartbeat packet
233 // If this heartbeat is necessary
234 if !p.LastSent.Add(p.Timeout).Before(p.now) {
238 p.bufT[S20BS+0] = PadByte
241 // Copy payload to our internal buffer and we are ready to
242 // accept the next one
243 copy(p.bufT[S20BS:], data)
244 p.bufT[S20BS+len(data)] = PadByte
245 p.BytesPayloadOut += uint64(len(data))
248 if p.NoiseEnable && !p.Encless {
249 p.frameT = p.bufT[S20BS : S20BS+p.MTU-TagSize]
250 } else if p.Encless {
251 p.frameT = p.bufT[S20BS : S20BS+p.MTU]
253 p.frameT = p.bufT[S20BS : S20BS+len(data)+1+NonceSize]
256 binary.BigEndian.PutUint64(p.frameT[len(p.frameT)-NonceSize:], p.nonceOur)
257 p.NonceCipher.Encrypt(
258 p.frameT[len(p.frameT)-NonceSize:],
259 p.frameT[len(p.frameT)-NonceSize:],
264 out, err = EnclessEncode(
266 p.frameT[len(p.frameT)-NonceSize:],
267 p.frameT[:len(p.frameT)-NonceSize],
272 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
274 salsa20.XORKeyStream(
275 p.bufT[:S20BS+len(p.frameT)-NonceSize],
276 p.bufT[:S20BS+len(p.frameT)-NonceSize],
277 p.frameT[len(p.frameT)-NonceSize:],
280 copy(p.keyAuthT[:], p.bufT[:SSize])
281 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
282 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+TagSize))
283 out = append(p.tagT[:], p.frameT...)
287 if p.CPRCycle != time.Duration(0) {
288 p.willSentCycle = p.LastSent.Add(p.CPRCycle)
289 if p.willSentCycle.After(p.now) {
290 time.Sleep(p.willSentCycle.Sub(p.now))
291 p.now = p.willSentCycle
300 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
301 if len(data) < MinPktLength {
304 if !p.Encless && len(data) > len(p.bufR)-S20BS {
311 out, err = EnclessDecode(
313 data[len(data)-NonceSize:],
314 data[:len(data)-NonceSize],
322 for i := 0; i < SSize; i++ {
325 copy(p.bufR[S20BS:], data[TagSize:])
326 salsa20.XORKeyStream(
327 p.bufR[:S20BS+len(data)-TagSize-NonceSize],
328 p.bufR[:S20BS+len(data)-TagSize-NonceSize],
329 data[len(data)-NonceSize:],
332 copy(p.keyAuthR[:], p.bufR[:SSize])
333 copy(p.tagR[:], data[:TagSize])
334 if !poly1305.Verify(p.tagR, data[TagSize:], p.keyAuthR) {
339 out = p.bufR[S20BS : S20BS+len(data)-TagSize-NonceSize]
342 // Check if received nonce is known to us in either of two buckets.
343 // If yes, then this is ignored duplicate.
344 // Check from the oldest bucket, as in most cases this will result
345 // in constant time check.
346 // If Bucket0 is filled, then it becomes Bucket1.
347 p.NonceCipher.Decrypt(
348 data[len(data)-NonceSize:],
349 data[len(data)-NonceSize:],
351 p.nonceRecv = binary.BigEndian.Uint64(data[len(data)-NonceSize:])
353 _, p.nonceFound0 = p.nonceBucket0[p.nonceRecv]
354 _, p.nonceFound1 = p.nonceBucket1[p.nonceRecv]
355 if p.nonceFound0 || p.nonceFound1 || p.nonceRecv+2*NonceBucketSize < p.nonceLatest {
360 p.nonceBucket0[p.nonceRecv] = struct{}{}
362 if p.nonceBucketN == NonceBucketSize {
363 p.nonceBucket1 = p.nonceBucket0
364 p.nonceBucket0 = make(map[uint64]struct{}, NonceBucketSize)
368 if p.nonceRecv != p.NonceExpect {
375 if p.nonceRecv > p.nonceLatest {
376 p.nonceLatest = p.nonceRecv
380 atomic.AddUint64(&p.BytesIn, uint64(len(data)))
381 p.LastPing = time.Now()
382 p.pktSizeR = bytes.LastIndexByte(out, PadByte)
383 if p.pktSizeR == -1 {
388 for i := p.pktSizeR + 1; i < len(out); i++ {
400 p.BytesPayloadIn += uint64(p.pktSizeR)
401 tap.Write(out[:p.pktSizeR])