|
|
|
@ -15,7 +15,9 @@ import ( |
|
|
|
"log" |
|
|
|
"log" |
|
|
|
mrand "math/rand" |
|
|
|
mrand "math/rand" |
|
|
|
"net/http" |
|
|
|
"net/http" |
|
|
|
|
|
|
|
"net/netip" |
|
|
|
"os" |
|
|
|
"os" |
|
|
|
|
|
|
|
"regexp" |
|
|
|
"strconv" |
|
|
|
"strconv" |
|
|
|
"sync" |
|
|
|
"sync" |
|
|
|
"sync/atomic" |
|
|
|
"sync/atomic" |
|
|
|
@ -24,6 +26,7 @@ import ( |
|
|
|
"tailscale.com/envknob" |
|
|
|
"tailscale.com/envknob" |
|
|
|
"tailscale.com/net/netmon" |
|
|
|
"tailscale.com/net/netmon" |
|
|
|
"tailscale.com/net/sockstats" |
|
|
|
"tailscale.com/net/sockstats" |
|
|
|
|
|
|
|
"tailscale.com/net/tsaddr" |
|
|
|
"tailscale.com/tstime" |
|
|
|
"tailscale.com/tstime" |
|
|
|
tslogger "tailscale.com/types/logger" |
|
|
|
tslogger "tailscale.com/types/logger" |
|
|
|
"tailscale.com/types/logid" |
|
|
|
"tailscale.com/types/logid" |
|
|
|
@ -725,6 +728,8 @@ func (l *Logger) Logf(format string, args ...any) { |
|
|
|
fmt.Fprintf(l, format, args...) |
|
|
|
fmt.Fprintf(l, format, args...) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var obscureIPs = envknob.RegisterBool("TS_OBSCURE_LOGGED_IPS") |
|
|
|
|
|
|
|
|
|
|
|
// Write logs an encoded JSON blob.
|
|
|
|
// Write logs an encoded JSON blob.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// If the []byte passed to Write is not an encoded JSON blob,
|
|
|
|
// If the []byte passed to Write is not an encoded JSON blob,
|
|
|
|
@ -749,6 +754,10 @@ func (l *Logger) Write(buf []byte) (int, error) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if obscureIPs() { |
|
|
|
|
|
|
|
buf = redactIPs(buf) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
l.writeLock.Lock() |
|
|
|
l.writeLock.Lock() |
|
|
|
defer l.writeLock.Unlock() |
|
|
|
defer l.writeLock.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
@ -757,6 +766,40 @@ func (l *Logger) Write(buf []byte) (int, error) { |
|
|
|
return inLen, err |
|
|
|
return inLen, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
regexMatchesIPv6 = regexp.MustCompile(`([0-9a-fA-F]{1,4}):([0-9a-fA-F]{1,4}):([0-9a-fA-F:]{1,4})*`) |
|
|
|
|
|
|
|
regexMatchesIPv4 = regexp.MustCompile(`(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}`) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// redactIPs is a helper function used in Write() to redact IPs (other than tailscale IPs).
|
|
|
|
|
|
|
|
// This function takes a log line as a byte slice and
|
|
|
|
|
|
|
|
// uses regex matching to parse and find IP addresses. Based on if the IP address is IPv4 or
|
|
|
|
|
|
|
|
// IPv6, it parses and replaces the end of the addresses with an "x". This function returns the
|
|
|
|
|
|
|
|
// log line with the IPs redacted.
|
|
|
|
|
|
|
|
func redactIPs(buf []byte) []byte { |
|
|
|
|
|
|
|
out := regexMatchesIPv6.ReplaceAllFunc(buf, func(b []byte) []byte { |
|
|
|
|
|
|
|
ip, err := netip.ParseAddr(string(b)) |
|
|
|
|
|
|
|
if err != nil || tsaddr.IsTailscaleIP(ip) { |
|
|
|
|
|
|
|
return b // don't change this one
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prefix := bytes.Split(b, []byte(":")) |
|
|
|
|
|
|
|
return bytes.Join(append(prefix[:2], []byte("x")), []byte(":")) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
out = regexMatchesIPv4.ReplaceAllFunc(out, func(b []byte) []byte { |
|
|
|
|
|
|
|
ip, err := netip.ParseAddr(string(b)) |
|
|
|
|
|
|
|
if err != nil || tsaddr.IsTailscaleIP(ip) { |
|
|
|
|
|
|
|
return b // don't change this one
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prefix := bytes.Split(b, []byte(".")) |
|
|
|
|
|
|
|
return bytes.Join(append(prefix[:2], []byte("x.x")), []byte(".")) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return []byte(out) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
openBracketV = []byte("[v") |
|
|
|
openBracketV = []byte("[v") |
|
|
|
v1 = []byte("[v1] ") |
|
|
|
v1 = []byte("[v1] ") |
|
|
|
|