github.com/koomox/wireguard-go@v0.0.0-20230722134753-17a50b2f22a3/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 }