2021-01-21 20:33:54 +00:00
|
|
|
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Package wglog contains logging helpers for wireguard-go.
|
|
|
|
package wglog
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
"github.com/tailscale/wireguard-go/device"
|
|
|
|
"tailscale.com/types/logger"
|
2021-04-29 20:52:20 +00:00
|
|
|
"tailscale.com/types/wgkey"
|
2021-01-29 20:16:36 +00:00
|
|
|
"tailscale.com/wgengine/wgcfg"
|
2021-01-21 20:33:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
type Logger struct {
|
|
|
|
DeviceLogger *device.Logger
|
2021-04-27 17:03:13 +00:00
|
|
|
replace atomic.Value // of map[string]string
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
ret := new(Logger)
|
|
|
|
wrapper := func(format string, args ...interface{}) {
|
2021-04-27 16:44:51 +00:00
|
|
|
if strings.Contains(format, "Routine:") && !strings.Contains(format, "receive incoming") {
|
2021-01-21 20:33:54 +00:00
|
|
|
// wireguard-go logs as it starts and stops routines.
|
|
|
|
// Drop those; there are a lot of them, and they're just noise.
|
|
|
|
return
|
|
|
|
}
|
2021-04-27 16:44:51 +00:00
|
|
|
if strings.Contains(format, "Failed to send data packet") {
|
2021-02-01 22:37:58 +00:00
|
|
|
// Drop. See https://github.com/tailscale/tailscale/issues/1239.
|
|
|
|
return
|
|
|
|
}
|
2021-04-27 16:44:51 +00:00
|
|
|
if strings.Contains(format, "Interface up requested") || strings.Contains(format, "Interface down requested") {
|
2021-02-23 05:57:51 +00:00
|
|
|
// Drop. Logs 1/s constantly while the tun device is open.
|
|
|
|
// See https://github.com/tailscale/tailscale/issues/1388.
|
|
|
|
return
|
|
|
|
}
|
2021-04-27 17:03:13 +00:00
|
|
|
replace, _ := ret.replace.Load().(map[string]string)
|
|
|
|
if replace == nil {
|
2021-01-21 20:33:54 +00:00
|
|
|
// No replacements specified; log as originally planned.
|
|
|
|
logf(format, args...)
|
|
|
|
return
|
|
|
|
}
|
2021-04-27 17:03:13 +00:00
|
|
|
// 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([]interface{}, 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.
|
|
|
|
s, ok := arg.(fmt.Stringer)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
wgStr := s.String()
|
|
|
|
tsStr, ok := replace[wgStr]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
newargs[i] = tsStr
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
2021-04-27 17:03:13 +00:00
|
|
|
logf(format, newargs...)
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
|
|
|
ret.DeviceLogger = &device.Logger{
|
2021-02-03 23:24:13 +00:00
|
|
|
Verbosef: logger.WithPrefix(wrapper, "[v2] "),
|
|
|
|
Errorf: wrapper,
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
|
|
|
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) {
|
|
|
|
// Construct a new peer public key log rewriter.
|
2021-04-27 17:03:13 +00:00
|
|
|
replace := make(map[string]string)
|
2021-01-21 20:33:54 +00:00
|
|
|
for _, peer := range peers {
|
2021-05-11 19:20:00 +00:00
|
|
|
old := wireguardGoString(peer.PublicKey)
|
2021-01-21 20:33:54 +00:00
|
|
|
new := peer.PublicKey.ShortString()
|
2021-04-27 17:03:13 +00:00
|
|
|
replace[old] = new
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
2021-04-27 17:03:13 +00:00
|
|
|
x.replace.Store(replace)
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// wireguardGoString prints p in the same format used by wireguard-go.
|
2021-04-29 20:52:20 +00:00
|
|
|
func wireguardGoString(k wgkey.Key) string {
|
2021-05-11 19:20:00 +00:00
|
|
|
const prefix = "peer("
|
|
|
|
b := make([]byte, len(prefix)+44)
|
|
|
|
copy(b, prefix)
|
|
|
|
r := b[len(prefix):]
|
|
|
|
base64.StdEncoding.Encode(r, k[:])
|
|
|
|
r = r[4:]
|
|
|
|
copy(r, "…")
|
|
|
|
r = r[len("…"):]
|
|
|
|
copy(r, b[len(prefix)+39:len(prefix)+43])
|
|
|
|
r = r[4:]
|
|
|
|
r[0] = ')'
|
|
|
|
r = r[1:]
|
|
|
|
return string(b[:len(b)-len(r)])
|
2021-01-21 20:33:54 +00:00
|
|
|
}
|