2018-05-03 13:04:00 +00:00
/ * SPDX - License - Identifier : GPL - 2.0
*
2018-05-07 20:27:03 +00: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 13:04:00 +00:00
* /
2018-02-11 18:02:50 +00:00
package main
import (
"math/rand"
2018-05-15 16:38:18 +00:00
"sync"
2018-02-11 18:02:50 +00:00
"sync/atomic"
"time"
)
2018-05-07 20:27:03 +00:00
/ * This Timer structure and related functions should roughly copy the interface of
* the Linux kernel ' s struct timer_list .
2018-02-11 18:02:50 +00:00
* /
2018-05-07 20:27:03 +00:00
type Timer struct {
2018-05-15 16:38:18 +00:00
timer * time . Timer
2018-05-20 01:31:27 +00:00
modifyingLock sync . RWMutex
2018-05-15 16:38:18 +00:00
runningLock sync . Mutex
isPending bool
2018-02-11 18:02:50 +00:00
}
2018-05-07 20:27:03 +00:00
func ( peer * Peer ) NewTimer ( expirationFunction func ( * Peer ) ) * Timer {
timer := & Timer { }
timer . timer = time . AfterFunc ( time . Hour , func ( ) {
2018-05-15 16:38:18 +00:00
timer . runningLock . Lock ( )
timer . modifyingLock . Lock ( )
if ! timer . isPending {
timer . modifyingLock . Unlock ( )
timer . runningLock . Unlock ( )
return
}
2018-05-07 20:27:03 +00:00
timer . isPending = false
2018-05-15 16:38:18 +00:00
timer . modifyingLock . Unlock ( )
2018-05-07 20:27:03 +00:00
expirationFunction ( peer )
2018-05-15 16:38:18 +00:00
timer . runningLock . Unlock ( )
2018-05-07 20:27:03 +00:00
} )
timer . timer . Stop ( )
return timer
2018-02-11 18:02:50 +00:00
}
2018-05-07 20:27:03 +00:00
func ( timer * Timer ) Mod ( d time . Duration ) {
2018-05-15 16:38:18 +00:00
timer . modifyingLock . Lock ( )
2018-05-07 20:27:03 +00:00
timer . isPending = true
timer . timer . Reset ( d )
2018-05-15 16:38:18 +00:00
timer . modifyingLock . Unlock ( )
2018-02-11 18:02:50 +00:00
}
2018-05-07 20:27:03 +00:00
func ( timer * Timer ) Del ( ) {
2018-05-15 16:38:18 +00:00
timer . modifyingLock . Lock ( )
2018-05-07 20:27:03 +00:00
timer . isPending = false
timer . timer . Stop ( )
2018-05-15 16:38:18 +00:00
timer . modifyingLock . Unlock ( )
}
func ( timer * Timer ) DelSync ( ) {
timer . Del ( )
timer . runningLock . Lock ( )
timer . Del ( )
timer . runningLock . Unlock ( )
2018-02-11 18:02:50 +00:00
}
2018-05-20 01:31:27 +00:00
func ( timer * Timer ) IsPending ( ) bool {
timer . modifyingLock . RLock ( )
defer timer . modifyingLock . RUnlock ( )
return timer . isPending
}
2018-05-07 20:27:03 +00: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 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
func expiredRetransmitHandshake ( peer * Peer ) {
2018-05-20 04:50:07 +00:00
if atomic . LoadUint32 ( & peer . timers . handshakeAttempts ) > MaxTimerHandshakes {
2018-05-07 20:27:03 +00:00
peer . device . log . Debug . Printf ( "%s: Handshake did not complete after %d attempts, giving up\n" , peer , MaxTimerHandshakes + 2 )
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00: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 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
/ * We set a timer for destroying any residue that might be left
* of a partial exchange .
* /
2018-05-20 01:31:27 +00:00
if peer . timersActive ( ) && ! peer . timers . zeroKeyMaterial . IsPending ( ) {
2018-05-07 20:27:03 +00:00
peer . timers . zeroKeyMaterial . Mod ( RejectAfterTime * 3 )
}
} else {
2018-05-20 04:50:07 +00:00
atomic . AddUint32 ( & peer . timers . handshakeAttempts , 1 )
peer . device . log . Debug . Printf ( "%s: Handshake did not complete after %d seconds, retrying (try %d)\n" , peer , int ( RekeyTimeout . Seconds ( ) ) , atomic . LoadUint32 ( & peer . timers . handshakeAttempts ) + 1 )
2018-05-07 20:27:03 +00:00
/* 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 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
peer . SendHandshakeInitiation ( true )
}
2018-02-11 18:02:50 +00:00
}
2018-05-07 20:27:03 +00:00
func expiredSendKeepalive ( peer * Peer ) {
peer . SendKeepalive ( )
2018-05-20 04:50:07 +00:00
if peer . timers . needAnotherKeepalive . Get ( ) {
peer . timers . needAnotherKeepalive . Set ( false )
2018-05-07 20:27:03 +00:00
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
}
}
2018-05-05 00:20:52 +00:00
}
2018-05-07 20:27:03 +00: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 18:02:50 +00:00
}
2018-05-07 20:27:03 +00:00
peer . mutex . Unlock ( )
peer . SendHandshakeInitiation ( false )
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
}
2018-05-05 02:15:07 +00:00
2018-05-07 20:27:03 +00: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-13 21:14:43 +00:00
peer . ZeroAndFlushAll ( )
2018-05-07 20:27:03 +00:00
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
func expiredPersistentKeepalive ( peer * Peer ) {
if peer . persistentKeepaliveInterval > 0 {
peer . SendKeepalive ( )
}
}
2018-05-05 00:20:52 +00:00
2018-05-07 20:27:03 +00:00
/* Should be called after an authenticated data packet is sent. */
func ( peer * Peer ) timersDataSent ( ) {
2018-05-20 01:31:27 +00:00
if peer . timersActive ( ) && ! peer . timers . newHandshake . IsPending ( ) {
2018-05-07 20:27:03 +00:00
peer . timers . newHandshake . Mod ( KeepaliveTimeout + RekeyTimeout )
}
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00:00
/* Should be called after an authenticated data packet is received. */
func ( peer * Peer ) timersDataReceived ( ) {
if peer . timersActive ( ) {
2018-05-20 01:31:27 +00:00
if ! peer . timers . sendKeepalive . IsPending ( ) {
2018-05-07 20:27:03 +00:00
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
} else {
2018-05-20 04:50:07 +00:00
peer . timers . needAnotherKeepalive . Set ( true )
2018-05-07 20:27:03 +00:00
}
}
}
2018-05-05 02:15:07 +00:00
2018-05-18 23:19:53 +00:00
/* Should be called after any type of authenticated packet is sent -- keepalive, data, or handshake. */
func ( peer * Peer ) timersAnyAuthenticatedPacketSent ( ) {
if peer . timersActive ( ) {
peer . timers . sendKeepalive . Del ( )
}
}
/* Should be called after any type of authenticated packet is received -- keepalive, data, or handshake. */
2018-05-07 20:27:03 +00:00
func ( peer * Peer ) timersAnyAuthenticatedPacketReceived ( ) {
if peer . timersActive ( ) {
peer . timers . newHandshake . Del ( )
}
}
2018-05-05 02:15:07 +00:00
2018-05-07 20:27:03 +00:00
/* Should be called after a handshake initiation message is sent. */
func ( peer * Peer ) timersHandshakeInitiated ( ) {
if peer . timersActive ( ) {
peer . timers . retransmitHandshake . Mod ( RekeyTimeout + time . Millisecond * time . Duration ( rand . Int31n ( RekeyTimeoutJitterMaxMs ) ) )
}
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00: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 ( )
}
2018-05-20 04:50:07 +00:00
atomic . StoreUint32 ( & peer . timers . handshakeAttempts , 0 )
peer . timers . sentLastMinuteHandshake . Set ( false )
2018-05-07 20:27:03 +00:00
atomic . StoreInt64 ( & peer . stats . lastHandshakeNano , time . Now ( ) . UnixNano ( ) )
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00: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 18:02:50 +00:00
2018-05-18 23:19:53 +00:00
/* Should be called before a packet with authentication -- keepalive, data, or handshake -- is sent, or after one is received. */
2018-05-07 20:27:03 +00:00
func ( peer * Peer ) timersAnyAuthenticatedPacketTraversal ( ) {
if peer . persistentKeepaliveInterval > 0 && peer . timersActive ( ) {
peer . timers . persistentKeepalive . Mod ( time . Duration ( peer . persistentKeepaliveInterval ) * time . Second )
}
}
2018-02-11 18:02:50 +00:00
2018-05-07 20:27:03 +00: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 )
2018-05-20 04:50:07 +00:00
atomic . StoreUint32 ( & peer . timers . handshakeAttempts , 0 )
peer . timers . sentLastMinuteHandshake . Set ( false )
peer . timers . needAnotherKeepalive . Set ( false )
2018-05-07 20:27:03 +00:00
}
2018-05-05 02:15:07 +00:00
2018-05-07 20:27:03 +00:00
func ( peer * Peer ) timersStop ( ) {
2018-05-15 16:38:18 +00:00
peer . timers . retransmitHandshake . DelSync ( )
peer . timers . sendKeepalive . DelSync ( )
peer . timers . newHandshake . DelSync ( )
peer . timers . zeroKeyMaterial . DelSync ( )
peer . timers . persistentKeepalive . DelSync ( )
2018-02-11 18:02:50 +00:00
}