mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
wgengine{,/wgint}: add wgint.Peer wrapper type, add to wgengine.Engine
This adds a method to wgengine.Engine and plumbed down into magicsock to add a way to get a type-safe Tailscale-safe wrapper around a wireguard-go device.Peer that only exposes methods that are safe for Tailscale to use internally. It also removes HandshakeAttempts from PeerStatusLite that was just added as it wasn't needed yet and is now accessible ala cart as needed from the Peer type accessor. None of this is used yet. Updates #7617 Change-Id: I07be0c4e6679883e6eeddf8dbed7394c9e79c5f4 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
7e17aeb36b
commit
69f4b4595a
@ -405,7 +405,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
||||||
tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+
|
tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+
|
||||||
tailscale.com/wgengine/wgcfg/nmcfg from tailscale.com/ipn/ipnlocal
|
tailscale.com/wgengine/wgcfg/nmcfg from tailscale.com/ipn/ipnlocal
|
||||||
💣 tailscale.com/wgengine/wgint from tailscale.com/wgengine
|
💣 tailscale.com/wgengine/wgint from tailscale.com/wgengine+
|
||||||
tailscale.com/wgengine/wglog from tailscale.com/wgengine
|
tailscale.com/wgengine/wglog from tailscale.com/wgengine
|
||||||
W 💣 tailscale.com/wgengine/winnet from tailscale.com/wgengine/router
|
W 💣 tailscale.com/wgengine/winnet from tailscale.com/wgengine/router
|
||||||
golang.org/x/crypto/argon2 from tailscale.com/tka
|
golang.org/x/crypto/argon2 from tailscale.com/tka
|
||||||
|
@ -203,11 +203,6 @@ type PeerStatusLite struct {
|
|||||||
// since this peer was last known to WireGuard. (Tailscale removes peers
|
// since this peer was last known to WireGuard. (Tailscale removes peers
|
||||||
// from the wireguard peer that are idle.)
|
// from the wireguard peer that are idle.)
|
||||||
LastHandshake time.Time
|
LastHandshake time.Time
|
||||||
|
|
||||||
// HandshakeAttempts is how many failed attempts there have been at
|
|
||||||
// completing the current WireGuard handshake. This resets to zero on every
|
|
||||||
// successful handshake.
|
|
||||||
HandshakeAttempts uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerStatus describes a peer node and its current state.
|
// PeerStatus describes a peer node and its current state.
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
"tailscale.com/util/testenv"
|
"tailscale.com/util/testenv"
|
||||||
"tailscale.com/util/uniq"
|
"tailscale.com/util/uniq"
|
||||||
"tailscale.com/wgengine/capture"
|
"tailscale.com/wgengine/capture"
|
||||||
|
"tailscale.com/wgengine/wgint"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -298,6 +299,10 @@ type Conn struct {
|
|||||||
// onPortUpdate is called with the new port when magicsock rebinds to
|
// onPortUpdate is called with the new port when magicsock rebinds to
|
||||||
// a new port.
|
// a new port.
|
||||||
onPortUpdate func(port uint16, network string)
|
onPortUpdate func(port uint16, network string)
|
||||||
|
|
||||||
|
// getPeerByKey optionally specifies a function to look up a peer's
|
||||||
|
// wireguard state by its public key. If nil, it's not used.
|
||||||
|
getPeerByKey func(key.NodePublic) (_ wgint.Peer, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDebugLoggingEnabled controls whether spammy debug logging is enabled.
|
// SetDebugLoggingEnabled controls whether spammy debug logging is enabled.
|
||||||
@ -367,6 +372,11 @@ type Options struct {
|
|||||||
// OnPortUpdate is called with the new port when magicsock rebinds to
|
// OnPortUpdate is called with the new port when magicsock rebinds to
|
||||||
// a new port.
|
// a new port.
|
||||||
OnPortUpdate func(port uint16, network string)
|
OnPortUpdate func(port uint16, network string)
|
||||||
|
|
||||||
|
// PeerByKeyFunc optionally specifies a function to look up a peer's
|
||||||
|
// WireGuard state by its public key. If nil, it's not used.
|
||||||
|
// In regular use, this will be wgengine.(*userspaceEngine).PeerByKey.
|
||||||
|
PeerByKeyFunc func(key.NodePublic) (_ wgint.Peer, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Options) logf() logger.Logf {
|
func (o *Options) logf() logger.Logf {
|
||||||
@ -440,6 +450,7 @@ func NewConn(opts Options) (*Conn, error) {
|
|||||||
}
|
}
|
||||||
c.netMon = opts.NetMon
|
c.netMon = opts.NetMon
|
||||||
c.onPortUpdate = opts.OnPortUpdate
|
c.onPortUpdate = opts.OnPortUpdate
|
||||||
|
c.getPeerByKey = opts.PeerByKeyFunc
|
||||||
|
|
||||||
if err := c.rebind(keepCurrentPort); err != nil {
|
if err := c.rebind(keepCurrentPort); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1011,25 +1011,30 @@ func (e *userspaceEngine) getStatusCallback() StatusCallback {
|
|||||||
|
|
||||||
var ErrEngineClosing = errors.New("engine closing; no status")
|
var ErrEngineClosing = errors.New("engine closing; no status")
|
||||||
|
|
||||||
func (e *userspaceEngine) getPeerStatusLite(pk key.NodePublic) (status ipnstate.PeerStatusLite, ok bool) {
|
func (e *userspaceEngine) PeerByKey(pubKey key.NodePublic) (_ wgint.Peer, ok bool) {
|
||||||
e.wgLock.Lock()
|
e.wgLock.Lock()
|
||||||
dev := e.wgdev
|
dev := e.wgdev
|
||||||
e.wgLock.Unlock()
|
e.wgLock.Unlock()
|
||||||
|
|
||||||
if dev == nil {
|
if dev == nil {
|
||||||
return status, false
|
return wgint.Peer{}, false
|
||||||
}
|
}
|
||||||
peer := dev.LookupPeer(pk.Raw32())
|
peer := dev.LookupPeer(pubKey.Raw32())
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
|
return wgint.Peer{}, false
|
||||||
|
}
|
||||||
|
return wgint.PeerOf(peer), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *userspaceEngine) getPeerStatusLite(pk key.NodePublic) (status ipnstate.PeerStatusLite, ok bool) {
|
||||||
|
peer, ok := e.PeerByKey(pk)
|
||||||
|
if !ok {
|
||||||
return status, false
|
return status, false
|
||||||
}
|
}
|
||||||
status.NodeKey = pk
|
status.NodeKey = pk
|
||||||
status.RxBytes = int64(wgint.PeerRxBytes(peer))
|
status.RxBytes = int64(peer.RxBytes())
|
||||||
status.TxBytes = int64(wgint.PeerTxBytes(peer))
|
status.TxBytes = int64(peer.TxBytes())
|
||||||
status.HandshakeAttempts = wgint.PeerHandshakeAttempts(peer)
|
status.LastHandshake = peer.LastHandshake()
|
||||||
if nano := wgint.PeerLastHandshakeNano(peer); nano != 0 {
|
|
||||||
status.LastHandshake = time.Unix(0, nano)
|
|
||||||
}
|
|
||||||
return status, true
|
return status, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +18,13 @@
|
|||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
"tailscale.com/net/dns"
|
"tailscale.com/net/dns"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/wgengine/capture"
|
"tailscale.com/wgengine/capture"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
|
"tailscale.com/wgengine/wgint"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWatchdog wraps an Engine and makes sure that all methods complete
|
// NewWatchdog wraps an Engine and makes sure that all methods complete
|
||||||
@ -157,3 +159,7 @@ func (e *watchdogEngine) Done() <-chan struct{} {
|
|||||||
func (e *watchdogEngine) InstallCaptureHook(cb capture.Callback) {
|
func (e *watchdogEngine) InstallCaptureHook(cb capture.Callback) {
|
||||||
e.wrap.InstallCaptureHook(cb)
|
e.wrap.InstallCaptureHook(cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *watchdogEngine) PeerByKey(pubKey key.NodePublic) (_ wgint.Peer, ok bool) {
|
||||||
|
return e.wrap.PeerByKey(pubKey)
|
||||||
|
}
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
"tailscale.com/net/dns"
|
"tailscale.com/net/dns"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/wgengine/capture"
|
"tailscale.com/wgengine/capture"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
"tailscale.com/wgengine/router"
|
"tailscale.com/wgengine/router"
|
||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
|
"tailscale.com/wgengine/wgint"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status is the Engine status.
|
// Status is the Engine status.
|
||||||
@ -84,6 +86,10 @@ type Engine interface {
|
|||||||
// away, sent to the callback registered via SetStatusCallback.
|
// away, sent to the callback registered via SetStatusCallback.
|
||||||
RequestStatus()
|
RequestStatus()
|
||||||
|
|
||||||
|
// PeerByKey returns the WireGuard status of the provided peer.
|
||||||
|
// If the peer is not found, ok is false.
|
||||||
|
PeerByKey(key.NodePublic) (_ wgint.Peer, ok bool)
|
||||||
|
|
||||||
// Close shuts down this wireguard instance, remove any routes
|
// Close shuts down this wireguard instance, remove any routes
|
||||||
// it added, etc. To bring it up again later, you'll need a
|
// it added, etc. To bring it up again later, you'll need a
|
||||||
// new Engine.
|
// new Engine.
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/tailscale/wireguard-go/device"
|
"github.com/tailscale/wireguard-go/device"
|
||||||
@ -49,24 +50,59 @@ func getPeerHandshakeAttemptsOffset() uintptr {
|
|||||||
return field.Offset + field2.Offset
|
return field.Offset + field2.Offset
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerLastHandshakeNano returns the last handshake time in nanoseconds since the
|
// peerLastHandshakeNano returns the last handshake time in nanoseconds since the
|
||||||
// unix epoch.
|
// unix epoch.
|
||||||
func PeerLastHandshakeNano(peer *device.Peer) int64 {
|
func peerLastHandshakeNano(peer *device.Peer) int64 {
|
||||||
return (*atomic.Int64)(unsafe.Add(unsafe.Pointer(peer), offHandshake)).Load()
|
return (*atomic.Int64)(unsafe.Add(unsafe.Pointer(peer), offHandshake)).Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerRxBytes returns the number of bytes received from this peer.
|
// peerRxBytes returns the number of bytes received from this peer.
|
||||||
func PeerRxBytes(peer *device.Peer) uint64 {
|
func peerRxBytes(peer *device.Peer) uint64 {
|
||||||
return (*atomic.Uint64)(unsafe.Add(unsafe.Pointer(peer), offRxBytes)).Load()
|
return (*atomic.Uint64)(unsafe.Add(unsafe.Pointer(peer), offRxBytes)).Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerTxBytes returns the number of bytes sent to this peer.
|
// peerTxBytes returns the number of bytes sent to this peer.
|
||||||
func PeerTxBytes(peer *device.Peer) uint64 {
|
func peerTxBytes(peer *device.Peer) uint64 {
|
||||||
return (*atomic.Uint64)(unsafe.Add(unsafe.Pointer(peer), offTxBytes)).Load()
|
return (*atomic.Uint64)(unsafe.Add(unsafe.Pointer(peer), offTxBytes)).Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerHandshakeAttempts returns the number of WireGuard handshake attempts
|
// peerHandshakeAttempts returns the number of WireGuard handshake attempts
|
||||||
// made for the current handshake. It resets to zero before every new handshake.
|
// made for the current handshake. It resets to zero before every new handshake.
|
||||||
func PeerHandshakeAttempts(peer *device.Peer) uint32 {
|
func peerHandshakeAttempts(peer *device.Peer) uint32 {
|
||||||
return (*atomic.Uint32)(unsafe.Add(unsafe.Pointer(peer), offHandshakeAttempts)).Load()
|
return (*atomic.Uint32)(unsafe.Add(unsafe.Pointer(peer), offHandshakeAttempts)).Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Peer is a wrapper around a wireguard-go device.Peer pointer.
|
||||||
|
type Peer struct {
|
||||||
|
p *device.Peer
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerOf returns a Peer wrapper around a wireguard-go device.Peer.
|
||||||
|
func PeerOf(p *device.Peer) Peer {
|
||||||
|
return Peer{p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastHandshake returns the last handshake time.
|
||||||
|
//
|
||||||
|
// If the handshake has never happened, it returns the zero value.
|
||||||
|
func (p Peer) LastHandshake() time.Time {
|
||||||
|
if n := peerLastHandshakeNano(p.p); n != 0 {
|
||||||
|
return time.Unix(0, n)
|
||||||
|
}
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Peer) IsValid() bool { return p.p != nil }
|
||||||
|
|
||||||
|
// TxBytes returns the number of bytes sent to this peer.
|
||||||
|
func (p Peer) TxBytes() uint64 { return peerTxBytes(p.p) }
|
||||||
|
|
||||||
|
// RxBytes returns the number of bytes received from this peer.
|
||||||
|
func (p Peer) RxBytes() uint64 { return peerRxBytes(p.p) }
|
||||||
|
|
||||||
|
// HandshakeAttempts returns the number of failed WireGuard handshake attempts
|
||||||
|
// made for the current handshake. It resets to zero before every new handshake
|
||||||
|
// and after a successful handshake.
|
||||||
|
func (p Peer) HandshakeAttempts() uint32 {
|
||||||
|
return peerHandshakeAttempts(p.p)
|
||||||
|
}
|
||||||
|
@ -11,16 +11,16 @@
|
|||||||
|
|
||||||
func TestInternalOffsets(t *testing.T) {
|
func TestInternalOffsets(t *testing.T) {
|
||||||
peer := new(device.Peer)
|
peer := new(device.Peer)
|
||||||
if got := PeerLastHandshakeNano(peer); got != 0 {
|
if got := peerLastHandshakeNano(peer); got != 0 {
|
||||||
t.Errorf("PeerLastHandshakeNano = %v, want 0", got)
|
t.Errorf("PeerLastHandshakeNano = %v, want 0", got)
|
||||||
}
|
}
|
||||||
if got := PeerRxBytes(peer); got != 0 {
|
if got := peerRxBytes(peer); got != 0 {
|
||||||
t.Errorf("PeerRxBytes = %v, want 0", got)
|
t.Errorf("PeerRxBytes = %v, want 0", got)
|
||||||
}
|
}
|
||||||
if got := PeerTxBytes(peer); got != 0 {
|
if got := peerTxBytes(peer); got != 0 {
|
||||||
t.Errorf("PeerTxBytes = %v, want 0", got)
|
t.Errorf("PeerTxBytes = %v, want 0", got)
|
||||||
}
|
}
|
||||||
if got := PeerHandshakeAttempts(peer); got != 0 {
|
if got := peerHandshakeAttempts(peer); got != 0 {
|
||||||
t.Errorf("PeerHandshakeAttempts = %v, want 0", got)
|
t.Errorf("PeerHandshakeAttempts = %v, want 0", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user