github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/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/tailscale/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  	b := []byte("peer(____…____)")
   157  	const first = len("peer(")
   158  	const second = len("peer(____…")
   159  	b[first+0] = b64((src[0] >> 2) & 63)
   160  	b[first+1] = b64(((src[0] << 4) | (src[1] >> 4)) & 63)
   161  	b[first+2] = b64(((src[1] << 2) | (src[2] >> 6)) & 63)
   162  	b[first+3] = b64(src[2] & 63)
   163  	b[second+0] = b64(src[29] & 63)
   164  	b[second+1] = b64((src[30] >> 2) & 63)
   165  	b[second+2] = b64(((src[30] << 4) | (src[31] >> 4)) & 63)
   166  	b[second+3] = b64((src[31] << 2) & 63)
   167  	return string(b)
   168  }
   169  
   170  func (peer *Peer) Start() {
   171  	// should never start a peer on a closed device
   172  	if peer.device.isClosed() {
   173  		return
   174  	}
   175  
   176  	// prevent simultaneous start/stop operations
   177  	peer.state.Lock()
   178  	defer peer.state.Unlock()
   179  
   180  	if peer.isRunning.Get() {
   181  		return
   182  	}
   183  
   184  	device := peer.device
   185  	device.log.Verbosef("%v - Starting", peer)
   186  
   187  	// reset routine state
   188  	peer.stopping.Wait()
   189  	peer.stopping.Add(2)
   190  
   191  	peer.handshake.mutex.Lock()
   192  	peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second))
   193  	peer.handshake.mutex.Unlock()
   194  
   195  	peer.device.queue.encryption.wg.Add(1) // keep encryption queue open for our writes
   196  
   197  	peer.timersStart()
   198  
   199  	device.flushInboundQueue(peer.queue.inbound)
   200  	device.flushOutboundQueue(peer.queue.outbound)
   201  	go peer.RoutineSequentialSender()
   202  	go peer.RoutineSequentialReceiver()
   203  
   204  	peer.isRunning.Set(true)
   205  }
   206  
   207  func (peer *Peer) ZeroAndFlushAll() {
   208  	device := peer.device
   209  
   210  	// clear key pairs
   211  
   212  	keypairs := &peer.keypairs
   213  	keypairs.Lock()
   214  	device.DeleteKeypair(keypairs.previous)
   215  	device.DeleteKeypair(keypairs.current)
   216  	device.DeleteKeypair(keypairs.loadNext())
   217  	keypairs.previous = nil
   218  	keypairs.current = nil
   219  	keypairs.storeNext(nil)
   220  	keypairs.Unlock()
   221  
   222  	// clear handshake state
   223  
   224  	handshake := &peer.handshake
   225  	handshake.mutex.Lock()
   226  	device.indexTable.Delete(handshake.localIndex)
   227  	handshake.Clear()
   228  	handshake.mutex.Unlock()
   229  
   230  	peer.FlushStagedPackets()
   231  }
   232  
   233  func (peer *Peer) ExpireCurrentKeypairs() {
   234  	handshake := &peer.handshake
   235  	handshake.mutex.Lock()
   236  	peer.device.indexTable.Delete(handshake.localIndex)
   237  	handshake.Clear()
   238  	peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second))
   239  	handshake.mutex.Unlock()
   240  
   241  	keypairs := &peer.keypairs
   242  	keypairs.Lock()
   243  	if keypairs.current != nil {
   244  		atomic.StoreUint64(&keypairs.current.sendNonce, RejectAfterMessages)
   245  	}
   246  	if keypairs.next != nil {
   247  		next := keypairs.loadNext()
   248  		atomic.StoreUint64(&next.sendNonce, RejectAfterMessages)
   249  	}
   250  	keypairs.Unlock()
   251  }
   252  
   253  func (peer *Peer) Stop() {
   254  	peer.state.Lock()
   255  	defer peer.state.Unlock()
   256  
   257  	if !peer.isRunning.Swap(false) {
   258  		return
   259  	}
   260  
   261  	peer.device.log.Verbosef("%v - Stopping", peer)
   262  
   263  	peer.timersStop()
   264  	// Signal that RoutineSequentialSender and RoutineSequentialReceiver should exit.
   265  	peer.queue.inbound.c <- nil
   266  	peer.queue.outbound.c <- nil
   267  	peer.stopping.Wait()
   268  	peer.device.queue.encryption.wg.Done() // no more writes to encryption queue from us
   269  
   270  	peer.ZeroAndFlushAll()
   271  }
   272  
   273  func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
   274  	if peer.disableRoaming {
   275  		return
   276  	}
   277  	peer.Lock()
   278  	peer.endpoint = endpoint
   279  	peer.Unlock()
   280  }