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