|
|
@ -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] ")
|
|
|
|