2018-05-03 15:04:00 +02:00
/ * SPDX - License - Identifier : GPL - 2.0
*
2018-05-07 22:27:03 +02:00
* Copyright ( C ) 2015 - 2018 Jason A . Donenfeld < Jason @ zx2c4 . com > . All Rights Reserved .
*
* This is based heavily on timers . c from the kernel implementation .
2018-05-03 15:04:00 +02:00
* /
2018-02-11 19:02:50 +01:00
package main
import (
"math/rand"
"sync/atomic"
"time"
)
2018-05-07 22:27:03 +02:00
/ * This Timer structure and related functions should roughly copy the interface of
* the Linux kernel ' s struct timer_list .
2018-02-11 19:02:50 +01:00
* /
2018-05-07 22:27:03 +02:00
type Timer struct {
timer * time . Timer
isPending bool
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
func ( peer * Peer ) NewTimer ( expirationFunction func ( * Peer ) ) * Timer {
timer := & Timer { }
timer . timer = time . AfterFunc ( time . Hour , func ( ) {
timer . isPending = false
expirationFunction ( peer )
} )
timer . timer . Stop ( )
return timer
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
func ( timer * Timer ) Mod ( d time . Duration ) {
timer . isPending = true
timer . timer . Reset ( d )
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
func ( timer * Timer ) Del ( ) {
timer . isPending = false
timer . timer . Stop ( )
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
func ( peer * Peer ) timersActive ( ) bool {
return peer . isRunning . Get ( ) && peer . device != nil && peer . device . isUp . Get ( ) && len ( peer . device . peers . keyMap ) > 0
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
func expiredRetransmitHandshake ( peer * Peer ) {
if peer . timers . handshakeAttempts > MaxTimerHandshakes {
peer . device . log . Debug . Printf ( "%s: Handshake did not complete after %d attempts, giving up\n" , peer , MaxTimerHandshakes + 2 )
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/ * We drop all packets without a keypair and don ' t try again ,
* if we try unsuccessfully for too long to make a handshake .
* /
peer . FlushNonceQueue ( )
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/ * We set a timer for destroying any residue that might be left
* of a partial exchange .
* /
if peer . timersActive ( ) && ! peer . timers . zeroKeyMaterial . isPending {
peer . timers . zeroKeyMaterial . Mod ( RejectAfterTime * 3 )
}
} else {
peer . timers . handshakeAttempts ++
peer . device . log . Debug . Printf ( "%s: Handshake did not complete after %d seconds, retrying (try %d)\n" , peer , int ( RekeyTimeout . Seconds ( ) ) , peer . timers . handshakeAttempts + 1 )
/* We clear the endpoint address src address, in case this is the cause of trouble. */
peer . mutex . Lock ( )
if peer . endpoint != nil {
peer . endpoint . ClearSrc ( )
}
peer . mutex . Unlock ( )
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
peer . SendHandshakeInitiation ( true )
}
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
func expiredSendKeepalive ( peer * Peer ) {
peer . SendKeepalive ( )
if peer . timers . needAnotherKeepalive {
peer . timers . needAnotherKeepalive = false
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
}
}
2018-05-05 02:20:52 +02:00
}
2018-05-07 22:27:03 +02:00
func expiredNewHandshake ( peer * Peer ) {
peer . device . log . Debug . Printf ( "%s: Retrying handshake because we stopped hearing back after %d seconds\n" , peer , int ( ( KeepaliveTimeout + RekeyTimeout ) . Seconds ( ) ) )
/* We clear the endpoint address src address, in case this is the cause of trouble. */
peer . mutex . Lock ( )
if peer . endpoint != nil {
peer . endpoint . ClearSrc ( )
2018-02-11 19:02:50 +01:00
}
2018-05-07 22:27:03 +02:00
peer . mutex . Unlock ( )
peer . SendHandshakeInitiation ( false )
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
}
2018-05-05 04:15:07 +02:00
2018-05-07 22:27:03 +02:00
func expiredZeroKeyMaterial ( peer * Peer ) {
peer . device . log . Debug . Printf ( ":%s Removing all keys, since we haven't received a new one in %d seconds\n" , peer , int ( ( RejectAfterTime * 3 ) . Seconds ( ) ) )
2018-05-05 04:15:07 +02:00
2018-05-07 22:27:03 +02:00
hs := & peer . handshake
hs . mutex . Lock ( )
2018-02-11 19:02:50 +01:00
2018-05-13 18:23:40 +02:00
kp := & peer . keypairs
2018-05-07 22:27:03 +02:00
kp . mutex . Lock ( )
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
if kp . previous != nil {
peer . device . DeleteKeypair ( kp . previous )
kp . previous = nil
}
if kp . current != nil {
peer . device . DeleteKeypair ( kp . current )
kp . current = nil
}
if kp . next != nil {
peer . device . DeleteKeypair ( kp . next )
kp . next = nil
}
kp . mutex . Unlock ( )
2018-02-11 19:02:50 +01:00
2018-05-13 18:23:40 +02:00
peer . device . indexTable . Delete ( hs . localIndex )
2018-05-07 22:27:03 +02:00
hs . Clear ( )
hs . mutex . Unlock ( )
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
func expiredPersistentKeepalive ( peer * Peer ) {
if peer . persistentKeepaliveInterval > 0 {
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
}
peer . SendKeepalive ( )
}
}
2018-05-05 02:20:52 +02:00
2018-05-07 22:27:03 +02:00
/* Should be called after an authenticated data packet is sent. */
func ( peer * Peer ) timersDataSent ( ) {
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
}
2018-05-05 02:20:52 +02:00
2018-05-07 22:27:03 +02:00
if peer . timersActive ( ) && ! peer . timers . newHandshake . isPending {
peer . timers . newHandshake . Mod ( KeepaliveTimeout + RekeyTimeout )
}
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/* Should be called after an authenticated data packet is received. */
func ( peer * Peer ) timersDataReceived ( ) {
if peer . timersActive ( ) {
if ! peer . timers . sendKeepalive . isPending {
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
} else {
peer . timers . needAnotherKeepalive = true
}
}
}
2018-05-05 04:15:07 +02:00
2018-05-07 22:27:03 +02:00
/* Should be called after any type of authenticated packet is received -- keepalive or data. */
func ( peer * Peer ) timersAnyAuthenticatedPacketReceived ( ) {
if peer . timersActive ( ) {
peer . timers . newHandshake . Del ( )
}
}
2018-05-05 04:15:07 +02:00
2018-05-07 22:27:03 +02:00
/* Should be called after a handshake initiation message is sent. */
func ( peer * Peer ) timersHandshakeInitiated ( ) {
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
peer . timers . retransmitHandshake . Mod ( RekeyTimeout + time . Millisecond * time . Duration ( rand . Int31n ( RekeyTimeoutJitterMaxMs ) ) )
}
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/* Should be called after a handshake response message is received and processed or when getting key confirmation via the first data message. */
func ( peer * Peer ) timersHandshakeComplete ( ) {
if peer . timersActive ( ) {
peer . timers . retransmitHandshake . Del ( )
}
peer . timers . handshakeAttempts = 0
peer . timers . sentLastMinuteHandshake = false
atomic . StoreInt64 ( & peer . stats . lastHandshakeNano , time . Now ( ) . UnixNano ( ) )
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */
func ( peer * Peer ) timersSessionDerived ( ) {
if peer . timersActive ( ) {
peer . timers . zeroKeyMaterial . Mod ( RejectAfterTime * 3 )
}
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
/* Should be called before a packet with authentication -- data, keepalive, either handshake -- is sent, or after one is received. */
func ( peer * Peer ) timersAnyAuthenticatedPacketTraversal ( ) {
if peer . persistentKeepaliveInterval > 0 && peer . timersActive ( ) {
peer . timers . persistentKeepalive . Mod ( time . Duration ( peer . persistentKeepaliveInterval ) * time . Second )
}
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
func ( peer * Peer ) timersInit ( ) {
peer . timers . retransmitHandshake = peer . NewTimer ( expiredRetransmitHandshake )
peer . timers . sendKeepalive = peer . NewTimer ( expiredSendKeepalive )
peer . timers . newHandshake = peer . NewTimer ( expiredNewHandshake )
peer . timers . zeroKeyMaterial = peer . NewTimer ( expiredZeroKeyMaterial )
peer . timers . persistentKeepalive = peer . NewTimer ( expiredPersistentKeepalive )
peer . timers . handshakeAttempts = 0
peer . timers . sentLastMinuteHandshake = false
peer . timers . needAnotherKeepalive = false
peer . timers . lastSentHandshake = time . Now ( ) . Add ( - ( RekeyTimeout + time . Second ) )
}
2018-05-05 04:15:07 +02:00
2018-05-07 22:27:03 +02:00
func ( peer * Peer ) timersStop ( ) {
peer . timers . retransmitHandshake . Del ( )
peer . timers . sendKeepalive . Del ( )
peer . timers . newHandshake . Del ( )
peer . timers . zeroKeyMaterial . Del ( )
peer . timers . persistentKeepalive . Del ( )
2018-02-11 19:02:50 +01:00
}