2019-01-02 01:55:51 +01:00
/* SPDX-License-Identifier: MIT
2018-05-03 15:04:00 +02:00
*
2019-01-02 01:55:51 +01:00
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
2018-05-07 22:27:03 +02:00
*
* 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"
2018-05-15 18:38:18 +02:00
"sync"
2018-02-11 19:02:50 +01:00
"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 {
2019-01-03 19:04:00 +01:00
* time . Timer
2018-05-20 03:31:27 +02:00
modifyingLock sync . RWMutex
2018-05-15 18:38:18 +02:00
runningLock sync . Mutex
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 {}
2019-01-03 19:04:00 +01:00
timer . Timer = time . AfterFunc ( time . Hour , func () {
2018-05-15 18:38:18 +02:00
timer . runningLock . Lock ()
timer . modifyingLock . Lock ()
if ! timer . isPending {
timer . modifyingLock . Unlock ()
timer . runningLock . Unlock ()
return
}
2018-05-07 22:27:03 +02:00
timer . isPending = false
2018-05-15 18:38:18 +02:00
timer . modifyingLock . Unlock ()
2018-05-07 22:27:03 +02:00
expirationFunction ( peer )
2018-05-15 18:38:18 +02:00
timer . runningLock . Unlock ()
2018-05-07 22:27:03 +02:00
})
2019-01-03 19:04:00 +01:00
timer . Stop ()
2018-05-05 02:20:52 +02:00
return timer
}
2018-05-07 22:27:03 +02:00
func ( timer * Timer ) Mod ( d time . Duration ) {
2018-05-15 18:38:18 +02:00
timer . modifyingLock . Lock ()
2018-05-07 22:27:03 +02:00
timer . isPending = true
2019-01-03 19:04:00 +01:00
timer . Reset ( d )
2018-05-15 18:38:18 +02:00
timer . modifyingLock . Unlock ()
2018-05-07 22:27:03 +02:00
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
func ( timer * Timer ) Del () {
2018-05-15 18:38:18 +02:00
timer . modifyingLock . Lock ()
2018-05-07 22:27:03 +02:00
timer . isPending = false
2019-01-03 19:04:00 +01:00
timer . Stop ()
2018-05-15 18:38:18 +02:00
timer . modifyingLock . Unlock ()
}
func ( timer * Timer ) DelSync () {
timer . Del ()
timer . runningLock . Lock ()
timer . Del ()
timer . runningLock . Unlock ()
2018-05-07 22:27:03 +02:00
}
2018-02-11 19:02:50 +01:00
2018-05-20 03:31:27 +02:00
func ( timer * Timer ) IsPending () bool {
timer . modifyingLock . RLock ()
defer timer . modifyingLock . RUnlock ()
return timer . isPending
}
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-04-18 20:29:48 +02:00
2018-05-07 22:27:03 +02:00
func expiredRetransmitHandshake ( peer * Peer ) {
2018-05-20 06:50:07 +02:00
if atomic . LoadUint32 ( & peer . timers . handshakeAttempts ) > MaxTimerHandshakes {
2018-12-19 00:35:53 +01:00
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-05-01 16:59:13 +02: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.
*/
2018-05-20 03:31:27 +02:00
if peer . timersActive () && ! peer . timers . zeroKeyMaterial . IsPending () {
2018-05-07 22:27:03 +02:00
peer . timers . zeroKeyMaterial . Mod ( RejectAfterTime * 3 )
}
} else {
2018-05-20 06:50:07 +02:00
atomic . AddUint32 ( & peer . timers . handshakeAttempts , 1 )
2018-12-19 00:35:53 +01:00
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-05 02:20:52 +02:00
2018-05-07 22:27:03 +02:00
/* We clear the endpoint address src address, in case this is the cause of trouble. */
2019-01-03 19:04:00 +01:00
peer . Lock ()
2018-05-07 22:27:03 +02:00
if peer . endpoint != nil {
peer . endpoint . ClearSrc ()
}
2019-01-03 19:04:00 +01:00
peer . 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
}
2018-02-11 19:02:50 +01:00
2018-05-07 22:27:03 +02:00
func expiredSendKeepalive ( peer * Peer ) {
peer . SendKeepalive ()
2018-05-20 06:50:07 +02:00
if peer . timers . needAnotherKeepalive . Get () {
peer . timers . needAnotherKeepalive . Set ( false )
2018-05-07 22:27:03 +02:00
if peer . timersActive () {
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
2018-02-11 19:02:50 +01:00
}
}
}
2018-05-07 22:27:03 +02:00
func expiredNewHandshake ( peer * Peer ) {
2018-12-19 00:35:53 +01:00
peer . device . log . Debug . Printf ( "%s - Retrying handshake because we stopped hearing back after %d seconds\n" , peer , int (( KeepaliveTimeout + RekeyTimeout ). Seconds ()))
2018-05-07 22:27:03 +02:00
/* We clear the endpoint address src address, in case this is the cause of trouble. */
2019-01-03 19:04:00 +01:00
peer . Lock ()
2018-05-07 22:27:03 +02:00
if peer . endpoint != nil {
peer . endpoint . ClearSrc ()
}
2019-01-03 19:04:00 +01:00
peer . Unlock ()
2018-05-07 22:27:03 +02:00
peer . SendHandshakeInitiation ( false )
}
func expiredZeroKeyMaterial ( peer * Peer ) {
2018-12-19 00:35:53 +01:00
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 23:14:43 +02:00
peer . ZeroAndFlushAll ()
2018-05-07 22:27:03 +02:00
}
func expiredPersistentKeepalive ( peer * Peer ) {
if peer . persistentKeepaliveInterval > 0 {
peer . SendKeepalive ()
}
}
/* Should be called after an authenticated data packet is sent. */
func ( peer * Peer ) timersDataSent () {
2018-05-20 03:31:27 +02:00
if peer . timersActive () && ! peer . timers . newHandshake . IsPending () {
2018-05-07 22:27:03 +02:00
peer . timers . newHandshake . Mod ( KeepaliveTimeout + RekeyTimeout )
}
}
/* Should be called after an authenticated data packet is received. */
func ( peer * Peer ) timersDataReceived () {
if peer . timersActive () {
2018-05-20 03:31:27 +02:00
if ! peer . timers . sendKeepalive . IsPending () {
2018-05-07 22:27:03 +02:00
peer . timers . sendKeepalive . Mod ( KeepaliveTimeout )
} else {
2018-05-20 06:50:07 +02:00
peer . timers . needAnotherKeepalive . Set ( true )
2018-05-07 22:27:03 +02:00
}
}
}
2018-05-19 01:19:53 +02: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 22:27:03 +02:00
func ( peer * Peer ) timersAnyAuthenticatedPacketReceived () {
if peer . timersActive () {
peer . timers . newHandshake . Del ()
}
}
/* 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 )))
}
}
/* 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 06:50:07 +02:00
atomic . StoreUint32 ( & peer . timers . handshakeAttempts , 0 )
peer . timers . sentLastMinuteHandshake . Set ( false )
2018-05-07 22:27:03 +02:00
atomic . StoreInt64 ( & peer . stats . lastHandshakeNano , time . Now (). UnixNano ())
}
/* 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-05-19 01:19:53 +02:00
/* Should be called before a packet with authentication -- keepalive, data, or handshake -- is sent, or after one is received. */
2018-05-07 22:27:03 +02:00
func ( peer * Peer ) timersAnyAuthenticatedPacketTraversal () {
if peer . persistentKeepaliveInterval > 0 && peer . timersActive () {
peer . timers . persistentKeepalive . Mod ( time . Duration ( peer . persistentKeepaliveInterval ) * time . Second )
}
}
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 06:50:07 +02:00
atomic . StoreUint32 ( & peer . timers . handshakeAttempts , 0 )
peer . timers . sentLastMinuteHandshake . Set ( false )
peer . timers . needAnotherKeepalive . Set ( false )
2018-05-07 22:27:03 +02:00
}
func ( peer * Peer ) timersStop () {
2018-05-15 18:38:18 +02:00
peer . timers . retransmitHandshake . DelSync ()
peer . timers . sendKeepalive . DelSync ()
peer . timers . newHandshake . DelSync ()
peer . timers . zeroKeyMaterial . DelSync ()
peer . timers . persistentKeepalive . DelSync ()
2018-05-07 22:27:03 +02:00
}