Files

297 lines
7.3 KiB
Go
Raw Permalink Normal View History

2019-01-02 01:55:51 +01:00
/* SPDX-License-Identifier: MIT
2018-05-03 15:04:00 +02:00
*
2025-05-04 17:48:53 +02:00
* Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved.
2018-05-03 15:04:00 +02:00
*/
2019-03-03 04:04:41 +01:00
package device
2017-05-30 22:36:49 +02:00
import (
"container/list"
2017-06-26 13:14:02 +02:00
"errors"
2017-05-30 22:36:49 +02:00
"sync"
2019-06-11 18:13:52 +02:00
"sync/atomic"
2017-06-04 21:48:15 +02:00
"time"
"golang.zx2c4.com/wireguard/conn"
2017-05-30 22:36:49 +02:00
)
type Peer struct {
2022-08-30 07:43:11 -07:00
isRunning atomic.Bool
keypairs Keypairs
handshake Handshake
device *Device
stopping sync.WaitGroup // routines pending stop
txBytes atomic.Uint64 // bytes send to peer (endpoint)
rxBytes atomic.Uint64 // bytes received from peer
lastHandshakeNano atomic.Int64 // nano seconds since epoch
2018-02-02 16:40:14 +01:00
endpoint struct {
sync.Mutex
val conn.Endpoint
clearSrcOnTx bool // signal to val.ClearSrc() prior to next packet transmission
disableRoaming bool
}
2020-12-22 21:34:21 +01:00
2018-05-07 22:27:03 +02:00
timers struct {
retransmitHandshake *Timer
sendKeepalive *Timer
newHandshake *Timer
zeroKeyMaterial *Timer
persistentKeepalive *Timer
2022-08-30 07:43:11 -07:00
handshakeAttempts atomic.Uint32
needAnotherKeepalive atomic.Bool
sentLastMinuteHandshake atomic.Bool
2017-06-28 23:45:45 +02:00
}
2018-02-02 16:40:14 +01:00
2021-02-08 13:02:52 -08:00
state struct {
sync.Mutex // protects against concurrent Start/Stop
2021-02-08 13:02:52 -08:00
}
2017-06-28 23:45:45 +02:00
queue struct {
staged chan *QueueOutboundElementsContainer // staged packets before a handshake is available
outbound *autodrainingOutboundQueue // sequential ordering of udp transmission
inbound *autodrainingInboundQueue // sequential ordering of tun writing
2018-01-13 09:00:37 +01:00
}
2018-02-02 16:40:14 +01:00
cookieGenerator CookieGenerator
trieEntries list.List
2022-08-30 07:43:11 -07:00
persistentKeepaliveInterval atomic.Uint32
2017-06-24 15:34:17 +02:00
}
2017-08-07 15:25:04 +02:00
func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
2021-01-19 09:02:16 -08:00
if device.isClosed() {
2018-05-13 19:33:41 +02:00
return nil, errors.New("device closed")
2018-01-26 22:52:32 +01:00
}
2018-02-02 16:40:14 +01:00
// lock resources
device.staticIdentity.RLock()
defer device.staticIdentity.RUnlock()
2018-02-02 16:40:14 +01:00
device.peers.Lock()
defer device.peers.Unlock()
2018-02-02 16:40:14 +01:00
// check if over limit
if len(device.peers.keyMap) >= MaxPeers {
2018-05-13 19:33:41 +02:00
return nil, errors.New("too many peers")
2018-02-02 16:40:14 +01:00
}
2018-01-26 22:52:32 +01:00
2017-06-26 13:14:02 +02:00
// create peer
2017-06-30 14:41:08 +02:00
peer := new(Peer)
2017-07-01 23:29:22 +02:00
2018-05-13 23:14:43 +02:00
peer.cookieGenerator.Init(pk)
2017-07-01 23:29:22 +02:00
peer.device = device
peer.queue.outbound = newAutodrainingOutboundQueue(device)
peer.queue.inbound = newAutodrainingInboundQueue(device)
peer.queue.staged = make(chan *QueueOutboundElementsContainer, QueueStagedSize)
2017-07-08 23:51:26 +02:00
2017-06-26 13:14:02 +02:00
// map public key
2018-02-02 16:40:14 +01:00
_, ok := device.peers.keyMap[pk]
2017-06-26 13:14:02 +02:00
if ok {
2018-05-13 19:33:41 +02:00
return nil, errors.New("adding existing peer")
2017-06-26 13:14:02 +02:00
}
// pre-compute DH
2017-06-26 13:14:02 +02:00
handshake := &peer.handshake
handshake.mutex.Lock()
handshake.precomputedStaticStatic, _ = device.staticIdentity.privateKey.sharedSecret(pk)
2019-08-05 16:57:41 +02:00
handshake.remoteStatic = pk
2017-06-26 13:14:02 +02:00
handshake.mutex.Unlock()
2017-06-24 15:34:17 +02:00
2017-10-16 21:33:47 +02:00
// reset endpoint
peer.endpoint.Lock()
peer.endpoint.val = nil
peer.endpoint.disableRoaming = false
peer.endpoint.clearSrcOnTx = false
peer.endpoint.Unlock()
2017-10-16 21:33:47 +02:00
// init timers
peer.timersInit()
2020-03-17 23:06:56 -06:00
// add
device.peers.keyMap[pk] = peer
2019-08-05 16:57:41 +02:00
2017-08-07 15:25:04 +02:00
return peer, nil
2017-05-30 22:36:49 +02:00
}
2017-06-28 23:45:45 +02:00
func (peer *Peer) SendBuffers(buffers [][]byte) error {
peer.device.net.RLock()
defer peer.device.net.RUnlock()
2017-12-29 17:42:09 +01:00
2021-02-22 02:01:50 +01:00
if peer.device.isClosed() {
return nil
2018-02-02 20:45:25 +01:00
}
peer.endpoint.Lock()
endpoint := peer.endpoint.val
if endpoint == nil {
peer.endpoint.Unlock()
2018-05-13 19:33:41 +02:00
return errors.New("no known endpoint for peer")
2017-10-27 10:43:37 +02:00
}
if peer.endpoint.clearSrcOnTx {
endpoint.ClearSrc()
peer.endpoint.clearSrcOnTx = false
}
peer.endpoint.Unlock()
2017-12-29 17:42:09 +01:00
err := peer.device.net.bind.Send(buffers, endpoint)
2019-06-11 18:13:52 +02:00
if err == nil {
var totalLen uint64
for _, b := range buffers {
totalLen += uint64(len(b))
}
peer.txBytes.Add(totalLen)
2019-06-11 18:13:52 +02:00
}
return err
2017-10-27 10:43:37 +02:00
}
2017-07-13 14:32:40 +02:00
func (peer *Peer) String() string {
2021-05-13 15:30:18 -07:00
// The awful goo that follows is identical to:
//
// base64Key := base64.StdEncoding.EncodeToString(peer.handshake.remoteStatic[:])
// abbreviatedKey := base64Key[0:4] + "…" + base64Key[39:43]
// return fmt.Sprintf("peer(%s)", abbreviatedKey)
//
// except that it is considerably more efficient.
2021-05-14 01:07:55 +02:00
src := peer.handshake.remoteStatic
b64 := func(input byte) byte {
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)
}
b := []byte("peer(____…____)")
const first = len("peer(")
const second = len("peer(____…")
b[first+0] = b64((src[0] >> 2) & 63)
b[first+1] = b64(((src[0] << 4) | (src[1] >> 4)) & 63)
b[first+2] = b64(((src[1] << 2) | (src[2] >> 6)) & 63)
b[first+3] = b64(src[2] & 63)
b[second+0] = b64(src[29] & 63)
b[second+1] = b64((src[30] >> 2) & 63)
b[second+2] = b64(((src[30] << 4) | (src[31] >> 4)) & 63)
b[second+3] = b64((src[31] << 2) & 63)
return string(b)
2017-07-13 14:32:40 +02:00
}
2018-01-13 09:00:37 +01:00
func (peer *Peer) Start() {
// should never start a peer on a closed device
2021-01-19 09:02:16 -08:00
if peer.device.isClosed() {
2018-02-02 16:40:14 +01:00
return
}
// prevent simultaneous start/stop operations
peer.state.Lock()
defer peer.state.Unlock()
2018-02-02 20:45:25 +01:00
2022-08-30 07:43:11 -07:00
if peer.isRunning.Load() {
2018-02-02 20:45:25 +01:00
return
}
2018-02-04 19:18:44 +01:00
device := peer.device
2021-05-07 12:17:41 +02:00
device.log.Verbosef("%v - Starting", peer)
2018-01-26 22:52:32 +01:00
2018-05-05 22:07:58 +02:00
// reset routine state
2021-01-29 14:54:11 +01:00
peer.stopping.Wait()
peer.stopping.Add(2)
2018-01-13 09:00:37 +01:00
peer.handshake.mutex.Lock()
peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second))
peer.handshake.mutex.Unlock()
peer.device.queue.encryption.wg.Add(1) // keep encryption queue open for our writes
2018-01-26 22:52:32 +01:00
peer.timersStart()
2018-02-02 20:45:25 +01:00
device.flushInboundQueue(peer.queue.inbound)
device.flushOutboundQueue(peer.queue.outbound)
// Use the device batch size, not the bind batch size, as the device size is
// the size of the batch pools.
batchSize := peer.device.BatchSize()
go peer.RoutineSequentialSender(batchSize)
go peer.RoutineSequentialReceiver(batchSize)
2017-12-29 17:42:09 +01:00
2022-08-30 07:43:11 -07:00
peer.isRunning.Store(true)
2017-12-29 17:42:09 +01:00
}
2018-05-13 23:14:43 +02:00
func (peer *Peer) ZeroAndFlushAll() {
device := peer.device
// clear key pairs
keypairs := &peer.keypairs
keypairs.Lock()
2018-05-13 23:14:43 +02:00
device.DeleteKeypair(keypairs.previous)
device.DeleteKeypair(keypairs.current)
2022-08-30 07:43:11 -07:00
device.DeleteKeypair(keypairs.next.Load())
2018-05-13 23:14:43 +02:00
keypairs.previous = nil
keypairs.current = nil
2022-08-30 07:43:11 -07:00
keypairs.next.Store(nil)
keypairs.Unlock()
2018-05-13 23:14:43 +02:00
// clear handshake state
handshake := &peer.handshake
handshake.mutex.Lock()
device.indexTable.Delete(handshake.localIndex)
handshake.Clear()
handshake.mutex.Unlock()
2021-01-27 18:13:53 +01:00
peer.FlushStagedPackets()
2018-05-13 23:14:43 +02:00
}
func (peer *Peer) ExpireCurrentKeypairs() {
handshake := &peer.handshake
handshake.mutex.Lock()
peer.device.indexTable.Delete(handshake.localIndex)
handshake.Clear()
peer.handshake.lastSentHandshake = time.Now().Add(-(RekeyTimeout + time.Second))
2020-12-15 15:02:13 -08:00
handshake.mutex.Unlock()
keypairs := &peer.keypairs
keypairs.Lock()
if keypairs.current != nil {
2022-08-30 07:43:11 -07:00
keypairs.current.sendNonce.Store(RejectAfterMessages)
}
2022-08-30 07:43:11 -07:00
if next := keypairs.next.Load(); next != nil {
next.sendNonce.Store(RejectAfterMessages)
}
keypairs.Unlock()
}
2017-12-29 17:42:09 +01:00
func (peer *Peer) Stop() {
peer.state.Lock()
defer peer.state.Unlock()
2018-02-02 20:45:25 +01:00
if !peer.isRunning.Swap(false) {
return
}
2021-05-07 12:17:41 +02:00
peer.device.log.Verbosef("%v - Stopping", peer)
2018-01-26 22:52:32 +01:00
2018-05-07 22:27:03 +02:00
peer.timersStop()
2021-02-08 13:02:52 -08:00
// Signal that RoutineSequentialSender and RoutineSequentialReceiver should exit.
peer.queue.inbound.c <- nil
peer.queue.outbound.c <- nil
2021-01-29 14:54:11 +01:00
peer.stopping.Wait()
peer.device.queue.encryption.wg.Done() // no more writes to encryption queue from us
2018-01-26 22:52:32 +01:00
2018-05-13 23:14:43 +02:00
peer.ZeroAndFlushAll()
2017-06-28 23:45:45 +02:00
}
2018-05-26 02:59:26 +02:00
func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
peer.endpoint.Lock()
defer peer.endpoint.Unlock()
if peer.endpoint.disableRoaming {
2018-05-26 02:59:26 +02:00
return
}
peer.endpoint.clearSrcOnTx = false
peer.endpoint.val = endpoint
}
func (peer *Peer) markEndpointSrcForClearing() {
peer.endpoint.Lock()
defer peer.endpoint.Unlock()
if peer.endpoint.val == nil {
return
}
peer.endpoint.clearSrcOnTx = true
2018-05-26 02:59:26 +02:00
}