Skip to content

Commit

Permalink
tailscale/logtail: redact public ipv6 and ipv4 ip addresses within ta…
Browse files Browse the repository at this point in the history
…ilscaled.

Updates #15664

Signed-off-by: Anishka Singh <anishka@tailscale.com>
  • Loading branch information
as2643 committed Dec 13, 2023
1 parent b62a3fc commit f789d98
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
38 changes: 38 additions & 0 deletions logtail/logtail.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ import (
"log"
mrand "math/rand"
"net/http"
"net/netip"
"os"
"regexp"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"

"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"
Expand Down Expand Up @@ -725,6 +729,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,
Expand All @@ -749,6 +755,10 @@ func (l *Logger) Write(buf []byte) (int, error) {
}
}

if obscureIPs() {
buf = redactIPs(buf)
}

l.writeLock.Lock()
defer l.writeLock.Unlock()

Expand All @@ -757,6 +767,34 @@ func (l *Logger) Write(buf []byte) (int, error) {
return inLen, err
}

func redactIPs(buf []byte) []byte {
regexMatchesIPv6 := regexp.MustCompile(`([0-9a-fA-F]{1,4}):([0-9a-fA-F]{1,4}):.\S*`)
regexMatchesIPv4 := regexp.MustCompile(`(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}`)

out := regexMatchesIPv6.ReplaceAllStringFunc(string(buf), func(s string) string {
ip, err := netip.ParseAddr(s)

if err != nil || tsaddr.IsTailscaleIP(ip) {
return s // don't change this one
}

prefix := strings.Split(s, ":")

return strings.Join(append(prefix[:2], "x"), ":")
})

out = regexMatchesIPv4.ReplaceAllStringFunc(string(out), func(s string) string {
ip, err := netip.ParseAddr(s)
if err != nil || tsaddr.IsTailscaleIP(ip) {
return s // don't change this one
}
prefix := strings.Split(s, ".")
return strings.Join(append(prefix[:2], "x.x"), ".")
})

return []byte(out)
}

var (
openBracketV = []byte("[v")
v1 = []byte("[v1] ")
Expand Down
76 changes: 76 additions & 0 deletions logtail/logtail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"testing"
"time"

"tailscale.com/envknob"
"tailscale.com/tstest"
"tailscale.com/tstime"
)
Expand Down Expand Up @@ -406,3 +407,78 @@ func TestLoggerWriteResult(t *testing.T) {
t.Errorf("mismatch.\n got: %#q\nwant: %#q", back, want)
}
}
func TestRedact(t *testing.T) {
envknob.Setenv("TS_OBSCURE_LOGGED_IPS", "true")
tests := []struct {
in string
want string
}{
// tests for ipv4 addresses
{
"120.100.30.47",
"120.100.x.x",
},
{
"192.167.0.1",
"192.167.x.x",
},
{
"node [5Btdd] d:e89a3384f526d251 now using 10.0.0.222:41641 mtu=1360 tx=d81a8a35a0ce",
"node [5Btdd] d:e89a3384f526d251 now using 10.0.x.x:41641 mtu=1360 tx=d81a8a35a0ce",
},
//tests for ipv6 addresses
{
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"2001:0db8:x",
},
{
"2345:0425:2CA1:0000:0000:0567:5673:23b5",
"2345:0425:x",
},
{
"2041:0000:140F::875B:131B",
"2041:0000:x",
},
{
"node [5Btdd] d:e89a3384f526d251 now using 2051:0000:140F::875B:131C mtu=1360 tx=d81a8a35a0ce",
"node [5Btdd] d:e89a3384f526d251 now using 2051:0000:x mtu=1360 tx=d81a8a35a0ce",
},
//tests for tailscale ip addresses
{
"100.64.5.6",
"100.64.5.6",
},
{
"fd7a:115c:a1e0::/96",
"fd7a:115c:a1e0::/96",
},
//tests for ipv6 and ipv4 together
{
"192.167.0.1 2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"192.167.x.x 2001:0db8:x",
},
{
"node [5Btdd] d:e89a3384f526d251 now using 10.0.0.222:41641 mtu=1360 tx=d81a8a35a0ce 2345:0425:2CA1::0567:5673:23b5",
"node [5Btdd] d:e89a3384f526d251 now using 10.0.x.x:41641 mtu=1360 tx=d81a8a35a0ce 2345:0425:x",
},
{
"100.64.5.6 2091:0db8:85a3:0000:0000:8a2e:0370:7334",
"100.64.5.6 2091:0db8:x",
},
{
"192.167.0.1 120.100.30.47 2041:0000:140F::875B:131B",
"192.167.x.x 120.100.x.x 2041:0000:x",
},
{
"fd7a:115c:a1e0::/96 192.167.0.1 2001:0db8:85a3:0000:0000:8a2e:0370:7334",
"fd7a:115c:a1e0::/96 192.167.x.x 2001:0db8:x",
},
}

for _, tt := range tests {
gotBuf := redactIPs([]byte(tt.in))
if string(gotBuf) != tt.want {
t.Errorf("for %q,\n got: %#q\nwant: %#q\n", tt.in, gotBuf, tt.want)
}
}
}

0 comments on commit f789d98

Please sign in to comment.