github.com/cawidtu/notwireguard-go/device@v0.0.0-20230523131112-68e8e5ce9cdf/timers.go (about)

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