wireguard-go/src/handshake.go
Mathias Hall-Andersen 1f0976a26c Work on UAPI
Cross-platform API (get operation)
Handshake initiation creation process
Outbound packet flow
Fixes from code-review
2017-06-28 23:45:45 +02:00

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 {
}
}