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