From 86e0f9b91268ba49214accea80f0b81e23579506 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 16 Jun 2024 11:34:11 -0700 Subject: [PATCH] net/ipset, wgengine/filter/filtertype: add split-out packages This moves NewContainsIPFunc from tsaddr to new ipset package. And wgengine/filter types gets split into wgengine/filter/filtertype, so netmap (and thus the CLI, etc) doesn't need to bring in ipset, bart, etc. Then add a test making sure the CLI deps don't regress. Updates #1278 Change-Id: Ia246d6d9502bbefbdeacc4aef1bed9c8b24f54d5 Signed-off-by: Brad Fitzpatrick --- cmd/derper/depaware.txt | 12 +- cmd/derper/derper_test.go | 2 + cmd/stund/depaware.txt | 2 - cmd/tailscale/depaware.txt | 10 +- cmd/tailscale/tailscale_test.go | 4 + cmd/tailscaled/depaware.txt | 2 + ipn/ipnlocal/local.go | 5 +- net/ipset/ipset.go | 80 ++++++++++ net/ipset/ipset_test.go | 149 ++++++++++++++++++ net/tsaddr/tsaddr.go | 72 --------- net/tsaddr/tsaddr_test.go | 139 ---------------- types/netmap/netmap.go | 4 +- wgengine/filter/filter.go | 30 ++-- wgengine/filter/filter_test.go | 8 +- wgengine/filter/filtertype/filtertype.go | 98 ++++++++++++ .../filtertype_clone.go} | 2 +- wgengine/filter/match.go | 96 +---------- wgengine/filter/tailcfg.go | 4 +- wgengine/netstack/netstack.go | 7 +- wgengine/userspace.go | 9 +- 20 files changed, 388 insertions(+), 347 deletions(-) create mode 100644 net/ipset/ipset.go create mode 100644 net/ipset/ipset_test.go create mode 100644 wgengine/filter/filtertype/filtertype.go rename wgengine/filter/{filter_clone.go => filtertype/filtertype_clone.go} (98%) diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt index 974716468..4ed20fd86 100644 --- a/cmd/derper/depaware.txt +++ b/cmd/derper/depaware.txt @@ -6,12 +6,10 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa W github.com/alexbrainman/sspi/internal/common from github.com/alexbrainman/sspi/negotiate W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy github.com/beorn7/perks/quantile from github.com/prometheus/client_golang/prometheus - github.com/bits-and-blooms/bitset from github.com/gaissmai/bart 💣 github.com/cespare/xxhash/v2 from github.com/prometheus/client_golang/prometheus L github.com/coreos/go-iptables/iptables from tailscale.com/util/linuxfw W 💣 github.com/dblohm7/wingoes from tailscale.com/util/winutil github.com/fxamacker/cbor/v2 from tailscale.com/tka - github.com/gaissmai/bart from tailscale.com/net/tsaddr github.com/golang/groupcache/lru from tailscale.com/net/dnscache L github.com/google/nftables from tailscale.com/util/linuxfw L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt @@ -48,7 +46,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa L github.com/vishvananda/netns from github.com/tailscale/netlink+ github.com/x448/float16 from github.com/fxamacker/cbor/v2 💣 go4.org/mem from tailscale.com/client/tailscale+ - go4.org/netipx from tailscale.com/net/tsaddr+ + go4.org/netipx from tailscale.com/net/tsaddr W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/netmon+ google.golang.org/protobuf/encoding/protodelim from github.com/prometheus/common/expfmt google.golang.org/protobuf/encoding/prototext from github.com/prometheus/common/expfmt+ @@ -97,14 +95,12 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa tailscale.com/ipn/ipnstate from tailscale.com/client/tailscale+ tailscale.com/metrics from tailscale.com/cmd/derper+ tailscale.com/net/dnscache from tailscale.com/derp/derphttp - tailscale.com/net/flowtrack from tailscale.com/net/packet+ tailscale.com/net/ktimeout from tailscale.com/cmd/derper tailscale.com/net/netaddr from tailscale.com/ipn+ tailscale.com/net/netknob from tailscale.com/net/netns 💣 tailscale.com/net/netmon from tailscale.com/derp/derphttp+ tailscale.com/net/netns from tailscale.com/derp/derphttp tailscale.com/net/netutil from tailscale.com/client/tailscale - tailscale.com/net/packet from tailscale.com/wgengine/filter tailscale.com/net/sockstats from tailscale.com/derp/derphttp tailscale.com/net/stun from tailscale.com/net/stunserver tailscale.com/net/stunserver from tailscale.com/cmd/derper @@ -121,13 +117,13 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa W tailscale.com/tsconst from tailscale.com/net/netmon tailscale.com/tstime from tailscale.com/derp+ tailscale.com/tstime/mono from tailscale.com/tstime/rate - tailscale.com/tstime/rate from tailscale.com/derp+ + tailscale.com/tstime/rate from tailscale.com/derp tailscale.com/tsweb from tailscale.com/cmd/derper tailscale.com/tsweb/promvarz from tailscale.com/tsweb tailscale.com/tsweb/varz from tailscale.com/tsweb+ tailscale.com/types/dnstype from tailscale.com/tailcfg tailscale.com/types/empty from tailscale.com/ipn - tailscale.com/types/ipproto from tailscale.com/net/flowtrack+ + tailscale.com/types/ipproto from tailscale.com/tailcfg+ tailscale.com/types/key from tailscale.com/client/tailscale+ tailscale.com/types/lazy from tailscale.com/version+ tailscale.com/types/logger from tailscale.com/cmd/derper+ @@ -162,7 +158,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa W 💣 tailscale.com/util/winutil/winenv from tailscale.com/hostinfo+ tailscale.com/version from tailscale.com/derp+ tailscale.com/version/distro from tailscale.com/envknob+ - tailscale.com/wgengine/filter from tailscale.com/types/netmap + tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap golang.org/x/crypto/acme from golang.org/x/crypto/acme/autocert golang.org/x/crypto/acme/autocert from tailscale.com/cmd/derper golang.org/x/crypto/argon2 from tailscale.com/tka diff --git a/cmd/derper/derper_test.go b/cmd/derper/derper_test.go index 79cde2a82..1af7c3abe 100644 --- a/cmd/derper/derper_test.go +++ b/cmd/derper/derper_test.go @@ -104,6 +104,8 @@ func TestDeps(t *testing.T) { "gvisor.dev/gvisor/pkg/cpuid": "https://github.com/tailscale/tailscale/issues/9756", "gvisor.dev/gvisor/pkg/tcpip": "https://github.com/tailscale/tailscale/issues/9756", "gvisor.dev/gvisor/pkg/tcpip/header": "https://github.com/tailscale/tailscale/issues/9756", + "tailscale.com/net/packet": "not needed in derper", + "github.com/gaissmai/bart": "not needed in derper", }, }.Check(t) } diff --git a/cmd/stund/depaware.txt b/cmd/stund/depaware.txt index 07a1f33b2..7395e0f38 100644 --- a/cmd/stund/depaware.txt +++ b/cmd/stund/depaware.txt @@ -1,9 +1,7 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depaware) github.com/beorn7/perks/quantile from github.com/prometheus/client_golang/prometheus - github.com/bits-and-blooms/bitset from github.com/gaissmai/bart 💣 github.com/cespare/xxhash/v2 from github.com/prometheus/client_golang/prometheus - github.com/gaissmai/bart from tailscale.com/net/tsaddr github.com/google/uuid from tailscale.com/util/fastuuid 💣 github.com/prometheus/client_golang/prometheus from tailscale.com/tsweb/promvarz github.com/prometheus/client_golang/prometheus/internal from github.com/prometheus/client_golang/prometheus diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index 449ff4687..fa484571e 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -5,12 +5,10 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/internal/common+ W github.com/alexbrainman/sspi/internal/common from github.com/alexbrainman/sspi/negotiate W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy - github.com/bits-and-blooms/bitset from github.com/gaissmai/bart L github.com/coreos/go-iptables/iptables from tailscale.com/util/linuxfw W 💣 github.com/dblohm7/wingoes from github.com/dblohm7/wingoes/pe+ W 💣 github.com/dblohm7/wingoes/pe from tailscale.com/util/winutil/authenticode github.com/fxamacker/cbor/v2 from tailscale.com/tka - github.com/gaissmai/bart from tailscale.com/net/tsaddr github.com/golang/groupcache/lru from tailscale.com/net/dnscache L github.com/google/nftables from tailscale.com/util/linuxfw L 💣 github.com/google/nftables/alignedbuff from github.com/google/nftables/xt @@ -59,7 +57,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep L github.com/vishvananda/netns from github.com/tailscale/netlink+ github.com/x448/float16 from github.com/fxamacker/cbor/v2 💣 go4.org/mem from tailscale.com/client/tailscale+ - go4.org/netipx from tailscale.com/net/tsaddr+ + go4.org/netipx from tailscale.com/net/tsaddr W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/netmon+ k8s.io/client-go/util/homedir from tailscale.com/cmd/tailscale/cli nhooyr.io/websocket from tailscale.com/control/controlhttp+ @@ -98,7 +96,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback tailscale.com/net/dnscache from tailscale.com/control/controlhttp+ tailscale.com/net/dnsfallback from tailscale.com/control/controlhttp - tailscale.com/net/flowtrack from tailscale.com/net/packet+ + tailscale.com/net/flowtrack from tailscale.com/net/packet tailscale.com/net/netaddr from tailscale.com/ipn+ tailscale.com/net/netcheck from tailscale.com/cmd/tailscale/cli tailscale.com/net/neterror from tailscale.com/net/netcheck+ @@ -106,7 +104,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep 💣 tailscale.com/net/netmon from tailscale.com/cmd/tailscale/cli+ tailscale.com/net/netns from tailscale.com/derp/derphttp+ tailscale.com/net/netutil from tailscale.com/client/tailscale+ - tailscale.com/net/packet from tailscale.com/wgengine/capture+ + tailscale.com/net/packet from tailscale.com/wgengine/capture tailscale.com/net/ping from tailscale.com/net/netcheck tailscale.com/net/portmapper from tailscale.com/cmd/tailscale/cli+ tailscale.com/net/sockstats from tailscale.com/control/controlhttp+ @@ -170,7 +168,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/version from tailscale.com/client/web+ tailscale.com/version/distro from tailscale.com/client/web+ tailscale.com/wgengine/capture from tailscale.com/cmd/tailscale/cli - tailscale.com/wgengine/filter from tailscale.com/types/netmap + tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap golang.org/x/crypto/argon2 from tailscale.com/tka golang.org/x/crypto/blake2b from golang.org/x/crypto/argon2+ golang.org/x/crypto/blake2s from tailscale.com/clientupdate/distsign+ diff --git a/cmd/tailscale/tailscale_test.go b/cmd/tailscale/tailscale_test.go index 6c8c497b2..dc477fb6e 100644 --- a/cmd/tailscale/tailscale_test.go +++ b/cmd/tailscale/tailscale_test.go @@ -17,6 +17,10 @@ func TestDeps(t *testing.T) { "gvisor.dev/gvisor/pkg/cpuid": "https://github.com/tailscale/tailscale/issues/9756", "gvisor.dev/gvisor/pkg/tcpip": "https://github.com/tailscale/tailscale/issues/9756", "gvisor.dev/gvisor/pkg/tcpip/header": "https://github.com/tailscale/tailscale/issues/9756", + "tailscale.com/wgengine/filter": "brings in bart, etc", + "github.com/bits-and-blooms/bitset": "unneeded in CLI", + "github.com/gaissmai/bart": "unneeded in CLI", + "tailscale.com/net/ipset": "unneeded in CLI", }, }.Check(t) } diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index c3d958e9d..5a680ff04 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -295,6 +295,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/net/dnscache from tailscale.com/control/controlclient+ tailscale.com/net/dnsfallback from tailscale.com/cmd/tailscaled+ tailscale.com/net/flowtrack from tailscale.com/net/packet+ + tailscale.com/net/ipset from tailscale.com/ipn/ipnlocal+ tailscale.com/net/netaddr from tailscale.com/ipn+ tailscale.com/net/netcheck from tailscale.com/wgengine/magicsock+ tailscale.com/net/neterror from tailscale.com/net/dns/resolver+ @@ -408,6 +409,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/wgengine from tailscale.com/cmd/tailscaled+ tailscale.com/wgengine/capture from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/filter from tailscale.com/control/controlclient+ + tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+ 💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/netlog from tailscale.com/wgengine tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index a77adf33f..bfb71f0b2 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -61,6 +61,7 @@ "tailscale.com/net/dns" "tailscale.com/net/dnscache" "tailscale.com/net/dnsfallback" + "tailscale.com/net/ipset" "tailscale.com/net/netcheck" "tailscale.com/net/netkernelconf" "tailscale.com/net/netmon" @@ -2761,13 +2762,13 @@ func (b *LocalBackend) setAtomicValuesFromPrefsLocked(p ipn.PrefsView) { b.setExposeRemoteWebClientAtomicBoolLocked(p) if !p.Valid() { - b.containsViaIPFuncAtomic.Store(tsaddr.FalseContainsIPFunc()) + b.containsViaIPFuncAtomic.Store(ipset.FalseContainsIPFunc()) b.setTCPPortsIntercepted(nil) b.lastServeConfJSON = mem.B(nil) b.serveConfig = ipn.ServeConfigView{} } else { filtered := tsaddr.FilterPrefixesCopy(p.AdvertiseRoutes(), tsaddr.IsViaPrefix) - b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(views.SliceOf(filtered))) + b.containsViaIPFuncAtomic.Store(ipset.NewContainsIPFunc(views.SliceOf(filtered))) b.setTCPPortsInterceptedFromNetmapAndPrefsLocked(p) } } diff --git a/net/ipset/ipset.go b/net/ipset/ipset.go new file mode 100644 index 000000000..45dc6486f --- /dev/null +++ b/net/ipset/ipset.go @@ -0,0 +1,80 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package ipset provides code for creating efficient IP-in-set lookup functions +// with different implementations depending on the set. +package ipset + +import ( + "net/netip" + + "github.com/gaissmai/bart" + "tailscale.com/types/views" +) + +// FalseContainsIPFunc is shorthand for NewContainsIPFunc(views.Slice[netip.Prefix]{}). +func FalseContainsIPFunc() func(ip netip.Addr) bool { + return func(ip netip.Addr) bool { return false } +} + +// pathForTest is a test hook for NewContainsIPFunc, to test that it took the +// right construction path. +var pathForTest = func(string) {} + +// NewContainsIPFunc returns a func that reports whether ip is in addrs. +// +// The returned func is optimized for the length of contents of addrs. +func NewContainsIPFunc(addrs views.Slice[netip.Prefix]) func(ip netip.Addr) bool { + // Specialize the three common cases: no address, just IPv4 + // (or just IPv6), and both IPv4 and IPv6. + if addrs.Len() == 0 { + pathForTest("empty") + return func(netip.Addr) bool { return false } + } + // If any addr is a prefix with more than a single IP, then do either a + // linear scan or a bart table, depending on the number of addrs. + if addrs.ContainsFunc(func(p netip.Prefix) bool { return !p.IsSingleIP() }) { + if addrs.Len() > 6 { + pathForTest("bart") + // Built a bart table. + t := &bart.Table[struct{}]{} + for i := range addrs.Len() { + t.Insert(addrs.At(i), struct{}{}) + } + return func(ip netip.Addr) bool { + _, ok := t.Get(ip) + return ok + } + } else { + pathForTest("linear-contains") + // Small enough to do a linear search. + acopy := addrs.AsSlice() + return func(ip netip.Addr) bool { + for _, a := range acopy { + if a.Contains(ip) { + return true + } + } + return false + } + } + } + // Fast paths for 1 and 2 IPs: + if addrs.Len() == 1 { + pathForTest("one-ip") + a := addrs.At(0) + return func(ip netip.Addr) bool { return ip == a.Addr() } + } + if addrs.Len() == 2 { + pathForTest("two-ip") + a, b := addrs.At(0), addrs.At(1) + return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() } + } + // General case: + pathForTest("ip-map") + m := map[netip.Addr]bool{} + for i := range addrs.Len() { + m[addrs.At(i).Addr()] = true + } + return func(ip netip.Addr) bool { return m[ip] } +} diff --git a/net/ipset/ipset_test.go b/net/ipset/ipset_test.go new file mode 100644 index 000000000..7060df5b3 --- /dev/null +++ b/net/ipset/ipset_test.go @@ -0,0 +1,149 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package ipset + +import ( + "net/netip" + "testing" + + "tailscale.com/tstest" + "tailscale.com/types/views" +) + +func pp(ss ...string) (ret []netip.Prefix) { + for _, s := range ss { + ret = append(ret, netip.MustParsePrefix(s)) + } + return +} + +func aa(ss ...string) (ret []netip.Addr) { + for _, s := range ss { + ret = append(ret, netip.MustParseAddr(s)) + } + return +} + +var newContainsIPFuncTests = []struct { + name string + pfx []netip.Prefix + want string + wantIn []netip.Addr + wantOut []netip.Addr +}{ + { + name: "empty", + pfx: pp(), + want: "empty", + wantOut: aa("8.8.8.8"), + }, + { + name: "cidr-list-1", + pfx: pp("10.0.0.0/8"), + want: "linear-contains", + wantIn: aa("10.0.0.1", "10.2.3.4"), + wantOut: aa("8.8.8.8"), + }, + { + name: "cidr-list-2", + pfx: pp("1.0.0.0/8", "3.0.0.0/8"), + want: "linear-contains", + wantIn: aa("1.0.0.1", "3.0.0.1"), + wantOut: aa("2.0.0.1"), + }, + { + name: "cidr-list-3", + pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8"), + want: "linear-contains", + wantIn: aa("1.0.0.1", "5.0.0.1"), + wantOut: aa("2.0.0.1"), + }, + { + name: "cidr-list-4", + pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8"), + want: "linear-contains", + wantIn: aa("1.0.0.1", "7.0.0.1"), + wantOut: aa("2.0.0.1"), + }, + { + name: "cidr-list-5", + pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8", "9.0.0.0/8"), + want: "linear-contains", + wantIn: aa("1.0.0.1", "9.0.0.1"), + wantOut: aa("2.0.0.1"), + }, + { + name: "cidr-list-10", + pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8", "9.0.0.0/8", + "11.0.0.0/8", "13.0.0.0/8", "15.0.0.0/8", "17.0.0.0/8", "19.0.0.0/8"), + want: "bart", // big enough that bart is faster than linear-contains + wantIn: aa("1.0.0.1", "19.0.0.1"), + wantOut: aa("2.0.0.1"), + }, + { + name: "one-ip", + pfx: pp("10.1.0.0/32"), + want: "one-ip", + wantIn: aa("10.1.0.0"), + wantOut: aa("10.0.0.9"), + }, + { + name: "two-ip", + pfx: pp("10.1.0.0/32", "10.2.0.0/32"), + want: "two-ip", + wantIn: aa("10.1.0.0", "10.2.0.0"), + wantOut: aa("8.8.8.8"), + }, + { + name: "three-ip", + pfx: pp("10.1.0.0/32", "10.2.0.0/32", "10.3.0.0/32"), + want: "ip-map", + wantIn: aa("10.1.0.0", "10.2.0.0"), + wantOut: aa("8.8.8.8"), + }, +} + +func BenchmarkNewContainsIPFunc(b *testing.B) { + for _, tt := range newContainsIPFuncTests { + b.Run(tt.name, func(b *testing.B) { + f := NewContainsIPFunc(views.SliceOf(tt.pfx)) + for i := 0; i < b.N; i++ { + for _, ip := range tt.wantIn { + if !f(ip) { + b.Fatal("unexpected false") + } + } + for _, ip := range tt.wantOut { + if f(ip) { + b.Fatal("unexpected true") + } + } + } + }) + } +} + +func TestNewContainsIPFunc(t *testing.T) { + for _, tt := range newContainsIPFuncTests { + t.Run(tt.name, func(t *testing.T) { + var got string + tstest.Replace(t, &pathForTest, func(path string) { got = path }) + + f := NewContainsIPFunc(views.SliceOf(tt.pfx)) + if got != tt.want { + t.Errorf("func type = %q; want %q", got, tt.want) + } + for _, ip := range tt.wantIn { + if !f(ip) { + t.Errorf("match(%v) = false; want true", ip) + } + } + for _, ip := range tt.wantOut { + if f(ip) { + t.Errorf("match(%v) = true; want false", ip) + } + } + }) + } +} diff --git a/net/tsaddr/tsaddr.go b/net/tsaddr/tsaddr.go index ed1e12a93..b75a2662d 100644 --- a/net/tsaddr/tsaddr.go +++ b/net/tsaddr/tsaddr.go @@ -11,7 +11,6 @@ "slices" "sync" - "github.com/gaissmai/bart" "go4.org/netipx" "tailscale.com/net/netaddr" "tailscale.com/types/views" @@ -161,77 +160,6 @@ type oncePrefix struct { v netip.Prefix } -// FalseContainsIPFunc is shorthand for NewContainsIPFunc(views.Slice[netip.Prefix]{}). -func FalseContainsIPFunc() func(ip netip.Addr) bool { - return func(ip netip.Addr) bool { return false } -} - -// pathForTest is a test hook for NewContainsIPFunc, to test that it took the -// right construction path. -var pathForTest = func(string) {} - -// NewContainsIPFunc returns a func that reports whether ip is in addrs. -// -// It's optimized for the cases of addrs being empty and addrs -// containing 1 or 2 single-IP prefixes (such as one IPv4 address and -// one IPv6 address). -// -// Otherwise the implementation is somewhat slow. -func NewContainsIPFunc(addrs views.Slice[netip.Prefix]) func(ip netip.Addr) bool { - // Specialize the three common cases: no address, just IPv4 - // (or just IPv6), and both IPv4 and IPv6. - if addrs.Len() == 0 { - pathForTest("empty") - return func(netip.Addr) bool { return false } - } - // If any addr is a prefix with more than a single IP, then do either a - // linear scan or a bart table, depending on the number of addrs. - if addrs.ContainsFunc(func(p netip.Prefix) bool { return !p.IsSingleIP() }) { - if addrs.Len() > 6 { - pathForTest("bart") - // Built a bart table. - t := &bart.Table[struct{}]{} - for i := range addrs.Len() { - t.Insert(addrs.At(i), struct{}{}) - } - return func(ip netip.Addr) bool { - _, ok := t.Get(ip) - return ok - } - } else { - pathForTest("linear-contains") - // Small enough to do a linear search. - acopy := addrs.AsSlice() - return func(ip netip.Addr) bool { - for _, a := range acopy { - if a.Contains(ip) { - return true - } - } - return false - } - } - } - // Fast paths for 1 and 2 IPs: - if addrs.Len() == 1 { - pathForTest("one-ip") - a := addrs.At(0) - return func(ip netip.Addr) bool { return ip == a.Addr() } - } - if addrs.Len() == 2 { - pathForTest("two-ip") - a, b := addrs.At(0), addrs.At(1) - return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() } - } - // General case: - pathForTest("ip-map") - m := map[netip.Addr]bool{} - for i := range addrs.Len() { - m[addrs.At(i).Addr()] = true - } - return func(ip netip.Addr) bool { return m[ip] } -} - // PrefixesContainsIP reports whether any prefix in ipp contains ip. func PrefixesContainsIP(ipp []netip.Prefix, ip netip.Addr) bool { for _, r := range ipp { diff --git a/net/tsaddr/tsaddr_test.go b/net/tsaddr/tsaddr_test.go index 3de85670d..dccc34271 100644 --- a/net/tsaddr/tsaddr_test.go +++ b/net/tsaddr/tsaddr_test.go @@ -8,8 +8,6 @@ "testing" "tailscale.com/net/netaddr" - "tailscale.com/tstest" - "tailscale.com/types/views" ) func TestInCrostiniRange(t *testing.T) { @@ -67,143 +65,6 @@ func TestCGNATRange(t *testing.T) { } } -func pp(ss ...string) (ret []netip.Prefix) { - for _, s := range ss { - ret = append(ret, netip.MustParsePrefix(s)) - } - return -} - -func aa(ss ...string) (ret []netip.Addr) { - for _, s := range ss { - ret = append(ret, netip.MustParseAddr(s)) - } - return -} - -var newContainsIPFuncTests = []struct { - name string - pfx []netip.Prefix - want string - wantIn []netip.Addr - wantOut []netip.Addr -}{ - { - name: "empty", - pfx: pp(), - want: "empty", - wantOut: aa("8.8.8.8"), - }, - { - name: "cidr-list-1", - pfx: pp("10.0.0.0/8"), - want: "linear-contains", - wantIn: aa("10.0.0.1", "10.2.3.4"), - wantOut: aa("8.8.8.8"), - }, - { - name: "cidr-list-2", - pfx: pp("1.0.0.0/8", "3.0.0.0/8"), - want: "linear-contains", - wantIn: aa("1.0.0.1", "3.0.0.1"), - wantOut: aa("2.0.0.1"), - }, - { - name: "cidr-list-3", - pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8"), - want: "linear-contains", - wantIn: aa("1.0.0.1", "5.0.0.1"), - wantOut: aa("2.0.0.1"), - }, - { - name: "cidr-list-4", - pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8"), - want: "linear-contains", - wantIn: aa("1.0.0.1", "7.0.0.1"), - wantOut: aa("2.0.0.1"), - }, - { - name: "cidr-list-5", - pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8", "9.0.0.0/8"), - want: "linear-contains", - wantIn: aa("1.0.0.1", "9.0.0.1"), - wantOut: aa("2.0.0.1"), - }, - { - name: "cidr-list-10", - pfx: pp("1.0.0.0/8", "3.0.0.0/8", "5.0.0.0/8", "7.0.0.0/8", "9.0.0.0/8", - "11.0.0.0/8", "13.0.0.0/8", "15.0.0.0/8", "17.0.0.0/8", "19.0.0.0/8"), - want: "bart", // big enough that bart is faster than linear-contains - wantIn: aa("1.0.0.1", "19.0.0.1"), - wantOut: aa("2.0.0.1"), - }, - { - name: "one-ip", - pfx: pp("10.1.0.0/32"), - want: "one-ip", - wantIn: aa("10.1.0.0"), - wantOut: aa("10.0.0.9"), - }, - { - name: "two-ip", - pfx: pp("10.1.0.0/32", "10.2.0.0/32"), - want: "two-ip", - wantIn: aa("10.1.0.0", "10.2.0.0"), - wantOut: aa("8.8.8.8"), - }, - { - name: "three-ip", - pfx: pp("10.1.0.0/32", "10.2.0.0/32", "10.3.0.0/32"), - want: "ip-map", - wantIn: aa("10.1.0.0", "10.2.0.0"), - wantOut: aa("8.8.8.8"), - }, -} - -func BenchmarkNewContainsIPFunc(b *testing.B) { - for _, tt := range newContainsIPFuncTests { - b.Run(tt.name, func(b *testing.B) { - f := NewContainsIPFunc(views.SliceOf(tt.pfx)) - for i := 0; i < b.N; i++ { - for _, ip := range tt.wantIn { - if !f(ip) { - b.Fatal("unexpected false") - } - } - for _, ip := range tt.wantOut { - if f(ip) { - b.Fatal("unexpected true") - } - } - } - }) - } -} - -func TestNewContainsIPFunc(t *testing.T) { - for _, tt := range newContainsIPFuncTests { - t.Run(tt.name, func(t *testing.T) { - var got string - tstest.Replace(t, &pathForTest, func(path string) { got = path }) - - f := NewContainsIPFunc(views.SliceOf(tt.pfx)) - if got != tt.want { - t.Errorf("func type = %q; want %q", got, tt.want) - } - for _, ip := range tt.wantIn { - if !f(ip) { - t.Errorf("match(%v) = false; want true", ip) - } - } - for _, ip := range tt.wantOut { - if f(ip) { - t.Errorf("match(%v) = true; want false", ip) - } - } - }) - } -} - var sinkIP netip.Addr func BenchmarkTailscaleServiceAddr(b *testing.B) { diff --git a/types/netmap/netmap.go b/types/netmap/netmap.go index 79459a6b5..5e0622922 100644 --- a/types/netmap/netmap.go +++ b/types/netmap/netmap.go @@ -18,7 +18,7 @@ "tailscale.com/types/key" "tailscale.com/types/views" "tailscale.com/util/set" - "tailscale.com/wgengine/filter" + "tailscale.com/wgengine/filter/filtertype" ) // NetworkMap is the current state of the world. @@ -40,7 +40,7 @@ type NetworkMap struct { Peers []tailcfg.NodeView // sorted by Node.ID DNS tailcfg.DNSConfig - PacketFilter []filter.Match + PacketFilter []filtertype.Match PacketFilterRules views.Slice[tailcfg.FilterRule] SSHPolicy *tailcfg.SSHPolicy // or nil, if not enabled/allowed diff --git a/wgengine/filter/filter.go b/wgengine/filter/filter.go index a545acb79..01182d4f8 100644 --- a/wgengine/filter/filter.go +++ b/wgengine/filter/filter.go @@ -14,9 +14,9 @@ "go4.org/netipx" "tailscale.com/envknob" "tailscale.com/net/flowtrack" + "tailscale.com/net/ipset" "tailscale.com/net/netaddr" "tailscale.com/net/packet" - "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/tstime/rate" "tailscale.com/types/ipproto" @@ -24,6 +24,7 @@ "tailscale.com/types/views" "tailscale.com/util/mak" "tailscale.com/util/slicesx" + "tailscale.com/wgengine/filter/filtertype" ) // Filter is a stateful packet filter. @@ -110,6 +111,13 @@ func (r Response) IsDrop() bool { HexdumpAccepts // print packet hexdump when logging accepts ) +type ( + Match = filtertype.Match + NetPortRange = filtertype.NetPortRange + PortRange = filtertype.PortRange + CapMatch = filtertype.CapMatch +) + // NewAllowAllForTest returns a packet filter that accepts // everything. Use in tests only, as it permits some kinds of spoofing // attacks to reach the OS network stack. @@ -192,23 +200,23 @@ func New(matches []Match, localNets, logIPs *netipx.IPSet, shareStateWith *Filte matches6: matchesFamily(matches, netip.Addr.Is6), cap4: capMatchesFunc(matches, netip.Addr.Is4), cap6: capMatchesFunc(matches, netip.Addr.Is6), - local4: tsaddr.FalseContainsIPFunc(), - local6: tsaddr.FalseContainsIPFunc(), - logIPs4: tsaddr.FalseContainsIPFunc(), - logIPs6: tsaddr.FalseContainsIPFunc(), + local4: ipset.FalseContainsIPFunc(), + local6: ipset.FalseContainsIPFunc(), + logIPs4: ipset.FalseContainsIPFunc(), + logIPs6: ipset.FalseContainsIPFunc(), state: state, } if localNets != nil { p := localNets.Prefixes() p4, p6 := slicesx.Partition(p, func(p netip.Prefix) bool { return p.Addr().Is4() }) - f.local4 = tsaddr.NewContainsIPFunc(views.SliceOf(p4)) - f.local6 = tsaddr.NewContainsIPFunc(views.SliceOf(p6)) + f.local4 = ipset.NewContainsIPFunc(views.SliceOf(p4)) + f.local6 = ipset.NewContainsIPFunc(views.SliceOf(p6)) } if logIPs != nil { p := logIPs.Prefixes() p4, p6 := slicesx.Partition(p, func(p netip.Prefix) bool { return p.Addr().Is4() }) - f.logIPs4 = tsaddr.NewContainsIPFunc(views.SliceOf(p4)) - f.logIPs6 = tsaddr.NewContainsIPFunc(views.SliceOf(p6)) + f.logIPs4 = ipset.NewContainsIPFunc(views.SliceOf(p4)) + f.logIPs6 = ipset.NewContainsIPFunc(views.SliceOf(p6)) } return f @@ -233,7 +241,7 @@ func matchesFamily(ms matches, keep func(netip.Addr) bool) matches { } } if len(retm.Srcs) > 0 && len(retm.Dsts) > 0 { - retm.SrcsContains = tsaddr.NewContainsIPFunc(views.SliceOf(retm.Srcs)) + retm.SrcsContains = ipset.NewContainsIPFunc(views.SliceOf(retm.Srcs)) ret = append(ret, retm) } } @@ -255,7 +263,7 @@ func capMatchesFunc(ms matches, keep func(netip.Addr) bool) matches { } } if len(retm.Srcs) > 0 { - retm.SrcsContains = tsaddr.NewContainsIPFunc(views.SliceOf(retm.Srcs)) + retm.SrcsContains = ipset.NewContainsIPFunc(views.SliceOf(retm.Srcs)) ret = append(ret, retm) } } diff --git a/wgengine/filter/filter_test.go b/wgengine/filter/filter_test.go index 23b0a936a..6a96d2366 100644 --- a/wgengine/filter/filter_test.go +++ b/wgengine/filter/filter_test.go @@ -19,6 +19,7 @@ "github.com/google/go-cmp/cmp/cmpopts" "go4.org/netipx" xmaps "golang.org/x/exp/maps" + "tailscale.com/net/ipset" "tailscale.com/net/packet" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" @@ -28,6 +29,7 @@ "tailscale.com/types/logger" "tailscale.com/types/views" "tailscale.com/util/must" + "tailscale.com/wgengine/filter/filtertype" ) // testAllowedProto is an IP protocol number we treat as allowed for @@ -44,7 +46,7 @@ func m(srcs []netip.Prefix, dsts []NetPortRange, protos ...ipproto.Proto) Match return Match{ IPProto: protos, Srcs: srcs, - SrcsContains: tsaddr.NewContainsIPFunc(views.SliceOf(srcs)), + SrcsContains: ipset.NewContainsIPFunc(views.SliceOf(srcs)), Dsts: dsts, } } @@ -440,7 +442,7 @@ func TestLoggingPrivacy(t *testing.T) { } f := newFilter(logf) - f.logIPs4 = tsaddr.NewContainsIPFunc(views.SliceOf([]netip.Prefix{ + f.logIPs4 = ipset.NewContainsIPFunc(views.SliceOf([]netip.Prefix{ tsaddr.CGNATRange(), tsaddr.TailscaleULARange(), })) @@ -702,7 +704,7 @@ func nets(nets ...string) (ret []netip.Prefix) { func ports(s string) PortRange { if s == "*" { - return allPorts + return filtertype.AllPorts } var fs, ls string diff --git a/wgengine/filter/filtertype/filtertype.go b/wgengine/filter/filtertype/filtertype.go new file mode 100644 index 000000000..1090ac718 --- /dev/null +++ b/wgengine/filter/filtertype/filtertype.go @@ -0,0 +1,98 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package filtertype defines the types used by wgengine/filter. +package filtertype + +import ( + "fmt" + "net/netip" + "strings" + + "tailscale.com/tailcfg" + "tailscale.com/types/ipproto" +) + +//go:generate go run tailscale.com/cmd/cloner --type=Match,CapMatch + +// PortRange is a range of TCP and UDP ports. +type PortRange struct { + First, Last uint16 // inclusive +} + +var AllPorts = PortRange{0, 0xffff} + +func (pr PortRange) String() string { + if pr.First == 0 && pr.Last == 65535 { + return "*" + } else if pr.First == pr.Last { + return fmt.Sprintf("%d", pr.First) + } else { + return fmt.Sprintf("%d-%d", pr.First, pr.Last) + } +} + +// contains returns whether port is in pr. +func (pr PortRange) Contains(port uint16) bool { + return port >= pr.First && port <= pr.Last +} + +// NetPortRange combines an IP address prefix and PortRange. +type NetPortRange struct { + Net netip.Prefix + Ports PortRange +} + +func (npr NetPortRange) String() string { + return fmt.Sprintf("%v:%v", npr.Net, npr.Ports) +} + +// CapMatch is a capability grant match predicate. +type CapMatch struct { + // Dst is the IP prefix that the destination IP address matches against + // to get the capability. + Dst netip.Prefix + + // Cap is the capability that's granted if the destination IP addresses + // matches Dst. + Cap tailcfg.PeerCapability + + // Values are the raw JSON values of the capability. + // See tailcfg.PeerCapability and tailcfg.PeerCapMap for details. + Values []tailcfg.RawMessage +} + +// Match matches packets from any IP address in Srcs to any ip:port in +// Dsts. +type Match struct { + IPProto []ipproto.Proto // required set (no default value at this layer) + Srcs []netip.Prefix + SrcsContains func(netip.Addr) bool `json:"-"` // report whether Addr is in Srcs + Dsts []NetPortRange // optional, if Srcs match + Caps []CapMatch // optional, if Srcs match +} + +func (m Match) String() string { + // TODO(bradfitz): use strings.Builder, add String tests + srcs := []string{} + for _, src := range m.Srcs { + srcs = append(srcs, src.String()) + } + dsts := []string{} + for _, dst := range m.Dsts { + dsts = append(dsts, dst.String()) + } + + var ss, ds string + if len(srcs) == 1 { + ss = srcs[0] + } else { + ss = "[" + strings.Join(srcs, ",") + "]" + } + if len(dsts) == 1 { + ds = dsts[0] + } else { + ds = "[" + strings.Join(dsts, ",") + "]" + } + return fmt.Sprintf("%v%v=>%v", m.IPProto, ss, ds) +} diff --git a/wgengine/filter/filter_clone.go b/wgengine/filter/filtertype/filtertype_clone.go similarity index 98% rename from wgengine/filter/filter_clone.go rename to wgengine/filter/filtertype/filtertype_clone.go index adeaf6efe..056e2ee09 100644 --- a/wgengine/filter/filter_clone.go +++ b/wgengine/filter/filtertype/filtertype_clone.go @@ -3,7 +3,7 @@ // Code generated by tailscale.com/cmd/cloner; DO NOT EDIT. -package filter +package filtertype import ( "net/netip" diff --git a/wgengine/filter/match.go b/wgengine/filter/match.go index 7bb063d7a..70c4a6d02 100644 --- a/wgengine/filter/match.go +++ b/wgengine/filter/match.go @@ -4,101 +4,13 @@ package filter import ( - "fmt" - "net/netip" "slices" - "strings" "tailscale.com/net/packet" - "tailscale.com/tailcfg" - "tailscale.com/types/ipproto" + "tailscale.com/wgengine/filter/filtertype" ) -//go:generate go run tailscale.com/cmd/cloner --type=Match,CapMatch - -// PortRange is a range of TCP and UDP ports. -type PortRange struct { - First, Last uint16 // inclusive -} - -var allPorts = PortRange{0, 0xffff} - -func (pr PortRange) String() string { - if pr.First == 0 && pr.Last == 65535 { - return "*" - } else if pr.First == pr.Last { - return fmt.Sprintf("%d", pr.First) - } else { - return fmt.Sprintf("%d-%d", pr.First, pr.Last) - } -} - -// contains returns whether port is in pr. -func (pr PortRange) contains(port uint16) bool { - return port >= pr.First && port <= pr.Last -} - -// NetPortRange combines an IP address prefix and PortRange. -type NetPortRange struct { - Net netip.Prefix - Ports PortRange -} - -func (npr NetPortRange) String() string { - return fmt.Sprintf("%v:%v", npr.Net, npr.Ports) -} - -// CapMatch is a capability grant match predicate. -type CapMatch struct { - // Dst is the IP prefix that the destination IP address matches against - // to get the capability. - Dst netip.Prefix - - // Cap is the capability that's granted if the destination IP addresses - // matches Dst. - Cap tailcfg.PeerCapability - - // Values are the raw JSON values of the capability. - // See tailcfg.PeerCapability and tailcfg.PeerCapMap for details. - Values []tailcfg.RawMessage -} - -// Match matches packets from any IP address in Srcs to any ip:port in -// Dsts. -type Match struct { - IPProto []ipproto.Proto // required set (no default value at this layer) - Srcs []netip.Prefix - SrcsContains func(netip.Addr) bool `json:"-"` // report whether Addr is in Srcs - Dsts []NetPortRange // optional, if Srcs match - Caps []CapMatch // optional, if Srcs match -} - -func (m Match) String() string { - // TODO(bradfitz): use strings.Builder, add String tests - srcs := []string{} - for _, src := range m.Srcs { - srcs = append(srcs, src.String()) - } - dsts := []string{} - for _, dst := range m.Dsts { - dsts = append(dsts, dst.String()) - } - - var ss, ds string - if len(srcs) == 1 { - ss = srcs[0] - } else { - ss = "[" + strings.Join(srcs, ",") + "]" - } - if len(dsts) == 1 { - ds = dsts[0] - } else { - ds = "[" + strings.Join(dsts, ",") + "]" - } - return fmt.Sprintf("%v%v=>%v", m.IPProto, ss, ds) -} - -type matches []Match +type matches []filtertype.Match func (ms matches) match(q *packet.Parsed) bool { for _, m := range ms { @@ -112,7 +24,7 @@ func (ms matches) match(q *packet.Parsed) bool { if !dst.Net.Contains(q.Dst.Addr()) { continue } - if !dst.Ports.contains(q.Dst.Port()) { + if !dst.Ports.Contains(q.Dst.Port()) { continue } return true @@ -147,7 +59,7 @@ func (ms matches) matchProtoAndIPsOnlyIfAllPorts(q *packet.Parsed) bool { continue } for _, dst := range m.Dsts { - if dst.Ports != allPorts { + if dst.Ports != filtertype.AllPorts { continue } if dst.Net.Contains(q.Dst.Addr()) { diff --git a/wgengine/filter/tailcfg.go b/wgengine/filter/tailcfg.go index 6bdb5b163..e52e7c6e1 100644 --- a/wgengine/filter/tailcfg.go +++ b/wgengine/filter/tailcfg.go @@ -9,8 +9,8 @@ "strings" "go4.org/netipx" + "tailscale.com/net/ipset" "tailscale.com/net/netaddr" - "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/ipproto" "tailscale.com/types/views" @@ -63,7 +63,7 @@ func MatchesFromFilterRules(pf []tailcfg.FilterRule) ([]Match, error) { } m.Srcs = append(m.Srcs, nets...) } - m.SrcsContains = tsaddr.NewContainsIPFunc(views.SliceOf(m.Srcs)) + m.SrcsContains = ipset.NewContainsIPFunc(views.SliceOf(m.Srcs)) for _, d := range r.DstPorts { nets, err := parseIPSet(d.IP, d.Bits) diff --git a/wgengine/netstack/netstack.go b/wgengine/netstack/netstack.go index fde9ab651..1bf0ee3de 100644 --- a/wgengine/netstack/netstack.go +++ b/wgengine/netstack/netstack.go @@ -39,6 +39,7 @@ "tailscale.com/ipn/ipnlocal" "tailscale.com/metrics" "tailscale.com/net/dns" + "tailscale.com/net/ipset" "tailscale.com/net/netaddr" "tailscale.com/net/packet" "tailscale.com/net/tsaddr" @@ -330,7 +331,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi driveForLocal: driveForLocal, } ns.ctx, ns.ctxCancel = context.WithCancel(context.Background()) - ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc()) + ns.atomicIsLocalIPFunc.Store(ipset.FalseContainsIPFunc()) ns.tundev.PostFilterPacketInboundFromWireGuard = ns.injectInbound ns.tundev.PreFilterPacketOutboundToWireGuardNetstackIntercept = ns.handleLocalPackets stacksForMetrics.Store(ns, struct{}{}) @@ -568,10 +569,10 @@ func ipPrefixToAddressWithPrefix(ipp netip.Prefix) tcpip.AddressWithPrefix { func (ns *Impl) UpdateNetstackIPs(nm *netmap.NetworkMap) { var selfNode tailcfg.NodeView if nm != nil { - ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.GetAddresses())) + ns.atomicIsLocalIPFunc.Store(ipset.NewContainsIPFunc(nm.GetAddresses())) selfNode = nm.SelfNode } else { - ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc()) + ns.atomicIsLocalIPFunc.Store(ipset.FalseContainsIPFunc()) } oldPfx := make(map[netip.Prefix]bool) diff --git a/wgengine/userspace.go b/wgengine/userspace.go index b65395fd8..6399476c8 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -27,6 +27,7 @@ "tailscale.com/ipn/ipnstate" "tailscale.com/net/dns" "tailscale.com/net/flowtrack" + "tailscale.com/net/ipset" "tailscale.com/net/netmon" "tailscale.com/net/packet" "tailscale.com/net/sockstats" @@ -330,8 +331,8 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) return nil, err } } - e.isLocalAddr.Store(tsaddr.FalseContainsIPFunc()) - e.isDNSIPOverTailscale.Store(tsaddr.FalseContainsIPFunc()) + e.isLocalAddr.Store(ipset.FalseContainsIPFunc()) + e.isDNSIPOverTailscale.Store(ipset.FalseContainsIPFunc()) if conf.NetMon != nil { e.netMon = conf.NetMon @@ -854,7 +855,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, panic("dnsCfg must not be nil") } - e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(views.SliceOf(routerCfg.LocalAddrs))) + e.isLocalAddr.Store(ipset.NewContainsIPFunc(views.SliceOf(routerCfg.LocalAddrs))) e.wgLock.Lock() defer e.wgLock.Unlock() @@ -912,7 +913,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, // instead have ipnlocal populate a map of DNS IP => linkName and // put that in the *dns.Config instead, and plumb it down to the // dns.Manager. Maybe also with isLocalAddr above. - e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(views.SliceOf(dnsIPsOverTailscale(dnsCfg, routerCfg)))) + e.isDNSIPOverTailscale.Store(ipset.NewContainsIPFunc(views.SliceOf(dnsIPsOverTailscale(dnsCfg, routerCfg)))) // See if any peers have changed disco keys, which means they've restarted. // If so, we need to update the wireguard-go/device.Device in two phases: