1f0976a26c
Cross-platform API (get operation) Handshake initiation creation process Outbound packet flow Fixes from code-review
173 lines
3 KiB
Go
173 lines
3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"net"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
/* Sends a keep-alive if no packets queued for peer
|
|
*
|
|
* Used by initiator of handshake and with active keep-alive
|
|
*/
|
|
func (peer *Peer) SendKeepAlive() bool {
|
|
if len(peer.queue.nonce) == 0 {
|
|
select {
|
|
case peer.queue.nonce <- []byte{}:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (peer *Peer) RoutineHandshakeInitiator() {
|
|
var ongoing bool
|
|
var begun time.Time
|
|
var attempts uint
|
|
var timeout time.Timer
|
|
|
|
device := peer.device
|
|
work := new(QueueOutboundElement)
|
|
buffer := make([]byte, 0, 1024)
|
|
|
|
queueHandshakeInitiation := func() error {
|
|
work.mutex.Lock()
|
|
defer work.mutex.Unlock()
|
|
|
|
// create initiation
|
|
|
|
msg, err := device.CreateMessageInitiation(peer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// create "work" element
|
|
|
|
writer := bytes.NewBuffer(buffer[:0])
|
|
binary.Write(writer, binary.LittleEndian, &msg)
|
|
work.packet = writer.Bytes()
|
|
peer.mac.AddMacs(work.packet)
|
|
peer.InsertOutbound(work)
|
|
return nil
|
|
}
|
|
|
|
for {
|
|
select {
|
|
case <-peer.signal.stopInitiator:
|
|
return
|
|
|
|
case <-peer.signal.newHandshake:
|
|
if ongoing {
|
|
continue
|
|
}
|
|
|
|
// create handshake
|
|
|
|
err := queueHandshakeInitiation()
|
|
if err != nil {
|
|
device.log.Error.Println("Failed to create initiation message:", err)
|
|
}
|
|
|
|
// log when we began
|
|
|
|
begun = time.Now()
|
|
ongoing = true
|
|
attempts = 0
|
|
timeout.Reset(RekeyTimeout)
|
|
|
|
case <-peer.timer.sendKeepalive.C:
|
|
|
|
// active keep-alives
|
|
|
|
peer.SendKeepAlive()
|
|
|
|
case <-peer.timer.handshakeTimeout.C:
|
|
|
|
// check if we can stop trying
|
|
|
|
if time.Now().Sub(begun) > MaxHandshakeAttempTime {
|
|
peer.signal.flushNonceQueue <- true
|
|
peer.timer.sendKeepalive.Stop()
|
|
ongoing = false
|
|
continue
|
|
}
|
|
|
|
// otherwise, try again (exponental backoff)
|
|
|
|
attempts += 1
|
|
err := queueHandshakeInitiation()
|
|
if err != nil {
|
|
device.log.Error.Println("Failed to create initiation message:", err)
|
|
}
|
|
peer.timer.handshakeTimeout.Reset((1 << attempts) * RekeyTimeout)
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Handles packets related to handshake
|
|
*
|
|
*
|
|
*/
|
|
func (device *Device) HandshakeWorker(queue chan struct {
|
|
msg []byte
|
|
msgType uint32
|
|
addr *net.UDPAddr
|
|
}) {
|
|
for {
|
|
elem := <-queue
|
|
|
|
switch elem.msgType {
|
|
case MessageInitiationType:
|
|
if len(elem.msg) != MessageInitiationSize {
|
|
continue
|
|
}
|
|
|
|
// check for cookie
|
|
|
|
var msg MessageInitiation
|
|
|
|
binary.Read(nil, binary.LittleEndian, &msg)
|
|
|
|
case MessageResponseType:
|
|
if len(elem.msg) != MessageResponseSize {
|
|
continue
|
|
}
|
|
|
|
// check for cookie
|
|
|
|
case MessageCookieReplyType:
|
|
|
|
case MessageTransportType:
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func (device *Device) KeepKeyFresh(peer *Peer) {
|
|
|
|
send := func() bool {
|
|
peer.keyPairs.mutex.RLock()
|
|
defer peer.keyPairs.mutex.RUnlock()
|
|
|
|
kp := peer.keyPairs.current
|
|
if kp == nil {
|
|
return false
|
|
}
|
|
|
|
nonce := atomic.LoadUint64(&kp.sendNonce)
|
|
if nonce > RekeyAfterMessage {
|
|
return true
|
|
}
|
|
|
|
return kp.isInitiator && time.Now().Sub(kp.created) > RekeyAfterTime
|
|
}()
|
|
|
|
if send {
|
|
|
|
}
|
|
}
|