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  }