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  }