|
|
@@ -15,7 +15,9 @@ import (
|
|
|
"log"
|
|
|
mrand "math/rand"
|
|
|
"net/http"
|
|
|
+ "net/netip"
|
|
|
"os"
|
|
|
+ "regexp"
|
|
|
"strconv"
|
|
|
"sync"
|
|
|
"sync/atomic"
|
|
|
@@ -24,6 +26,7 @@ import (
|
|
|
"tailscale.com/envknob"
|
|
|
"tailscale.com/net/netmon"
|
|
|
"tailscale.com/net/sockstats"
|
|
|
+ "tailscale.com/net/tsaddr"
|
|
|
"tailscale.com/tstime"
|
|
|
tslogger "tailscale.com/types/logger"
|
|
|
"tailscale.com/types/logid"
|
|
|
@@ -725,6 +728,8 @@ func (l *Logger) Logf(format string, args ...any) {
|
|
|
fmt.Fprintf(l, format, args...)
|
|
|
}
|
|
|
|
|
|
+var obscureIPs = envknob.RegisterBool("TS_OBSCURE_LOGGED_IPS")
|
|
|
+
|
|
|
// Write logs 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()
|
|
|
defer l.writeLock.Unlock()
|
|
|
|
|
|
@@ -757,6 +766,40 @@ func (l *Logger) Write(buf []byte) (int, error) {
|
|
|
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 (
|
|
|
openBracketV = []byte("[v")
|
|
|
v1 = []byte("[v1] ")
|