github.com/liloew/wireguard-go@v0.0.0-20220224014633-9cd745e6f114/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 "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 }