/*
GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
const (
// NonceSize is nonce size
- NonceSize = 8
- nonceBucketSize = 256
- tagSize = poly1305.TagSize
- chacha20InternalBlockSize = 64
+ NonceSize = 8
+ nonceBucketSize = 256
+ tagSize = poly1305.TagSize
+ CC20IBS = 64
// MaxBytesPerKey is maximal amount of bytes transferred with single key (4 GiB)
MaxBytesPerKey uint64 = 1 << 32
// Heartbeat rate, relative to Timeout
noncesT chan *[NonceSize]byte
}
-// LogFields return a logrus compatible Fields to identity a single peer in logs
+// LogFields returns a logrus compatible Fields to identity a single
+// peer in logs
func (p *Peer) LogFields() logrus.Fields {
return logrus.Fields{
logPrefixPeer + "addr": p.Addr,
}
}
-// ConfigurationLogFields return a logrus compatible Fields with the settings of
-// a single peer. Complement LogFields() for extra debugging details.
+// ConfigurationLogFields returns a logrus compatible Fields with the
+// settings of a single peer. Complement LogFields() for extra debugging
+// details.
func (p *Peer) ConfigurationLogFields() logrus.Fields {
return logrus.Fields{
logPrefixPeer + "timeout": p.Timeout.String(),
timeout = timeout / timeoutHeartbeat
}
- bufSize := chacha20InternalBlockSize + 2*conf.MTU
+ bufSize := CC20IBS + 2*conf.MTU
if conf.Encless {
bufSize += EnclessEnlargeSize
noiseEnable = true
// packets will be sent to remote Peer side immediately.
func (p *Peer) EthProcess(data []byte) error {
const paddingSize = 1
- lenData := len(data)
- if lenData > p.MTU-paddingSize {
- logger.WithFields(p.LogFields()).WithFields(p.ConfigurationLogFields()).WithFields(
+ if len(data) > p.MTU-paddingSize {
+ logger.WithFields(
+ p.LogFields(),
+ ).WithFields(
+ p.ConfigurationLogFields(),
+ ).WithFields(
logrus.Fields{
"func": logFuncPrefix + "Peer.EthProcess",
"padding": paddingSize,
- "packet_size": lenData,
- }).Warning("Ignore padded data packet larger than MTU")
+ "packet_size": len(data),
+ },
+ ).Warning("Ignore padded data packet larger than MTU")
return nil
}
p.BusyT.Lock()
// Zero size is a heartbeat packet
SliceZero(p.bufT)
- if lenData == 0 {
- p.bufT[chacha20InternalBlockSize+0] = padByte
+ if len(data) == 0 {
+ p.bufT[CC20IBS+0] = padByte
p.HeartbeatSent++
} else {
// Copy payload to our internal buffer and we are ready to
// accept the next one
- copy(p.bufT[chacha20InternalBlockSize:], data)
- p.bufT[chacha20InternalBlockSize+lenData] = padByte
- p.BytesPayloadOut += uint64(lenData)
+ copy(p.bufT[CC20IBS:], data)
+ p.bufT[CC20IBS+len(data)] = padByte
+ p.BytesPayloadOut += uint64(len(data))
}
if p.NoiseEnable && !p.Encless {
- p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU-tagSize]
+ p.frameT = p.bufT[CC20IBS : CC20IBS+p.MTU-tagSize]
} else if p.Encless {
- p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+p.MTU]
+ p.frameT = p.bufT[CC20IBS : CC20IBS+p.MTU]
} else {
- p.frameT = p.bufT[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData+1+NonceSize]
+ p.frameT = p.bufT[CC20IBS : CC20IBS+len(data)+1+NonceSize]
}
copy(p.frameT[len(p.frameT)-NonceSize:], (<-p.noncesT)[:])
var out []byte
out = append(out, p.frameT[len(p.frameT)-NonceSize:]...)
} else {
chacha20.XORKeyStream(
- p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
- p.bufT[:chacha20InternalBlockSize+len(p.frameT)-NonceSize],
+ p.bufT[:CC20IBS+len(p.frameT)-NonceSize],
+ p.bufT[:CC20IBS+len(p.frameT)-NonceSize],
p.nonceT,
p.key,
)
// PktProcess processes data of a single packet
func (p *Peer) PktProcess(data []byte, tap io.Writer, reorderable bool) bool {
- lenData := len(data)
fields := logrus.Fields{
"func": logFuncPrefix + "Peer.PktProcess",
"reorderable": reorderable,
- "data": lenData,
+ "data": len(data),
}
- if lenData < MinPktLength {
- logger.WithFields(p.LogFields()).WithFields(fields).WithField("minimum_packet_Length", MinPktLength).Debug("Ignore packet smaller than allowed minimum")
+ if len(data) < MinPktLength {
+ logger.WithFields(
+ p.LogFields(),
+ ).WithFields(
+ fields,
+ ).WithField(
+ "minimum_packet_Length",
+ MinPktLength,
+ ).Debug("Ignore packet smaller than allowed minimum")
return false
}
- if !p.Encless && lenData > len(p.bufR)-chacha20InternalBlockSize {
+ if !p.Encless && len(data) > len(p.bufR)-CC20IBS {
return false
}
var out []byte
- p.BusyR.Lock() // TODO use defer to unlock?
- copy(p.nonceR[8:], data[lenData-NonceSize:])
+ var err error
+ p.BusyR.Lock()
+ defer p.BusyR.Unlock()
+ copy(p.nonceR[8:], data[len(data)-NonceSize:])
if p.Encless {
- var err error
- out, err = EnclessDecode(p.key, p.nonceR, data[:lenData-NonceSize])
+ out, err = EnclessDecode(p.key, p.nonceR, data[:len(data)-NonceSize])
if err != nil {
- logger.WithFields(p.LogFields()).WithError(err).Debug("Failed to decode encless")
+ logger.WithFields(
+ p.LogFields(),
+ ).WithError(err).Debug("Failed to decode encless")
p.FramesUnauth++
- p.BusyR.Unlock()
return false
}
} else {
for i := 0; i < SSize; i++ {
p.bufR[i] = 0
}
- copy(p.bufR[chacha20InternalBlockSize:], data[tagSize:])
+ copy(p.bufR[CC20IBS:], data[tagSize:])
chacha20.XORKeyStream(
- p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
- p.bufR[:chacha20InternalBlockSize+lenData-tagSize-NonceSize],
+ p.bufR[:CC20IBS+len(data)-tagSize-NonceSize],
+ p.bufR[:CC20IBS+len(data)-tagSize-NonceSize],
p.nonceR,
p.key,
)
copy(p.tagR[:], data[:tagSize])
if !poly1305.Verify(p.tagR, data[tagSize:], p.keyAuthR) {
p.FramesUnauth++
- p.BusyR.Unlock()
return false
}
- out = p.bufR[chacha20InternalBlockSize : chacha20InternalBlockSize+lenData-tagSize-NonceSize]
+ out = p.bufR[CC20IBS : CC20IBS+len(data)-tagSize-NonceSize]
}
if reorderable {
- copy(p.nonceRecv[:], data[lenData-NonceSize:])
+ copy(p.nonceRecv[:], data[len(data)-NonceSize:])
_, foundL := p.nonceBucketL[p.nonceRecv]
_, foundM := p.nonceBucketM[p.nonceRecv]
_, foundH := p.nonceBucketH[p.nonceRecv]
// or too new (many packets were lost)
if !(foundL || foundM || foundH) {
p.FramesDup++
- p.BusyR.Unlock()
return false
}
// Delete seen nonce
}
}
} else {
- if subtle.ConstantTimeCompare(data[lenData-NonceSize:], p.NonceExpect) != 1 {
+ if subtle.ConstantTimeCompare(data[len(data)-NonceSize:], p.NonceExpect) != 1 {
p.FramesDup++
- p.BusyR.Unlock()
return false
}
copy(p.NonceExpect, (<-p.noncesExpect)[:])
}
p.FramesIn++
- atomic.AddUint64(&p.BytesIn, uint64(lenData))
+ atomic.AddUint64(&p.BytesIn, uint64(len(data)))
p.LastPing = time.Now()
p.pktSizeR = bytes.LastIndexByte(out, padByte)
if p.pktSizeR == -1 {
- p.BusyR.Unlock()
return false
}
// Validate the pad
for i := p.pktSizeR + 1; i < len(out); i++ {
if out[i] != 0 {
- p.BusyR.Unlock()
return false
}
}
if p.pktSizeR == 0 {
p.HeartbeatRecv++
- p.BusyR.Unlock()
return true
}
p.BytesPayloadIn += uint64(p.pktSizeR)
- tap.Write(out[:p.pktSizeR])
- p.BusyR.Unlock()
+ if _, err = tap.Write(out[:p.pktSizeR]); err != nil {
+ logger.WithFields(p.LogFields()).WithFields(fields).WithError(err).Error("Can't write to TAP")
+ }
return true
}
now = time.Now()
if lastSent.Add(peer.Timeout).Before(now) {
if err = peer.EthProcess(nil); err != nil {
- logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
+ logger.WithFields(
+ fields,
+ ).WithFields(
+ peer.LogFields(),
+ ).WithError(err).Warn(
+ "Can't process nil ethernet packet",
+ )
}
lastSent = now
}
case data = <-tap.Sink:
if err = peer.EthProcess(data); err != nil {
- logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
+ logger.WithFields(
+ fields,
+ ).WithFields(
+ peer.LogFields(),
+ ).WithError(err).Warn("Can't process ethernet packet")
}
lastSent = time.Now()
}
break CPRProcessor
case data = <-tap.Sink:
if err = peer.EthProcess(data); err != nil {
- logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process ethernet packet")
+ logger.WithFields(
+ fields,
+ ).WithFields(
+ peer.LogFields(),
+ ).WithError(err).Warn("Can't process ethernet packet")
}
default:
}
if data == nil {
if err = peer.EthProcess(nil); err != nil {
- logger.WithFields(fields).WithFields(peer.LogFields()).WithError(err).Warn("Can't process nil ethernet packet")
+ logger.WithFields(
+ fields,
+ ).WithFields(
+ peer.LogFields(),
+ ).WithError(err).Warn("Can't process nil ethernet packet")
}
}
time.Sleep(peer.CPRCycle)