github.com/bugfan/wireguard-go@v0.0.0-20230720020150-a7b2fa340c66/device/peer.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package device 7 8 import ( 9 "container/list" 10 "errors" 11 "sync" 12 "sync/atomic" 13 "time" 14 15 "github.com/bugfan/wireguard-go/conn" 16 ) 17 18 type Peer struct { 19 isRunning AtomicBool 20 sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer 21 keypairs Keypairs 22 handshake Handshake 23 device *Device 24 endpoint conn.Endpoint 25 stopping sync.WaitGroup // routines pending stop 26 27 // These fields are accessed with atomic operations, which must be 28 // 64-bit aligned even on 32-bit platforms. Go guarantees that an 29 // allocated struct will be 64-bit aligned. So we place 30 // atomically-accessed fields up front, so that they can share in 31 // this alignment before smaller fields throw it off. 32 stats struct { 33 txBytes uint64 // bytes send to peer (endpoint) 34 rxBytes uint64 // bytes received from peer 35 lastHandshakeNano int64 // nano seconds since epoch 36 } 37 38 disableRoaming bool 39 40 timers struct { 41 retransmitHandshake *Timer 42 sendKeepalive *Timer 43 newHandshake *Timer 44 zeroKeyMaterial *Timer 45 persistentKeepalive *Timer 46 handshakeAttempts uint32 47 needAnotherKeepalive AtomicBool 48 sentLastMinuteHandshake AtomicBool 49 } 50 51 state struct { 52 sync.Mutex // protects against concurrent Start/Stop 53 } 54 55 queue struct { 56 staged chan *QueueOutboundElement // staged packets before a handshake is available 57 outbound *autodrainingOutboundQueue // sequential ordering of udp transmission 58 inbound *autodrainingInboundQueue // sequential ordering of tun writing 59 } 60 61 cookieGenerator CookieGenerator 62 trieEntries list.List 63 persistentKeepaliveInterval uint32 // accessed atomically 64 } 65 66 func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) { 67 if device.isClosed() { 68 return nil, errors.New("device closed") 69 } 70 71 // lock resources 72 device.staticIdentity.RLock() 73 defer device.staticIdentity.RUnlock() 74 75 device.peers.Lock() 76 defer device.peers.Unlock() 77 78 // check if over limit 79 if len(device.peers.keyMap) >= MaxPeers { 80 return nil, errors.New("too many peers") 81 } 82 83 // create peer 84 peer := new(Peer) 85 peer.Lock() 86 defer peer.Unlock() 87 88 peer.cookieGenerator.Init(pk) 89 peer.device = device 90 peer.queue.outbound = newAutodrainingOutboundQueue(device) 91 peer.queue.inbound = newAutodrainingInboundQueue(device) 92 peer.queue.staged = make(chan *QueueOutboundElement, QueueStagedSize) 93 94 // map public key 95 _, ok := device.peers.keyMap[pk] 96 if ok { 97 return nil, errors.New("adding existing peer") 98 } 99 100 // pre-compute DH 101 handshake := &peer.handshake 102 handshake.mutex.Lock() 103 handshake.precomputedStaticStatic = device.staticIdentity.privateKey.sharedSecret(pk) 104 handshake.remoteStatic = pk 105 handshake.mutex.Unlock() 106 107 // reset endpoint 108 peer.endpoint = nil 109 110 // add 111 device.peers.keyMap[pk] = peer 112 113 // start peer 114 peer.timersInit() 115 if peer.device.isUp() { 116 peer.Start() 117 } 118 119 return peer, nil 120 } 121 122 func (peer *Peer) SendBuffer(buffer []byte) error { 123 peer.device.net.RLock() 124 defer peer.device.net.RUnlock() 125 126 if peer.device.isClosed() { 127 return nil 128 } 129 130 peer.RLock() 131 defer peer.RUnlock() 132 133 if peer.endpoint == nil { 134 return errors.New("no known endpoint for peer") 135 } 136 137 err := peer.device.net.bind.Send(buffer, peer.endpoint) 138 if err == nil { 139 atomic.AddUint64(&peer.stats.txBytes, uint64(len(buffer))) 140 } 141 return err 142 } 143 144 func (peer *Peer) String() string { 145 // The awful goo that follows is identical to: 146 // 147 // base64Key := base64.StdEncoding.EncodeToString(peer.handshake.remoteStatic[:]) 148 // abbreviatedKey := base64Key[0:4] + "…" + base64Key[39:43] 149 // return fmt.Sprintf("peer(%s)", abbreviatedKey) 150 // 151 // except that it is considerably more efficient. 152 src := peer.handshake.remoteStatic 153 b64 := func(input byte) byte { 154 return input + 'A' + byte(((25-int(input))>>8)&6) - byte(((51-int(input))>>8)&75) - byte(((61-int(input))>>8)&15) + byte(((62-int(input))>>8)&3) 155 } 156 157 b := []byte("peer(____…____)") 158 const first = len("peer(") 159 const second = len("peer(____…") 160 b[first+0] = b64((src[0] >> 2) & 63) 161 b[first+1] = b64(((src[0] << 4) | (src[1] >> 4)) & 63) 162 b[first+2] = b64(((src[1] << 2) | (src[2] >> 6)) & 63) 163 b[first+3] = b64(src[2] & 63) 164 b[second+0] = b64(src[29] & 63) 165 b[second+1] = b64((src[30] >> 2) & 63) 166 b[second+2] = b64(((src[30] << 4) | (src[31] >> 4)) & 63) 167 b[second+3] = b64((src[31] << 2) & 63) 168 return string(b) 169 } 170 171 func (peer *Peer) Start() { 172 // should never start a peer on a closed device 173 if peer.device.isClosed() { 174 return 175 } 176 177 // prevent simultaneous start/stop operations 178 peer.state.Lock() 179 defer peer.state.Unlock() 180 181 if peer.isRunning.Get() { 182 return 183 } 184 185 device := peer.device 186 device.log.Verbosef("%v - Starting", peer) 187 188 // reset routine state 189 peer.stopping.Wait() 190 peer.stopping.Add(2) 191 192 peer.handshake.mutex.Lock() 193 peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second)) 194 peer.handshake.mutex.Unlock() 195 196 peer.device.queue.encryption.wg.Add(1) // keep encryption queue open for our writes 197 198 peer.timersStart() 199 200 device.flushInboundQueue(peer.queue.inbound) 201 device.flushOutboundQueue(peer.queue.outbound) 202 go peer.RoutineSequentialSender() 203 go peer.RoutineSequentialReceiver() 204 205 peer.isRunning.Set(true) 206 } 207 208 func (peer *Peer) ZeroAndFlushAll() { 209 device := peer.device 210 211 // clear key pairs 212 213 keypairs := &peer.keypairs 214 keypairs.Lock() 215 device.DeleteKeypair(keypairs.previous) 216 device.DeleteKeypair(keypairs.current) 217 device.DeleteKeypair(keypairs.loadNext()) 218 keypairs.previous = nil 219 keypairs.current = nil 220 keypairs.storeNext(nil) 221 keypairs.Unlock() 222 223 // clear handshake state 224 225 handshake := &peer.handshake 226 handshake.mutex.Lock() 227 device.indexTable.Delete(handshake.localIndex) 228 handshake.Clear() 229 handshake.mutex.Unlock() 230 231 peer.FlushStagedPackets() 232 } 233 234 func (peer *Peer) ExpireCurrentKeypairs() { 235 handshake := &peer.handshake 236 handshake.mutex.Lock() 237 peer.device.indexTable.Delete(handshake.localIndex) 238 handshake.Clear() 239 peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second)) 240 handshake.mutex.Unlock() 241 242 keypairs := &peer.keypairs 243 keypairs.Lock() 244 if keypairs.current != nil { 245 atomic.StoreUint64(&keypairs.current.sendNonce, RejectAfterMessages) 246 } 247 if keypairs.next != nil { 248 next := keypairs.loadNext() 249 atomic.StoreUint64(&next.sendNonce, RejectAfterMessages) 250 } 251 keypairs.Unlock() 252 } 253 254 func (peer *Peer) Stop() { 255 peer.state.Lock() 256 defer peer.state.Unlock() 257 258 if !peer.isRunning.Swap(false) { 259 return 260 } 261 262 peer.device.log.Verbosef("%v - Stopping", peer) 263 264 peer.timersStop() 265 // Signal that RoutineSequentialSender and RoutineSequentialReceiver should exit. 266 peer.queue.inbound.c <- nil 267 peer.queue.outbound.c <- nil 268 peer.stopping.Wait() 269 peer.device.queue.encryption.wg.Done() // no more writes to encryption queue from us 270 271 peer.ZeroAndFlushAll() 272 } 273 274 func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) { 275 if peer.disableRoaming { 276 return 277 } 278 peer.Lock() 279 peer.endpoint = endpoint 280 peer.Unlock() 281 }