github.com/liloew/wireguard-go@v0.0.0-20220224014633-9cd745e6f114/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/liloew/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 // init timers 111 peer.timersInit() 112 113 // add 114 device.peers.keyMap[pk] = peer 115 116 return peer, nil 117 } 118 119 func (peer *Peer) SendBuffer(buffer []byte) error { 120 peer.device.net.RLock() 121 defer peer.device.net.RUnlock() 122 123 if peer.device.isClosed() { 124 return nil 125 } 126 127 peer.RLock() 128 defer peer.RUnlock() 129 130 if peer.endpoint == nil { 131 return errors.New("no known endpoint for peer") 132 } 133 134 err := peer.device.net.bind.Send(buffer, peer.endpoint) 135 if err == nil { 136 atomic.AddUint64(&peer.stats.txBytes, uint64(len(buffer))) 137 } 138 return err 139 } 140 141 func (peer *Peer) String() string { 142 // The awful goo that follows is identical to: 143 // 144 // base64Key := base64.StdEncoding.EncodeToString(peer.handshake.remoteStatic[:]) 145 // abbreviatedKey := base64Key[0:4] + "…" + base64Key[39:43] 146 // return fmt.Sprintf("peer(%s)", abbreviatedKey) 147 // 148 // except that it is considerably more efficient. 149 src := peer.handshake.remoteStatic 150 b64 := func(input byte) byte { 151 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) 152 } 153 b := []byte("peer(____…____)") 154 const first = len("peer(") 155 const second = len("peer(____…") 156 b[first+0] = b64((src[0] >> 2) & 63) 157 b[first+1] = b64(((src[0] << 4) | (src[1] >> 4)) & 63) 158 b[first+2] = b64(((src[1] << 2) | (src[2] >> 6)) & 63) 159 b[first+3] = b64(src[2] & 63) 160 b[second+0] = b64(src[29] & 63) 161 b[second+1] = b64((src[30] >> 2) & 63) 162 b[second+2] = b64(((src[30] << 4) | (src[31] >> 4)) & 63) 163 b[second+3] = b64((src[31] << 2) & 63) 164 return string(b) 165 } 166 167 func (peer *Peer) Start() { 168 // should never start a peer on a closed device 169 if peer.device.isClosed() { 170 return 171 } 172 173 // prevent simultaneous start/stop operations 174 peer.state.Lock() 175 defer peer.state.Unlock() 176 177 if peer.isRunning.Get() { 178 return 179 } 180 181 device := peer.device 182 device.log.Verbosef("%v - Starting", peer) 183 184 // reset routine state 185 peer.stopping.Wait() 186 peer.stopping.Add(2) 187 188 peer.handshake.mutex.Lock() 189 peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second)) 190 peer.handshake.mutex.Unlock() 191 192 peer.device.queue.encryption.wg.Add(1) // keep encryption queue open for our writes 193 194 peer.timersStart() 195 196 device.flushInboundQueue(peer.queue.inbound) 197 device.flushOutboundQueue(peer.queue.outbound) 198 go peer.RoutineSequentialSender() 199 go peer.RoutineSequentialReceiver() 200 201 peer.isRunning.Set(true) 202 } 203 204 func (peer *Peer) ZeroAndFlushAll() { 205 device := peer.device 206 207 // clear key pairs 208 209 keypairs := &peer.keypairs 210 keypairs.Lock() 211 device.DeleteKeypair(keypairs.previous) 212 device.DeleteKeypair(keypairs.current) 213 device.DeleteKeypair(keypairs.loadNext()) 214 keypairs.previous = nil 215 keypairs.current = nil 216 keypairs.storeNext(nil) 217 keypairs.Unlock() 218 219 // clear handshake state 220 221 handshake := &peer.handshake 222 handshake.mutex.Lock() 223 device.indexTable.Delete(handshake.localIndex) 224 handshake.Clear() 225 handshake.mutex.Unlock() 226 227 peer.FlushStagedPackets() 228 } 229 230 func (peer *Peer) ExpireCurrentKeypairs() { 231 handshake := &peer.handshake 232 handshake.mutex.Lock() 233 peer.device.indexTable.Delete(handshake.localIndex) 234 handshake.Clear() 235 peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second)) 236 handshake.mutex.Unlock() 237 238 keypairs := &peer.keypairs 239 keypairs.Lock() 240 if keypairs.current != nil { 241 atomic.StoreUint64(&keypairs.current.sendNonce, RejectAfterMessages) 242 } 243 if keypairs.next != nil { 244 next := keypairs.loadNext() 245 atomic.StoreUint64(&next.sendNonce, RejectAfterMessages) 246 } 247 keypairs.Unlock() 248 } 249 250 func (peer *Peer) Stop() { 251 peer.state.Lock() 252 defer peer.state.Unlock() 253 254 if !peer.isRunning.Swap(false) { 255 return 256 } 257 258 peer.device.log.Verbosef("%v - Stopping", peer) 259 260 peer.timersStop() 261 // Signal that RoutineSequentialSender and RoutineSequentialReceiver should exit. 262 peer.queue.inbound.c <- nil 263 peer.queue.outbound.c <- nil 264 peer.stopping.Wait() 265 peer.device.queue.encryption.wg.Done() // no more writes to encryption queue from us 266 267 peer.ZeroAndFlushAll() 268 } 269 270 func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) { 271 if peer.disableRoaming { 272 return 273 } 274 peer.Lock() 275 peer.endpoint = endpoint 276 peer.Unlock() 277 }