Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+84
-55
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package wglog contains logging helpers for wireguard-go.
|
||||
@@ -11,33 +11,42 @@ import (
|
||||
|
||||
"github.com/tailscale/wireguard-go/device"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
"tailscale.com/util/mak"
|
||||
)
|
||||
|
||||
// A Logger is a wireguard-go log wrapper that cleans up and rewrites log lines.
|
||||
// It can be modified at run time to adjust to new wireguard-go configurations.
|
||||
// It rewrites wireguard-go peer references like "peer(XXXX…YYYY)" into the
|
||||
// Tailscale-conventional short string form like "[XXXXX]".
|
||||
type Logger struct {
|
||||
DeviceLogger *device.Logger
|
||||
replace syncs.AtomicValue[map[string]string]
|
||||
mu sync.Mutex // protects strs
|
||||
strs map[key.NodePublic]*strCache // cached strs used to populate replace
|
||||
}
|
||||
|
||||
// strCache holds a wireguard-go and a Tailscale style peer string.
|
||||
type strCache struct {
|
||||
wg, ts string
|
||||
used bool // track whether this strCache was used in a particular round
|
||||
// lookup, when non-nil, returns the Tailscale-conventional short
|
||||
// string for a wireguard-go-formatted peer string (e.g. it maps
|
||||
// "peer(IMTB…r7lM)" to "[IMTBr]"), or "", false if no peer matches.
|
||||
// It is set once at construction and not changed afterwards.
|
||||
lookup func(wgString string) (tsString string, ok bool)
|
||||
|
||||
mu sync.Mutex // protects cache
|
||||
|
||||
// cache memoizes lookup results. The key is the wireguard-go
|
||||
// peer-string form ("peer(XXXX…YYYY)") and the value is the
|
||||
// Tailscale-conventional short-string form ("[XXXXX]").
|
||||
// It is cleared in bulk by Invalidate when the underlying peer set
|
||||
// may have changed.
|
||||
cache map[string]string
|
||||
}
|
||||
|
||||
// NewLogger creates a new logger for use with wireguard-go.
|
||||
// This logger silences repetitive/unhelpful noisy log lines
|
||||
// and rewrites peer keys from wireguard-go into Tailscale format.
|
||||
func NewLogger(logf logger.Logf) *Logger {
|
||||
//
|
||||
// lookup, if non-nil, is consulted on cache misses to translate
|
||||
// wireguard-go peer references in log lines. If lookup is nil,
|
||||
// peer references are passed through unchanged.
|
||||
func NewLogger(logf logger.Logf, lookup func(wgString string) (tsString string, ok bool)) *Logger {
|
||||
const prefix = "wg: "
|
||||
ret := new(Logger)
|
||||
ret := &Logger{lookup: lookup}
|
||||
wrapper := func(format string, args ...any) {
|
||||
if strings.Contains(format, "Routine:") && !strings.Contains(format, "receive incoming") {
|
||||
// wireguard-go logs as it starts and stops routines.
|
||||
@@ -60,32 +69,37 @@ func NewLogger(logf logger.Logf) *Logger {
|
||||
// useful.
|
||||
return
|
||||
}
|
||||
replace := ret.replace.Load()
|
||||
if replace == nil {
|
||||
// No replacements specified; log as originally planned.
|
||||
if ret.lookup == nil {
|
||||
// No lookup; log as originally planned.
|
||||
logf(format, args...)
|
||||
return
|
||||
}
|
||||
// Duplicate the args slice so that we can modify it.
|
||||
// This is not always required, but the code required to avoid it is not worth the complexity.
|
||||
newargs := make([]any, len(args))
|
||||
copy(newargs, args)
|
||||
for i, arg := range newargs {
|
||||
// We want to replace *device.Peer args with the Tailscale-formatted version of themselves.
|
||||
// Using *device.Peer directly makes this hard to test, so we string any fmt.Stringers,
|
||||
// and if the string ends up looking exactly like a known Peer, we replace it.
|
||||
// This is slightly imprecise, in that we don't check the formatting verb. Oh well.
|
||||
// Replace any *device.Peer-shaped fmt.Stringer args with the
|
||||
// Tailscale-formatted version of themselves. Using *device.Peer
|
||||
// directly makes this hard to test, so we string any fmt.Stringers,
|
||||
// and if the string ends up matching a known peer, we substitute.
|
||||
// This is slightly imprecise, in that we don't check the formatting
|
||||
// verb. Oh well.
|
||||
var newargs []any
|
||||
for i, arg := range args {
|
||||
s, ok := arg.(fmt.Stringer)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
wgStr := s.String()
|
||||
tsStr, ok := replace[wgStr]
|
||||
tsStr, ok := ret.peerStringFor(s.String())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if newargs == nil {
|
||||
newargs = make([]any, len(args))
|
||||
copy(newargs, args)
|
||||
}
|
||||
newargs[i] = tsStr
|
||||
}
|
||||
if newargs == nil {
|
||||
logf(format, args...)
|
||||
return
|
||||
}
|
||||
logf(format, newargs...)
|
||||
}
|
||||
if envknob.Bool("TS_DEBUG_RAW_WGLOG") {
|
||||
@@ -95,36 +109,51 @@ func NewLogger(logf logger.Logf) *Logger {
|
||||
Verbosef: logger.WithPrefix(wrapper, prefix+"[v2] "),
|
||||
Errorf: logger.WithPrefix(wrapper, prefix),
|
||||
}
|
||||
ret.strs = make(map[key.NodePublic]*strCache)
|
||||
return ret
|
||||
}
|
||||
|
||||
// SetPeers adjusts x to rewrite the peer public keys found in peers.
|
||||
// SetPeers is safe for concurrent use.
|
||||
func (x *Logger) SetPeers(peers []wgcfg.Peer) {
|
||||
// peerStringFor returns the Tailscale-conventional short string for
|
||||
// wgString, if wgString is a wireguard-go-formatted peer string for a
|
||||
// peer known to x.lookup. Results are memoized in x.cache for
|
||||
// subsequent log lines.
|
||||
func (x *Logger) peerStringFor(wgString string) (tsString string, ok bool) {
|
||||
// Fast path: only strings shaped like wireguard-go's
|
||||
// "peer(XXXX…YYYY)" output can be peer references; skip the cache
|
||||
// and lookup call for anything else (e.g. arbitrary stringers used
|
||||
// in unrelated log args).
|
||||
if !strings.HasPrefix(wgString, "peer(") || !strings.HasSuffix(wgString, ")") {
|
||||
return "", false
|
||||
}
|
||||
x.mu.Lock()
|
||||
defer x.mu.Unlock()
|
||||
// Construct a new peer public key log rewriter.
|
||||
replace := make(map[string]string)
|
||||
for _, peer := range peers {
|
||||
c, ok := x.strs[peer.PublicKey] // look up cached strs
|
||||
if !ok {
|
||||
wg := peer.PublicKey.WireGuardGoString()
|
||||
ts := peer.PublicKey.ShortString()
|
||||
c = &strCache{wg: wg, ts: ts}
|
||||
x.strs[peer.PublicKey] = c
|
||||
}
|
||||
c.used = true
|
||||
replace[c.wg] = c.ts
|
||||
if v, ok := x.cache[wgString]; ok {
|
||||
x.mu.Unlock()
|
||||
return v, true
|
||||
}
|
||||
// Remove any unused cached strs.
|
||||
for k, c := range x.strs {
|
||||
if !c.used {
|
||||
delete(x.strs, k)
|
||||
continue
|
||||
}
|
||||
// Mark c as unused for next round.
|
||||
c.used = false
|
||||
x.mu.Unlock()
|
||||
|
||||
// Call lookup without x.mu held so we don't have to reason about
|
||||
// deadlocks between x.mu and any locks lookup acquires.
|
||||
// In the worst case, two goroutines concurrently miss the cache
|
||||
// for the same wgString and both call lookup; the redundant call
|
||||
// is wasted but harmless.
|
||||
tsString, ok = x.lookup(wgString)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
x.replace.Store(replace)
|
||||
x.mu.Lock()
|
||||
mak.Set(&x.cache, wgString, tsString)
|
||||
x.mu.Unlock()
|
||||
return tsString, true
|
||||
}
|
||||
|
||||
// Invalidate clears the peer-string rewrite cache.
|
||||
//
|
||||
// Callers should invoke Invalidate when the set of wireguard-go peers
|
||||
// has changed so that the next log line re-resolves peer references
|
||||
// against the current lookup. It is safe to call concurrently with
|
||||
// logging.
|
||||
func (x *Logger) Invalidate() {
|
||||
x.mu.Lock()
|
||||
clear(x.cache)
|
||||
x.mu.Unlock()
|
||||
}
|
||||
Reference in new issue
Block a user