From aa51644a24577c0a4cd91a782b0b30a43417f5c5 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Mon, 2 Dec 2024 12:52:04 +0100 Subject: [PATCH] Replace yaml with json --- client/server/debug.go | 14 +-- client/server/debug_test.go | 194 ++++++++++++++++++++++++++++++++++++ go.mod | 6 -- go.sum | 14 --- 4 files changed, 201 insertions(+), 27 deletions(-) create mode 100644 client/server/debug_test.go diff --git a/client/server/debug.go b/client/server/debug.go index fc9add7f51f..6d4546480f0 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -17,8 +17,8 @@ import ( "strings" "time" - "buf.build/go/protoyaml" log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/encoding/protojson" "github.com/netbirdio/netbird/client/anonymize" "github.com/netbirdio/netbird/client/internal/peer" @@ -35,7 +35,7 @@ client.log: Most recent, anonymized log file of the NetBird client. routes.txt: Anonymized system routes, if --system-info flag was provided. interfaces.txt: Anonymized network interface information, if --system-info flag was provided. config.txt: Anonymized configuration information of the NetBird client. -network_map.yaml: Anonymized network map containing peer configurations, routes, DNS settings, and firewall rules. +network_map.json: Anonymized network map containing peer configurations, routes, DNS settings, and firewall rules. Anonymization Process @@ -283,19 +283,19 @@ func (s *Server) addNetworkMap(req *proto.DebugBundleRequest, anonymizer *anonym } } - options := protoyaml.MarshalOptions{ + options := protojson.MarshalOptions{ EmitUnpopulated: true, UseProtoNames: true, - Indent: 2, + Indent: " ", AllowPartial: true, } - yamlBytes, err := options.Marshal(networkMap) + jsonBytes, err := options.Marshal(networkMap) if err != nil { - return fmt.Errorf("generate yaml: %w", err) + return fmt.Errorf("generate json: %w", err) } - if err := addFileToZip(archive, bytes.NewReader(yamlBytes), "network_map.yaml"); err != nil { + if err := addFileToZip(archive, bytes.NewReader(jsonBytes), "network_map.json"); err != nil { return fmt.Errorf("add network map to zip: %w", err) } diff --git a/client/server/debug_test.go b/client/server/debug_test.go new file mode 100644 index 00000000000..b85ae9e4aae --- /dev/null +++ b/client/server/debug_test.go @@ -0,0 +1,194 @@ +package server + +import ( + "math/bits" + "net" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/netbirdio/netbird/client/anonymize" + mgmProto "github.com/netbirdio/netbird/management/proto" +) + +func TestAnonymizeNetworkMap(t *testing.T) { + // Create test network map with sensitive data + networkMap := &mgmProto.NetworkMap{ + PeerConfig: &mgmProto.PeerConfig{ + Address: "203.0.113.5", // Public IP that should be anonymized + Dns: "dns.corp.example.com", + Fqdn: "peer1.corp.example.com", + SshConfig: &mgmProto.SSHConfig{ + SshPubKey: []byte("ssh-rsa AAAAB3NzaC1..."), + }, + }, + RemotePeers: []*mgmProto.RemotePeerConfig{ + { + AllowedIps: []string{ + "203.0.113.1/32", // Public IP that should be anonymized + "2001:db8:1234::1/128", // Public IPv6 that should be anonymized + "192.168.1.1/32", // Private IP that should be preserved + "100.64.0.1/32", // CGNAT IP that should be preserved + "10.0.0.1/32", // Private IP that should be preserved + }, + Fqdn: "peer2.corp.example.com", + SshConfig: &mgmProto.SSHConfig{ + SshPubKey: []byte("ssh-rsa AAAAB3NzaC2..."), + }, + }, + }, + Routes: []*mgmProto.Route{ + { + Network: "198.51.100.0/24", // Public IP that should be anonymized + Domains: []string{"prod.example.com", "staging.example.com"}, + NetID: "net-123abc", + }, + }, + DNSConfig: &mgmProto.DNSConfig{ + NameServerGroups: []*mgmProto.NameServerGroup{ + { + NameServers: []*mgmProto.NameServer{ + {IP: "8.8.8.8"}, // Google DNS that should be preserved + {IP: "1.1.1.1"}, // Cloudflare DNS that should be preserved + {IP: "203.0.113.53"}, // Public DNS that should be anonymized + }, + Domains: []string{"example.com", "internal.example.com"}, + }, + }, + CustomZones: []*mgmProto.CustomZone{ + { + Domain: "custom.example.com", + Records: []*mgmProto.SimpleRecord{ + { + Name: "www.custom.example.com", + Type: 1, // A record + RData: "203.0.113.10", // Public IP that should be anonymized + }, + { + Name: "internal.custom.example.com", + Type: 1, // A record + RData: "192.168.1.10", // Private IP that should be preserved + }, + }, + }, + }, + }, + FirewallRules: []*mgmProto.FirewallRule{ + { + PeerIP: "203.0.113.100", // Public IP that should be anonymized + }, + { + PeerIP: "192.168.1.100", // Private IP that should be preserved + }, + }, + RoutesFirewallRules: []*mgmProto.RouteFirewallRule{ + { + SourceRanges: []string{"203.0.113.0/24"}, // Public IP that should be anonymized + Destination: "198.51.100.0/24", // Public IP that should be anonymized + }, + { + SourceRanges: []string{"192.168.0.0/16"}, // Private IP that should be preserved + Destination: "10.0.0.0/8", // Private IP that should be preserved + }, + }, + } + + // Create anonymizer with test addresses + anonymizer := anonymize.NewAnonymizer(anonymize.DefaultAddresses()) + + // Anonymize the network map + err := anonymizeNetworkMap(networkMap, anonymizer) + require.NoError(t, err) + + // Test PeerConfig anonymization + peerCfg := networkMap.PeerConfig + require.NotEqual(t, "203.0.113.5", peerCfg.Address, "Public IP should be anonymized") + t.Logf("dns: %s, fqdn: %s", peerCfg.Dns, peerCfg.Fqdn) + require.NotEqual(t, "dns.corp.example.com", peerCfg.Dns) + require.NotEqual(t, "peer1.corp.example.com", peerCfg.Fqdn) + require.True(t, strings.HasSuffix(peerCfg.Dns, ".domain")) + require.True(t, strings.HasSuffix(peerCfg.Fqdn, ".domain")) + require.Equal(t, []byte("ssh-placeholder-key"), peerCfg.SshConfig.SshPubKey) + + // Test RemotePeers anonymization + remotePeer := networkMap.RemotePeers[0] + + // Check that public IPs are anonymized but private IPs are preserved + for _, allowedIP := range remotePeer.AllowedIps { + ip, _, err := net.ParseCIDR(allowedIP) + require.NoError(t, err) + + if ip.IsPrivate() || isInCGNATRange(ip) { + require.Contains(t, []string{ + "192.168.1.1/32", + "100.64.0.1/32", + "10.0.0.1/32", + }, allowedIP, "Private/CGNAT IP should be preserved") + } else { + require.NotContains(t, []string{ + "203.0.113.1/32", + "2001:db8:1234::1/128", + }, allowedIP, "Public IP should be anonymized") + } + } + + // Test DNS config anonymization + dnsConfig := networkMap.DNSConfig + nameServers := dnsConfig.NameServerGroups[0].NameServers + + // Well-known DNS servers should be preserved + require.Equal(t, "8.8.8.8", nameServers[0].IP) + require.Equal(t, "1.1.1.1", nameServers[1].IP) + + // Public DNS server should be anonymized + require.NotEqual(t, "203.0.113.53", nameServers[2].IP) + + // Test CustomZones anonymization + customZone := dnsConfig.CustomZones[0] + require.True(t, strings.HasSuffix(customZone.Domain, ".domain")) + + // Test records anonymization + for _, record := range customZone.Records { + require.True(t, strings.HasSuffix(record.Name, ".domain")) + + ip := net.ParseIP(record.RData) + if ip != nil && !ip.IsPrivate() { + require.NotEqual(t, "203.0.113.10", record.RData, "Public IP in record should be anonymized") + } else if ip != nil && ip.IsPrivate() { + require.Equal(t, "192.168.1.10", record.RData, "Private IP in record should be preserved") + } + } + + // Test FirewallRules anonymization + require.NotEqual(t, "203.0.113.100", networkMap.FirewallRules[0].PeerIP, "Public IP should be anonymized") + require.Equal(t, "192.168.1.100", networkMap.FirewallRules[1].PeerIP, "Private IP should be preserved") + + // Test RouteFirewallRules anonymization + routeRule := networkMap.RoutesFirewallRules[0] + require.NotEqual(t, "203.0.113.0/24", routeRule.SourceRanges[0], "Public IP range should be anonymized") + require.NotEqual(t, "198.51.100.0/24", routeRule.Destination, "Public IP range should be anonymized") + + privateRouteRule := networkMap.RoutesFirewallRules[1] + require.Equal(t, "192.168.0.0/16", privateRouteRule.SourceRanges[0], "Private IP range should be preserved") + require.Equal(t, "10.0.0.0/8", privateRouteRule.Destination, "Private IP range should be preserved") + +} + +// Helper function to check if IP is in CGNAT range +func isInCGNATRange(ip net.IP) bool { + cgnat := net.IPNet{ + IP: net.ParseIP("100.64.0.0"), + Mask: net.CIDRMask(10, 32), + } + return cgnat.Contains(ip) +} + +// Helper function to count netmask bits +func countNetmaskBits(mask net.IPMask) int { + bitss := 0 + for _, b := range mask { + bitss += bits.OnesCount8(b) + } + return bitss +} diff --git a/go.mod b/go.mod index 66ad346ec8d..c08713f2bd4 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,6 @@ require ( ) require ( - buf.build/go/protoyaml v0.2.0 fyne.io/fyne/v2 v2.5.0 fyne.io/systray v1.11.0 github.com/TheJumpCloud/jcapi-go v3.0.0+incompatible @@ -104,7 +103,6 @@ require ( ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 // indirect cloud.google.com/go/auth v0.3.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect @@ -115,7 +113,6 @@ require ( github.com/Microsoft/hcsshim v0.12.3 // indirect github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect @@ -132,7 +129,6 @@ require ( github.com/aws/smithy-go v1.20.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect - github.com/bufbuild/protovalidate-go v0.6.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/containerd v1.7.16 // indirect @@ -160,7 +156,6 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/cel-go v0.21.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect @@ -212,7 +207,6 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect - github.com/stoewer/go-strcase v1.3.0 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect diff --git a/go.sum b/go.sum index b7da4f8bd6a..5519d6ded99 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 h1:SZRVx928rbYZ6hEKUIN+vtGDkl7uotABRWGY4OAg5gM= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2/go.mod h1:ylS4c28ACSI59oJrOdW4pHS4n0Hw4TgSPHn8rpHl4Yw= -buf.build/go/protoyaml v0.2.0 h1:2g3OHjtLDqXBREIOjpZGHmQ+U/4mkN1YiQjxNB68Ip8= -buf.build/go/protoyaml v0.2.0/go.mod h1:L/9QvTDkTWcDTzAL6HMfN+mYC6CmZRm2KnsUA054iL0= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -80,8 +76,6 @@ github.com/allegro/bigcache/v3 v3.0.2/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpx github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -119,8 +113,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw= github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/bufbuild/protovalidate-go v0.6.3 h1:wxQyzW035zM16Binbaz/nWAzS12dRIXhZdSUWRY7Fv0= -github.com/bufbuild/protovalidate-go v0.6.3/go.mod h1:J4PtwP9Z2YAGgB0+o+tTWEDtLtXvz/gfhFZD8pbzM/U= github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU= github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= @@ -192,8 +184,6 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= @@ -309,8 +299,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= -github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -670,8 +658,6 @@ github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiY github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= -github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=