Files
wireguard-go/src/handshake.go
T

208 lines
4.0 KiB
Go
Raw Normal View History

2017-06-28 23:45:45 +02:00
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
}
2017-06-30 14:41:08 +02:00
func StoppedTimer() *time.Timer {
timer := time.NewTimer(time.Hour)
if !timer.Stop() {
<-timer.C
2017-06-28 23:45:45 +02:00
}
2017-06-30 14:41:08 +02:00
return timer
}
2017-06-28 23:45:45 +02:00
2017-06-30 14:41:08 +02:00
/* Called when a new authenticated message has been send
*
* TODO: This might be done in a faster way
*/
func (peer *Peer) KeepKeyFreshSending() {
send := func() bool {
peer.keyPairs.mutex.RLock()
defer peer.keyPairs.mutex.RUnlock()
2017-06-28 23:45:45 +02:00
2017-06-30 14:41:08 +02:00
kp := peer.keyPairs.current
if kp == nil {
return false
2017-06-28 23:45:45 +02:00
}
2017-06-30 14:41:08 +02:00
if !kp.isInitiator {
return false
}
nonce := atomic.LoadUint64(&kp.sendNonce)
if nonce > RekeyAfterMessages {
return true
}
return time.Now().Sub(kp.created) > RekeyAfterTime
}()
if send {
sendSignal(peer.signal.handshakeBegin)
2017-06-28 23:45:45 +02:00
}
}
2017-06-30 14:41:08 +02:00
/* This is the state machine for handshake initiation
*
* Associated with this routine is the signal "handshakeBegin"
* The routine will read from the "handshakeBegin" channel
2017-06-30 23:05:03 +02:00
* at most every RekeyTimeout seconds
2017-06-30 14:41:08 +02:00
*/
func (peer *Peer) RoutineHandshakeInitiator() {
device := peer.device
buffer := make([]byte, 1024)
logger := device.log.Debug
timeout := time.NewTimer(time.Hour)
2017-06-30 23:05:03 +02:00
var work *QueueOutboundElement
2017-06-30 14:41:08 +02:00
logger.Println("Routine, handshake initator, started for peer", peer.id)
func() {
for {
var attempts uint
var deadline time.Time
2017-06-30 23:05:03 +02:00
// wait for signal
2017-06-30 14:41:08 +02:00
select {
case <-peer.signal.handshakeBegin:
case <-peer.signal.stop:
return
}
HandshakeLoop:
2017-06-30 23:05:03 +02:00
for {
2017-06-30 14:41:08 +02:00
// clear completed signal
select {
case <-peer.signal.handshakeCompleted:
case <-peer.signal.stop:
return
default:
}
2017-06-30 23:05:03 +02:00
// create initiation
2017-06-30 14:41:08 +02:00
2017-06-30 23:05:03 +02:00
if work != nil {
2017-06-30 14:41:08 +02:00
work.mutex.Lock()
2017-06-30 23:05:03 +02:00
work.packet = nil
work.mutex.Unlock()
}
work = new(QueueOutboundElement)
msg, err := device.CreateMessageInitiation(peer)
2017-06-30 14:41:08 +02:00
if err != nil {
device.log.Error.Println("Failed to create initiation message:", err)
break
}
2017-06-30 23:05:03 +02:00
// schedule for sending
writer := bytes.NewBuffer(buffer[:0])
binary.Write(writer, binary.LittleEndian, msg)
work.packet = writer.Bytes()
peer.mac.AddMacs(work.packet)
peer.InsertOutbound(work)
2017-06-30 14:41:08 +02:00
if attempts == 0 {
deadline = time.Now().Add(MaxHandshakeAttemptTime)
}
// set timeout
if !timeout.Stop() {
select {
case <-timeout.C:
default:
}
}
attempts += 1
2017-06-30 23:05:03 +02:00
timeout.Reset(RekeyTimeout)
2017-06-30 14:41:08 +02:00
device.log.Debug.Println("Handshake initiation attempt", attempts, "queued for peer", peer.id)
// wait for handshake or timeout
select {
case <-peer.signal.stop:
return
case <-peer.signal.handshakeCompleted:
break HandshakeLoop
2017-06-30 23:05:03 +02:00
case <-timeout.C:
if deadline.Before(time.Now().Add(RekeyTimeout)) {
peer.signal.flushNonceQueue <- struct{}{}
if !peer.timer.sendKeepalive.Stop() {
<-peer.timer.sendKeepalive.C
2017-06-30 14:41:08 +02:00
}
2017-06-30 23:05:03 +02:00
break HandshakeLoop
2017-06-30 14:41:08 +02:00
}
}
}
}
}()
logger.Println("Routine, handshake initator, stopped for peer", peer.id)
}
/* Handles incomming packets related to handshake
2017-06-28 23:45:45 +02:00
*
*
*/
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:
2017-06-30 14:41:08 +02:00
if len(elem.msg) != MessageCookieReplySize {
continue
}
2017-06-28 23:45:45 +02:00
2017-06-30 14:41:08 +02:00
default:
device.log.Error.Println("Invalid message type in handshake queue")
2017-06-28 23:45:45 +02:00
}
}
}