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