summaryrefslogtreecommitdiffhomepage
path: root/src/handshake.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/handshake.go')
-rw-r--r--src/handshake.go172
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 {
+
+ }
+}