timers.go raw

   1  /* SPDX-License-Identifier: MIT
   2   *
   3   * Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved.
   4   *
   5   * This is based heavily on timers.c from the kernel implementation.
   6   */
   7  
   8  package device
   9  
  10  import (
  11  	"sync"
  12  	"time"
  13  	_ "unsafe"
  14  )
  15  
  16  //go:linkname fastrandn runtime.fastrandn
  17  func fastrandn(n uint32) uint32
  18  
  19  // A Timer manages time-based aspects of the WireGuard protocol.
  20  // Timer roughly copies the interface of the Linux kernel's struct timer_list.
  21  type Timer struct {
  22  	*time.Timer
  23  	modifyingLock sync.RWMutex
  24  	runningLock   sync.Mutex
  25  	isPending     bool
  26  }
  27  
  28  func (peer *Peer) NewTimer(expirationFunction func(*Peer)) *Timer {
  29  	timer := &Timer{}
  30  	timer.Timer = time.AfterFunc(time.Hour, func() {
  31  		timer.runningLock.Lock()
  32  		defer timer.runningLock.Unlock()
  33  
  34  		timer.modifyingLock.Lock()
  35  		if !timer.isPending {
  36  			timer.modifyingLock.Unlock()
  37  			return
  38  		}
  39  		timer.isPending = false
  40  		timer.modifyingLock.Unlock()
  41  
  42  		expirationFunction(peer)
  43  	})
  44  	timer.Stop()
  45  	return timer
  46  }
  47  
  48  func (timer *Timer) Mod(d time.Duration) {
  49  	timer.modifyingLock.Lock()
  50  	timer.isPending = true
  51  	timer.Reset(d)
  52  	timer.modifyingLock.Unlock()
  53  }
  54  
  55  func (timer *Timer) Del() {
  56  	timer.modifyingLock.Lock()
  57  	timer.isPending = false
  58  	timer.Stop()
  59  	timer.modifyingLock.Unlock()
  60  }
  61  
  62  func (timer *Timer) DelSync() {
  63  	timer.Del()
  64  	timer.runningLock.Lock()
  65  	timer.Del()
  66  	timer.runningLock.Unlock()
  67  }
  68  
  69  func (timer *Timer) IsPending() bool {
  70  	timer.modifyingLock.RLock()
  71  	defer timer.modifyingLock.RUnlock()
  72  	return timer.isPending
  73  }
  74  
  75  func (peer *Peer) timersActive() bool {
  76  	return peer.isRunning.Load() && peer.device != nil && peer.device.isUp()
  77  }
  78  
  79  func expiredRetransmitHandshake(peer *Peer) {
  80  	if peer.timers.handshakeAttempts.Load() > MaxTimerHandshakes {
  81  		peer.device.log.Verbosef("%s - Handshake did not complete after %d attempts, giving up", peer, MaxTimerHandshakes+2)
  82  
  83  		if peer.timersActive() {
  84  			peer.timers.sendKeepalive.Del()
  85  		}
  86  
  87  		/* We drop all packets without a keypair and don't try again,
  88  		 * if we try unsuccessfully for too long to make a handshake.
  89  		 */
  90  		peer.FlushStagedPackets()
  91  
  92  		/* We set a timer for destroying any residue that might be left
  93  		 * of a partial exchange.
  94  		 */
  95  		if peer.timersActive() && !peer.timers.zeroKeyMaterial.IsPending() {
  96  			peer.timers.zeroKeyMaterial.Mod(RejectAfterTime * 3)
  97  		}
  98  	} else {
  99  		peer.timers.handshakeAttempts.Add(1)
 100  		peer.device.log.Verbosef("%s - Handshake did not complete after %d seconds, retrying (try %d)", peer, int(RekeyTimeout.Seconds()), peer.timers.handshakeAttempts.Load()+1)
 101  
 102  		/* We clear the endpoint address src address, in case this is the cause of trouble. */
 103  		peer.markEndpointSrcForClearing()
 104  
 105  		peer.SendHandshakeInitiation(true)
 106  	}
 107  }
 108  
 109  func expiredSendKeepalive(peer *Peer) {
 110  	peer.SendKeepalive()
 111  	if peer.timers.needAnotherKeepalive.Load() {
 112  		peer.timers.needAnotherKeepalive.Store(false)
 113  		if peer.timersActive() {
 114  			peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
 115  		}
 116  	}
 117  }
 118  
 119  func expiredNewHandshake(peer *Peer) {
 120  	peer.device.log.Verbosef("%s - Retrying handshake because we stopped hearing back after %d seconds", peer, int((KeepaliveTimeout + RekeyTimeout).Seconds()))
 121  	/* We clear the endpoint address src address, in case this is the cause of trouble. */
 122  	peer.markEndpointSrcForClearing()
 123  	peer.SendHandshakeInitiation(false)
 124  }
 125  
 126  func expiredZeroKeyMaterial(peer *Peer) {
 127  	peer.device.log.Verbosef("%s - Removing all keys, since we haven't received a new one in %d seconds", peer, int((RejectAfterTime * 3).Seconds()))
 128  	peer.ZeroAndFlushAll()
 129  }
 130  
 131  func expiredPersistentKeepalive(peer *Peer) {
 132  	if peer.persistentKeepaliveInterval.Load() > 0 {
 133  		peer.SendKeepalive()
 134  	}
 135  }
 136  
 137  /* Should be called after an authenticated data packet is sent. */
 138  func (peer *Peer) timersDataSent() {
 139  	if peer.timersActive() && !peer.timers.newHandshake.IsPending() {
 140  		peer.timers.newHandshake.Mod(KeepaliveTimeout + RekeyTimeout + time.Millisecond*time.Duration(fastrandn(RekeyTimeoutJitterMaxMs)))
 141  	}
 142  }
 143  
 144  /* Should be called after an authenticated data packet is received. */
 145  func (peer *Peer) timersDataReceived() {
 146  	if peer.timersActive() {
 147  		if !peer.timers.sendKeepalive.IsPending() {
 148  			peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
 149  		} else {
 150  			peer.timers.needAnotherKeepalive.Store(true)
 151  		}
 152  	}
 153  }
 154  
 155  /* Should be called after any type of authenticated packet is sent -- keepalive, data, or handshake. */
 156  func (peer *Peer) timersAnyAuthenticatedPacketSent() {
 157  	if peer.timersActive() {
 158  		peer.timers.sendKeepalive.Del()
 159  	}
 160  }
 161  
 162  /* Should be called after any type of authenticated packet is received -- keepalive, data, or handshake. */
 163  func (peer *Peer) timersAnyAuthenticatedPacketReceived() {
 164  	if peer.timersActive() {
 165  		peer.timers.newHandshake.Del()
 166  	}
 167  }
 168  
 169  /* Should be called after a handshake initiation message is sent. */
 170  func (peer *Peer) timersHandshakeInitiated() {
 171  	if peer.timersActive() {
 172  		peer.timers.retransmitHandshake.Mod(RekeyTimeout + time.Millisecond*time.Duration(fastrandn(RekeyTimeoutJitterMaxMs)))
 173  	}
 174  }
 175  
 176  /* Should be called after a handshake response message is received and processed or when getting key confirmation via the first data message. */
 177  func (peer *Peer) timersHandshakeComplete() {
 178  	if peer.timersActive() {
 179  		peer.timers.retransmitHandshake.Del()
 180  	}
 181  	peer.timers.handshakeAttempts.Store(0)
 182  	peer.timers.sentLastMinuteHandshake.Store(false)
 183  	peer.lastHandshakeNano.Store(time.Now().UnixNano())
 184  }
 185  
 186  /* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */
 187  func (peer *Peer) timersSessionDerived() {
 188  	if peer.timersActive() {
 189  		peer.timers.zeroKeyMaterial.Mod(RejectAfterTime * 3)
 190  	}
 191  }
 192  
 193  /* Should be called before a packet with authentication -- keepalive, data, or handshake -- is sent, or after one is received. */
 194  func (peer *Peer) timersAnyAuthenticatedPacketTraversal() {
 195  	keepalive := peer.persistentKeepaliveInterval.Load()
 196  	if keepalive > 0 && peer.timersActive() {
 197  		peer.timers.persistentKeepalive.Mod(time.Duration(keepalive) * time.Second)
 198  	}
 199  }
 200  
 201  func (peer *Peer) timersInit() {
 202  	peer.timers.retransmitHandshake = peer.NewTimer(expiredRetransmitHandshake)
 203  	peer.timers.sendKeepalive = peer.NewTimer(expiredSendKeepalive)
 204  	peer.timers.newHandshake = peer.NewTimer(expiredNewHandshake)
 205  	peer.timers.zeroKeyMaterial = peer.NewTimer(expiredZeroKeyMaterial)
 206  	peer.timers.persistentKeepalive = peer.NewTimer(expiredPersistentKeepalive)
 207  }
 208  
 209  func (peer *Peer) timersStart() {
 210  	peer.timers.handshakeAttempts.Store(0)
 211  	peer.timers.sentLastMinuteHandshake.Store(false)
 212  	peer.timers.needAnotherKeepalive.Store(false)
 213  }
 214  
 215  func (peer *Peer) timersStop() {
 216  	peer.timers.retransmitHandshake.DelSync()
 217  	peer.timers.sendKeepalive.DelSync()
 218  	peer.timers.newHandshake.DelSync()
 219  	peer.timers.zeroKeyMaterial.DelSync()
 220  	peer.timers.persistentKeepalive.DelSync()
 221  }
 222