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