diff options
Diffstat (limited to 'src/handshake.go')
-rw-r--r-- | src/handshake.go | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/handshake.go b/src/handshake.go new file mode 100644 index 0000000..238c339 --- /dev/null +++ b/src/handshake.go @@ -0,0 +1,172 @@ +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 { + + } +} |