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/>.
31 "github.com/dchest/blake2b"
32 "golang.org/x/crypto/poly1305"
33 "golang.org/x/crypto/salsa20"
39 TagSize = poly1305.TagSize
40 // S20BS is Salsa20's internal blocksize in bytes
42 // Maximal amount of bytes transfered with single key (4 GiB)
43 MaxBytesPerKey uint64 = 1 << 32
44 // Heartbeat rate, relative to Timeout
46 // Minimal valid packet length
47 MinPktLength = 1 + 16 + 8
52 func newNonces(key *[32]byte, i uint64) chan *[NonceSize]byte {
53 macKey := make([]byte, 32)
54 salsa20.XORKeyStream(macKey, make([]byte, 32), make([]byte, 8), key)
55 mac := blake2b.NewMAC(NonceSize, macKey)
56 nonces := make(chan *[NonceSize]byte, NonceBucketSize*3)
59 buf := new([NonceSize]byte)
60 binary.BigEndian.PutUint64(buf[:], i)
72 // Statistics (they are at the beginning for correct int64 alignment)
76 BytesPayloadOut uint64
87 Conn io.Writer `json:"-"`
92 CPRCycle time.Duration `json:"-"`
96 key *[SSize]byte `json:"-"`
99 Timeout time.Duration `json:"-"`
100 Established time.Time
104 BusyR sync.Mutex `json:"-"`
107 keyAuthR *[SSize]byte
111 noncesR chan *[NonceSize]byte
112 nonceRecv [NonceSize]byte
113 nonceBucketL map[[NonceSize]byte]struct{}
114 nonceBucketM map[[NonceSize]byte]struct{}
115 nonceBucketH map[[NonceSize]byte]struct{}
118 NonceExpect []byte `json:"-"`
119 noncesExpect chan *[NonceSize]byte
122 BusyT sync.Mutex `json:"-"`
125 keyAuthT *[SSize]byte
127 noncesT chan *[NonceSize]byte
130 func (p *Peer) String() string {
131 return p.Id.String() + ":" + p.Addr
134 // Zero peer's memory state.
135 func (p *Peer) Zero() {
141 SliceZero(p.keyAuthR[:])
142 SliceZero(p.keyAuthT[:])
147 func cprCycleCalculate(conf *PeerConf) time.Duration {
149 return time.Duration(0)
151 rate := conf.CPR * 1 << 10
153 rate /= EnclessEnlargeSize + conf.MTU
157 return time.Second / time.Duration(rate)
160 func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[SSize]byte) *Peer {
162 timeout := conf.Timeout
164 cprCycle := cprCycleCalculate(conf)
165 noiseEnable := conf.Noise
170 timeout = timeout / TimeoutHeartbeat
173 bufSize := S20BS + 2*conf.MTU
175 bufSize += EnclessEnlargeSize
184 NoiseEnable: noiseEnable,
187 Encless: conf.Encless,
196 bufR: make([]byte, bufSize),
197 bufT: make([]byte, bufSize),
198 tagR: new([TagSize]byte),
199 tagT: new([TagSize]byte),
200 keyAuthR: new([SSize]byte),
201 keyAuthT: new([SSize]byte),
205 peer.noncesT = newNonces(peer.key, 1+2)
206 peer.noncesR = newNonces(peer.key, 0+2)
207 peer.noncesExpect = newNonces(peer.key, 0+2)
209 peer.noncesT = newNonces(peer.key, 0+2)
210 peer.noncesR = newNonces(peer.key, 1+2)
211 peer.noncesExpect = newNonces(peer.key, 1+2)
214 peer.NonceExpect = make([]byte, NonceSize)
215 nonce := <-peer.noncesExpect
216 copy(peer.NonceExpect, nonce[:])
219 peer.nonceBucketL = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
220 for i = 0; i < NonceBucketSize; i++ {
221 nonce = <-peer.noncesR
222 peer.nonceBucketL[*nonce] = struct{}{}
224 peer.nonceBucketM = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
225 for i = 0; i < NonceBucketSize; i++ {
226 nonce = <-peer.noncesR
227 peer.nonceBucketM[*nonce] = struct{}{}
229 peer.nonceBucketH = make(map[[NonceSize]byte]struct{}, NonceBucketSize)
230 for i = 0; i < NonceBucketSize; i++ {
231 nonce = <-peer.noncesR
232 peer.nonceBucketH[*nonce] = struct{}{}
238 // Process incoming Ethernet packet.
239 // ready channel is TAPListen's synchronization channel used to tell him
240 // that he is free to receive new packets. Encrypted and authenticated
241 // packets will be sent to remote Peer side immediately.
242 func (p *Peer) EthProcess(data []byte) {
243 if len(data) > p.MTU-1 { // 1 is for padding byte
244 log.Println("Padded data packet size", len(data)+1, "is bigger than MTU", p.MTU, p)
249 // Zero size is a heartbeat packet
252 p.bufT[S20BS+0] = PadByte
255 // Copy payload to our internal buffer and we are ready to
256 // accept the next one
257 copy(p.bufT[S20BS:], data)
258 p.bufT[S20BS+len(data)] = PadByte
259 p.BytesPayloadOut += uint64(len(data))
262 if p.NoiseEnable && !p.Encless {
263 p.frameT = p.bufT[S20BS : S20BS+p.MTU-TagSize]
264 } else if p.Encless {
265 p.frameT = p.bufT[S20BS : S20BS+p.MTU]
267 p.frameT = p.bufT[S20BS : S20BS+len(data)+1+NonceSize]
269 copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
273 out, err = EnclessEncode(
275 p.frameT[len(p.frameT)-NonceSize:],
276 p.frameT[:len(p.frameT)-NonceSize],
281 out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
283 salsa20.XORKeyStream(
284 p.bufT[:S20BS+len(p.frameT)-NonceSize],
285 p.bufT[:S20BS+len(p.frameT)-NonceSize],
286 p.frameT[len(p.frameT)-NonceSize:],
289 copy(p.keyAuthT[:], p.bufT[:SSize])
290 poly1305.Sum(p.tagT, p.frameT, p.keyAuthT)
291 atomic.AddUint64(&p.BytesOut, uint64(len(p.frameT)+TagSize))
292 out = append(p.tagT[:], p.frameT...)
299 func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
300 if len(data) < MinPktLength {
303 if !p.Encless && len(data) > len(p.bufR)-S20BS {
310 out, err = EnclessDecode(
312 data[len(data)-NonceSize:],
313 data[:len(data)-NonceSize],
321 for i := 0; i < SSize; i++ {
324 copy(p.bufR[S20BS:], data[TagSize:])
325 salsa20.XORKeyStream(
326 p.bufR[:S20BS+len(data)-TagSize-NonceSize],
327 p.bufR[:S20BS+len(data)-TagSize-NonceSize],
328 data[len(data)-NonceSize:],
331 copy(p.keyAuthR[:], p.bufR[:SSize])
332 copy(p.tagR[:], data[:TagSize])
333 if !poly1305.Verify(p.tagR, data[TagSize:], p.keyAuthR) {
338 out = p.bufR[S20BS : S20BS+len(data)-TagSize-NonceSize]
342 copy(p.nonceRecv[:], data[len(data)-NonceSize:])
343 _, foundL := p.nonceBucketL[p.nonceRecv]
344 _, foundM := p.nonceBucketM[p.nonceRecv]
345 _, foundH := p.nonceBucketH[p.nonceRecv]
346 // If found is none of buckets: either it is too old,
347 // or too new (many packets were lost)
348 if !(foundL || foundM || foundH) {
355 delete(p.nonceBucketL, p.nonceRecv)
358 delete(p.nonceBucketM, p.nonceRecv)
361 delete(p.nonceBucketH, p.nonceRecv)
363 // If we are dealing with the latest bucket, create the new one
365 p.nonceBucketL, p.nonceBucketM = p.nonceBucketM, p.nonceBucketH
366 p.nonceBucketH = make(map[[NonceSize]byte]struct{})
367 var nonce *[NonceSize]byte
368 for i := 0; i < NonceBucketSize; i++ {
370 p.nonceBucketH[*nonce] = struct{}{}
374 if subtle.ConstantTimeCompare(data[len(data)-NonceSize:], p.NonceExpect) != 1 {
379 copy(p.NonceExpect, (<-p.noncesExpect)[:])
383 atomic.AddUint64(&p.BytesIn, uint64(len(data)))
384 p.LastPing = time.Now()
385 p.pktSizeR = bytes.LastIndexByte(out, PadByte)
386 if p.pktSizeR == -1 {
391 for i := p.pktSizeR + 1; i < len(out); i++ {
403 p.BytesPayloadIn += uint64(p.pktSizeR)
404 tap.Write(out[:p.pktSizeR])
409 func PeerTapProcessor(peer *Peer, tap *TAP, terminator chan struct{}) {
412 lastSent := time.Now()
413 heartbeat := time.NewTicker(peer.Timeout)
414 if peer.CPRCycle == time.Duration(0) {
422 if lastSent.Add(peer.Timeout).Before(now) {
426 case data = <-tap.Sink:
427 peer.EthProcess(data)
428 lastSent = time.Now()
438 case data = <-tap.Sink:
439 peer.EthProcess(data)
445 time.Sleep(peer.CPRCycle)