github.com/cawidtu/notwireguard-go/device@v0.0.0-20230523131112-68e8e5ce9cdf/send.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 "bytes" 10 "encoding/binary" 11 "errors" 12 "net" 13 "os" 14 "sync" 15 "sync/atomic" 16 "time" 17 "math/rand" 18 "github.com/aead/chacha20" 19 "golang.org/x/crypto/chacha20poly1305" 20 "golang.org/x/net/ipv4" 21 "golang.org/x/net/ipv6" 22 ) 23 24 /* Outbound flow 25 * 26 * 1. TUN queue 27 * 2. Routing (sequential) 28 * 3. Nonce assignment (sequential) 29 * 4. Encryption (parallel) 30 * 5. Transmission (sequential) 31 * 32 * The functions in this file occur (roughly) in the order in 33 * which the packets are processed. 34 * 35 * Locking, Producers and Consumers 36 * 37 * The order of packets (per peer) must be maintained, 38 * but encryption of packets happen out-of-order: 39 * 40 * The sequential consumers will attempt to take the lock, 41 * workers release lock when they have completed work (encryption) on the packet. 42 * 43 * If the element is inserted into the "encryption queue", 44 * the content is preceded by enough "junk" to contain the transport header 45 * (to allow the construction of transport messages in-place) 46 */ 47 48 type QueueOutboundElement struct { 49 sync.Mutex 50 buffer *[MaxMessageSize]byte // slice holding the packet data 51 packet []byte // slice of "buffer" (always!) 52 nonce uint64 // nonce for encryption 53 keypair *Keypair // keypair for encryption 54 peer *Peer // related peer 55 } 56 57 func (device *Device) NewOutboundElement() *QueueOutboundElement { 58 elem := device.GetOutboundElement() 59 elem.buffer = device.GetMessageBuffer() 60 elem.Mutex = sync.Mutex{} 61 elem.nonce = 0 62 // keypair and peer were cleared (if necessary) by clearPointers. 63 return elem 64 } 65 66 // clearPointers clears elem fields that contain pointers. 67 // This makes the garbage collector's life easier and 68 // avoids accidentally keeping other objects around unnecessarily. 69 // It also reduces the possible collateral damage from use-after-free bugs. 70 func (elem *QueueOutboundElement) clearPointers() { 71 elem.buffer = nil 72 elem.packet = nil 73 elem.keypair = nil 74 elem.peer = nil 75 } 76 77 func wgObfuscatePacket(obfuscator [NoisePublicKeySize]byte, buf *[]byte, length int, maxLength int) int { 78 79 // Calculate the number of 32-bit words to add to the end of the packet 80 nWords := (maxLength - length) >> 2 81 82 newbuf := *buf 83 // Add some random junk to the end of the packet if needed 84 if nWords > 0 { 85 junkSize := (rand.Intn(nWords) + 1) * 4 86 junk := make([]byte, junkSize) 87 88 _, err := rand.Read(junk) 89 if err != nil { 90 panic(err) 91 } 92 newbuf = append(*buf, junk...) 93 length += junkSize 94 } 95 96 // Encrypt the packet header using nonce from 4 bytes of the package contents 97 encryptLength := min(length&0xFFFC, NoiseObfuscateLenMax) - 4 98 99 // The C code uses an 8-byte nonce, of which only the first 4 ones are used 100 var nonce [8]byte 101 102 copy(nonce[0:4], newbuf[encryptLength : encryptLength + 4]) 103 104 cipher, err := chacha20.NewCipher(nonce[:],obfuscator[:]) 105 if err != nil { 106 panic(err) 107 } 108 cipher.XORKeyStream(newbuf[:encryptLength], newbuf[:encryptLength]) 109 110 *buf = newbuf 111 return encryptLength 112 } 113 114 func min(x, y int) int { 115 if x < y { 116 return x 117 } 118 return y 119 } 120 121 /* Queues a keepalive if no packets are queued for peer 122 */ 123 func (peer *Peer) SendKeepalive() { 124 if len(peer.queue.staged) == 0 && peer.isRunning.Get() { 125 elem := peer.device.NewOutboundElement() 126 select { 127 case peer.queue.staged <- elem: 128 peer.device.log.Verbosef("%v - Sending keepalive packet", peer) 129 default: 130 peer.device.PutMessageBuffer(elem.buffer) 131 peer.device.PutOutboundElement(elem) 132 } 133 } 134 peer.SendStagedPackets() 135 } 136 137 func (peer *Peer) SendHandshakeInitiation(isRetry bool) error { 138 if !isRetry { 139 atomic.StoreUint32(&peer.timers.handshakeAttempts, 0) 140 } 141 142 peer.handshake.mutex.RLock() 143 if time.Since(peer.handshake.lastSentHandshake) < RekeyTimeout { 144 peer.handshake.mutex.RUnlock() 145 return nil 146 } 147 peer.handshake.mutex.RUnlock() 148 149 peer.handshake.mutex.Lock() 150 if time.Since(peer.handshake.lastSentHandshake) < RekeyTimeout { 151 peer.handshake.mutex.Unlock() 152 return nil 153 } 154 peer.handshake.lastSentHandshake = time.Now() 155 peer.handshake.mutex.Unlock() 156 157 peer.device.log.Verbosef("%v - Sending handshake initiation", peer) 158 159 msg, err := peer.device.CreateMessageInitiation(peer) 160 if err != nil { 161 peer.device.log.Errorf("%v - Failed to create initiation message: %v", peer, err) 162 return err 163 } 164 165 var buff [MessageInitiationSize]byte 166 writer := bytes.NewBuffer(buff[:0]) 167 binary.Write(writer, binary.LittleEndian, msg) 168 packet := writer.Bytes() 169 peer.cookieGenerator.AddMacs(packet) 170 171 // obfuscation 172 wgObfuscatePacket(peer.handshake.obfuscator, &packet, MessageInitiationSize, MessageInitiationSize+64) 173 174 peer.timersAnyAuthenticatedPacketTraversal() 175 peer.timersAnyAuthenticatedPacketSent() 176 177 err = peer.SendBuffer(packet) 178 if err != nil { 179 peer.device.log.Errorf("%v - Failed to send handshake initiation: %v", peer, err) 180 } 181 peer.timersHandshakeInitiated() 182 183 return err 184 } 185 186 func (peer *Peer) SendHandshakeResponse() error { 187 peer.handshake.mutex.Lock() 188 peer.handshake.lastSentHandshake = time.Now() 189 peer.handshake.mutex.Unlock() 190 191 peer.device.log.Verbosef("%v - Sending handshake response", peer) 192 193 response, err := peer.device.CreateMessageResponse(peer) 194 if err != nil { 195 peer.device.log.Errorf("%v - Failed to create response message: %v", peer, err) 196 return err 197 } 198 199 var buff [MessageResponseSize]byte 200 writer := bytes.NewBuffer(buff[:0]) 201 binary.Write(writer, binary.LittleEndian, response) 202 packet := writer.Bytes() 203 peer.cookieGenerator.AddMacs(packet) 204 205 wgObfuscatePacket(peer.handshake.obfuscator, &packet, MessageResponseSize, MessageResponseSize+64) 206 207 err = peer.BeginSymmetricSession() 208 if err != nil { 209 peer.device.log.Errorf("%v - Failed to derive keypair: %v", peer, err) 210 return err 211 } 212 213 peer.timersSessionDerived() 214 peer.timersAnyAuthenticatedPacketTraversal() 215 peer.timersAnyAuthenticatedPacketSent() 216 217 err = peer.SendBuffer(packet) 218 if err != nil { 219 peer.device.log.Errorf("%v - Failed to send handshake response: %v", peer, err) 220 } 221 return err 222 } 223 224 func (device *Device) SendHandshakeCookie(initiatingElem *QueueHandshakeElement, obfuscator [NoisePublicKeySize]byte) error { 225 device.log.Verbosef("Sending cookie response for denied handshake message for %v", initiatingElem.endpoint.DstToString()) 226 227 sender := binary.LittleEndian.Uint32(initiatingElem.packet[4:8]) 228 reply, err := device.cookieChecker.CreateReply(initiatingElem.packet, sender, initiatingElem.endpoint.DstToBytes()) 229 if err != nil { 230 device.log.Errorf("Failed to create cookie reply: %v", err) 231 return err 232 } 233 234 var buff [MessageCookieReplySize]byte 235 writer := bytes.NewBuffer(buff[:0]) 236 binary.Write(writer, binary.LittleEndian, reply) 237 packet := writer.Bytes() 238 239 wgObfuscatePacket(obfuscator, &packet, MessageCookieReplySize, MessageCookieReplySize+64) 240 241 device.net.bind.Send(packet, initiatingElem.endpoint) 242 return nil 243 } 244 245 func (peer *Peer) keepKeyFreshSending() { 246 keypair := peer.keypairs.Current() 247 if keypair == nil { 248 return 249 } 250 nonce := atomic.LoadUint64(&keypair.sendNonce) 251 if nonce > RekeyAfterMessages || (keypair.isInitiator && time.Since(keypair.created) > RekeyAfterTime) { 252 peer.SendHandshakeInitiation(false) 253 } 254 } 255 256 /* Reads packets from the TUN and inserts 257 * into staged queue for peer 258 * 259 * Obs. Single instance per TUN device 260 */ 261 func (device *Device) RoutineReadFromTUN() { 262 defer func() { 263 device.log.Verbosef("Routine: TUN reader - stopped") 264 device.state.stopping.Done() 265 device.queue.encryption.wg.Done() 266 }() 267 268 device.log.Verbosef("Routine: TUN reader - started") 269 270 var elem *QueueOutboundElement 271 272 for { 273 if elem != nil { 274 device.PutMessageBuffer(elem.buffer) 275 device.PutOutboundElement(elem) 276 } 277 elem = device.NewOutboundElement() 278 279 // read packet 280 281 offset := MessageTransportHeaderSize 282 size, err := device.tun.device.Read(elem.buffer[:], offset) 283 if err != nil { 284 if !device.isClosed() { 285 if !errors.Is(err, os.ErrClosed) { 286 device.log.Errorf("Failed to read packet from TUN device: %v", err) 287 } 288 go device.Close() 289 } 290 device.PutMessageBuffer(elem.buffer) 291 device.PutOutboundElement(elem) 292 return 293 } 294 295 if size == 0 || size > MaxContentSize { 296 continue 297 } 298 299 elem.packet = elem.buffer[offset : offset+size] 300 301 // lookup peer 302 303 var peer *Peer 304 switch elem.packet[0] >> 4 { 305 case ipv4.Version: 306 if len(elem.packet) < ipv4.HeaderLen { 307 continue 308 } 309 dst := elem.packet[IPv4offsetDst : IPv4offsetDst+net.IPv4len] 310 peer = device.allowedips.Lookup(dst) 311 312 case ipv6.Version: 313 if len(elem.packet) < ipv6.HeaderLen { 314 continue 315 } 316 dst := elem.packet[IPv6offsetDst : IPv6offsetDst+net.IPv6len] 317 peer = device.allowedips.Lookup(dst) 318 319 default: 320 device.log.Verbosef("Received packet with unknown IP version") 321 } 322 323 if peer == nil { 324 continue 325 } 326 if peer.isRunning.Get() { 327 peer.StagePacket(elem) 328 elem = nil 329 peer.SendStagedPackets() 330 } 331 } 332 } 333 334 func (peer *Peer) StagePacket(elem *QueueOutboundElement) { 335 for { 336 select { 337 case peer.queue.staged <- elem: 338 return 339 default: 340 } 341 select { 342 case tooOld := <-peer.queue.staged: 343 peer.device.PutMessageBuffer(tooOld.buffer) 344 peer.device.PutOutboundElement(tooOld) 345 default: 346 } 347 } 348 } 349 350 func (peer *Peer) SendStagedPackets() { 351 top: 352 if len(peer.queue.staged) == 0 || !peer.device.isUp() { 353 return 354 } 355 356 keypair := peer.keypairs.Current() 357 if keypair == nil || atomic.LoadUint64(&keypair.sendNonce) >= RejectAfterMessages || time.Since(keypair.created) >= RejectAfterTime { 358 peer.SendHandshakeInitiation(false) 359 return 360 } 361 362 for { 363 select { 364 case elem := <-peer.queue.staged: 365 elem.peer = peer 366 elem.nonce = atomic.AddUint64(&keypair.sendNonce, 1) - 1 367 if elem.nonce >= RejectAfterMessages { 368 atomic.StoreUint64(&keypair.sendNonce, RejectAfterMessages) 369 peer.StagePacket(elem) // XXX: Out of order, but we can't front-load go chans 370 goto top 371 } 372 373 elem.keypair = keypair 374 elem.Lock() 375 376 // add to parallel and sequential queue 377 if peer.isRunning.Get() { 378 peer.queue.outbound.c <- elem 379 peer.device.queue.encryption.c <- elem 380 } else { 381 peer.device.PutMessageBuffer(elem.buffer) 382 peer.device.PutOutboundElement(elem) 383 } 384 default: 385 return 386 } 387 } 388 } 389 390 func (peer *Peer) FlushStagedPackets() { 391 for { 392 select { 393 case elem := <-peer.queue.staged: 394 peer.device.PutMessageBuffer(elem.buffer) 395 peer.device.PutOutboundElement(elem) 396 default: 397 return 398 } 399 } 400 } 401 402 func calculatePaddingSize(packetSize, mtu int) int { 403 lastUnit := packetSize 404 if mtu == 0 { 405 return ((lastUnit + PaddingMultiple - 1) & ^(PaddingMultiple - 1)) - lastUnit 406 } 407 if lastUnit > mtu { 408 lastUnit %= mtu 409 } 410 paddedSize := ((lastUnit + PaddingMultiple - 1) & ^(PaddingMultiple - 1)) 411 if paddedSize > mtu { 412 paddedSize = mtu 413 } 414 return paddedSize - lastUnit 415 } 416 417 /* Encrypts the elements in the queue 418 * and marks them for sequential consumption (by releasing the mutex) 419 * 420 * Obs. One instance per core 421 */ 422 func (device *Device) RoutineEncryption(id int) { 423 var paddingZeros [PaddingMultiple]byte 424 var nonce [chacha20poly1305.NonceSize]byte 425 426 defer device.log.Verbosef("Routine: encryption worker %d - stopped", id) 427 device.log.Verbosef("Routine: encryption worker %d - started", id) 428 429 for elem := range device.queue.encryption.c { 430 // populate header fields 431 header := elem.buffer[:MessageTransportHeaderSize] 432 433 fieldType := header[0:4] 434 fieldReceiver := header[4:8] 435 fieldNonce := header[8:16] 436 437 binary.LittleEndian.PutUint32(fieldType, MessageTransportType) 438 binary.LittleEndian.PutUint32(fieldReceiver, elem.keypair.remoteIndex) 439 binary.LittleEndian.PutUint64(fieldNonce, elem.nonce) 440 441 // pad content to multiple of 16 442 paddingSize := calculatePaddingSize(len(elem.packet), int(atomic.LoadInt32(&device.tun.mtu))) 443 elem.packet = append(elem.packet, paddingZeros[:paddingSize]...) 444 445 // encrypt content and release to consumer 446 447 binary.LittleEndian.PutUint64(nonce[4:], elem.nonce) 448 elem.packet = elem.keypair.send.Seal( 449 header, 450 nonce[:], 451 elem.packet, 452 nil, 453 ) 454 elem.Unlock() 455 } 456 } 457 458 /* Sequentially reads packets from queue and sends to endpoint 459 * 460 * Obs. Single instance per peer. 461 * The routine terminates then the outbound queue is closed. 462 */ 463 func (peer *Peer) RoutineSequentialSender() { 464 device := peer.device 465 defer func() { 466 defer device.log.Verbosef("%v - Routine: sequential sender - stopped", peer) 467 peer.stopping.Done() 468 }() 469 device.log.Verbosef("%v - Routine: sequential sender - started", peer) 470 471 for elem := range peer.queue.outbound.c { 472 if elem == nil { 473 return 474 } 475 elem.Lock() 476 if !peer.isRunning.Get() { 477 // peer has been stopped; return re-usable elems to the shared pool. 478 // This is an optimization only. It is possible for the peer to be stopped 479 // immediately after this check, in which case, elem will get processed. 480 // The timers and SendBuffer code are resilient to a few stragglers. 481 // TODO: rework peer shutdown order to ensure 482 // that we never accidentally keep timers alive longer than necessary. 483 device.PutMessageBuffer(elem.buffer) 484 device.PutOutboundElement(elem) 485 continue 486 } 487 488 peer.timersAnyAuthenticatedPacketTraversal() 489 peer.timersAnyAuthenticatedPacketSent() 490 491 // encrypt and send message and return buffer to pool 492 493 wgObfuscatePacket(peer.handshake.obfuscator, &elem.packet, len(elem.packet), len(elem.packet)) 494 err := peer.SendBuffer(elem.packet) 495 if len(elem.packet) != MessageKeepaliveSize { 496 peer.timersDataSent() 497 } 498 device.PutMessageBuffer(elem.buffer) 499 device.PutOutboundElement(elem) 500 if err != nil { 501 device.log.Errorf("%v - Failed to send data packet: %v", peer, err) 502 continue 503 } 504 505 peer.keepKeyFreshSending() 506 } 507 }