github.com/sagernet/wireguard-go@v0.0.0-20231215174105-89dec3b2f3e8/device/timers.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2023 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.Lock()
   104  		if peer.endpoint != nil {
   105  			peer.endpoint.ClearSrc()
   106  		}
   107  		peer.Unlock()
   108  
   109  		peer.SendHandshakeInitiation(true)
   110  	}
   111  }
   112  
   113  func expiredSendKeepalive(peer *Peer) {
   114  	peer.SendKeepalive()
   115  	if peer.timers.needAnotherKeepalive.Load() {
   116  		peer.timers.needAnotherKeepalive.Store(false)
   117  		if peer.timersActive() {
   118  			peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
   119  		}
   120  	}
   121  }
   122  
   123  func expiredNewHandshake(peer *Peer) {
   124  	peer.device.log.Verbosef("%s - Retrying handshake because we stopped hearing back after %d seconds", peer, int((KeepaliveTimeout + RekeyTimeout).Seconds()))
   125  	/* We clear the endpoint address src address, in case this is the cause of trouble. */
   126  	peer.Lock()
   127  	if peer.endpoint != nil {
   128  		peer.endpoint.ClearSrc()
   129  	}
   130  	peer.Unlock()
   131  	peer.SendHandshakeInitiation(false)
   132  }
   133  
   134  func expiredZeroKeyMaterial(peer *Peer) {
   135  	peer.device.log.Verbosef("%s - Removing all keys, since we haven't received a new one in %d seconds", peer, int((RejectAfterTime * 3).Seconds()))
   136  	peer.ZeroAndFlushAll()
   137  }
   138  
   139  func expiredPersistentKeepalive(peer *Peer) {
   140  	if peer.persistentKeepaliveInterval.Load() > 0 {
   141  		peer.SendKeepalive()
   142  	}
   143  }
   144  
   145  /* Should be called after an authenticated data packet is sent. */
   146  func (peer *Peer) timersDataSent() {
   147  	if peer.timersActive() && !peer.timers.newHandshake.IsPending() {
   148  		peer.timers.newHandshake.Mod(KeepaliveTimeout + RekeyTimeout + time.Millisecond*time.Duration(fastrandn(RekeyTimeoutJitterMaxMs)))
   149  	}
   150  }
   151  
   152  /* Should be called after an authenticated data packet is received. */
   153  func (peer *Peer) timersDataReceived() {
   154  	if peer.timersActive() {
   155  		if !peer.timers.sendKeepalive.IsPending() {
   156  			peer.timers.sendKeepalive.Mod(KeepaliveTimeout)
   157  		} else {
   158  			peer.timers.needAnotherKeepalive.Store(true)
   159  		}
   160  	}
   161  }
   162  
   163  /* Should be called after any type of authenticated packet is sent -- keepalive, data, or handshake. */
   164  func (peer *Peer) timersAnyAuthenticatedPacketSent() {
   165  	if peer.timersActive() {
   166  		peer.timers.sendKeepalive.Del()
   167  	}
   168  }
   169  
   170  /* Should be called after any type of authenticated packet is received -- keepalive, data, or handshake. */
   171  func (peer *Peer) timersAnyAuthenticatedPacketReceived() {
   172  	if peer.timersActive() {
   173  		peer.timers.newHandshake.Del()
   174  	}
   175  }
   176  
   177  /* Should be called after a handshake initiation message is sent. */
   178  func (peer *Peer) timersHandshakeInitiated() {
   179  	if peer.timersActive() {
   180  		peer.timers.retransmitHandshake.Mod(RekeyTimeout + time.Millisecond*time.Duration(fastrandn(RekeyTimeoutJitterMaxMs)))
   181  	}
   182  }
   183  
   184  /* Should be called after a handshake response message is received and processed or when getting key confirmation via the first data message. */
   185  func (peer *Peer) timersHandshakeComplete() {
   186  	if peer.timersActive() {
   187  		peer.timers.retransmitHandshake.Del()
   188  	}
   189  	peer.timers.handshakeAttempts.Store(0)
   190  	peer.timers.sentLastMinuteHandshake.Store(false)
   191  	peer.lastHandshakeNano.Store(time.Now().UnixNano())
   192  }
   193  
   194  /* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */
   195  func (peer *Peer) timersSessionDerived() {
   196  	if peer.timersActive() {
   197  		peer.timers.zeroKeyMaterial.Mod(RejectAfterTime * 3)
   198  	}
   199  }
   200  
   201  /* Should be called before a packet with authentication -- keepalive, data, or handshake -- is sent, or after one is received. */
   202  func (peer *Peer) timersAnyAuthenticatedPacketTraversal() {
   203  	keepalive := peer.persistentKeepaliveInterval.Load()
   204  	if keepalive > 0 && peer.timersActive() {
   205  		peer.timers.persistentKeepalive.Mod(time.Duration(keepalive) * time.Second)
   206  	}
   207  }
   208  
   209  func (peer *Peer) timersInit() {
   210  	peer.timers.retransmitHandshake = peer.NewTimer(expiredRetransmitHandshake)
   211  	peer.timers.sendKeepalive = peer.NewTimer(expiredSendKeepalive)
   212  	peer.timers.newHandshake = peer.NewTimer(expiredNewHandshake)
   213  	peer.timers.zeroKeyMaterial = peer.NewTimer(expiredZeroKeyMaterial)
   214  	peer.timers.persistentKeepalive = peer.NewTimer(expiredPersistentKeepalive)
   215  }
   216  
   217  func (peer *Peer) timersStart() {
   218  	peer.timers.handshakeAttempts.Store(0)
   219  	peer.timers.sentLastMinuteHandshake.Store(false)
   220  	peer.timers.needAnotherKeepalive.Store(false)
   221  }
   222  
   223  func (peer *Peer) timersStop() {
   224  	peer.timers.retransmitHandshake.DelSync()
   225  	peer.timers.sendKeepalive.DelSync()
   226  	peer.timers.newHandshake.DelSync()
   227  	peer.timers.zeroKeyMaterial.DelSync()
   228  	peer.timers.persistentKeepalive.DelSync()
   229  }