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 }