mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-27 10:47:35 +00:00
appc: add test to ensure that individual IPs are not removed during route updates
If control advised the connector to advertise a route that had already been discovered by DNS it would be incorrectly removed. Now those routes are preserved. Updates tailscale/corp#16833 Signed-off-by: James Tucker <james@tailscale.com> (cherry picked from commit 0e2cb76abe1867736fe2aea89d3bc5bbdb5911dd)
This commit is contained in:
parent
8ffcd9a11b
commit
d1810a7e10
@ -155,7 +155,7 @@ nextRoute:
|
|||||||
for _, r := range routes {
|
for _, r := range routes {
|
||||||
for _, addr := range e.domains {
|
for _, addr := range e.domains {
|
||||||
for _, a := range addr {
|
for _, a := range addr {
|
||||||
if r.Contains(a) {
|
if r.Contains(a) && netip.PrefixFrom(a, a.BitLen()) != r {
|
||||||
pfx := netip.PrefixFrom(a, a.BitLen())
|
pfx := netip.PrefixFrom(a, a.BitLen())
|
||||||
toRemove = append(toRemove, pfx)
|
toRemove = append(toRemove, pfx)
|
||||||
continue nextRoute
|
continue nextRoute
|
||||||
|
@ -45,13 +45,39 @@ func TestUpdateDomains(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateRoutes(t *testing.T) {
|
func TestUpdateRoutes(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
rc := &appctest.RouteCollector{}
|
rc := &appctest.RouteCollector{}
|
||||||
a := NewAppConnector(t.Logf, rc)
|
a := NewAppConnector(t.Logf, rc)
|
||||||
routes := []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24")}
|
a.updateDomains([]string{"*.example.com"})
|
||||||
|
|
||||||
|
// This route should be collapsed into the range
|
||||||
|
a.ObserveDNSResponse(dnsResponse("a.example.com.", "192.0.2.1"))
|
||||||
|
a.Wait(ctx)
|
||||||
|
|
||||||
|
if !slices.Equal(rc.Routes(), []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")}) {
|
||||||
|
t.Fatalf("got %v, want %v", rc.Routes(), []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This route should not be collapsed or removed
|
||||||
|
a.ObserveDNSResponse(dnsResponse("b.example.com.", "192.0.0.1"))
|
||||||
|
a.Wait(ctx)
|
||||||
|
|
||||||
|
routes := []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24"), netip.MustParsePrefix("192.0.0.1/32")}
|
||||||
a.updateRoutes(routes)
|
a.updateRoutes(routes)
|
||||||
|
|
||||||
|
slices.SortFunc(rc.Routes(), prefixCompare)
|
||||||
|
rc.SetRoutes(slices.Compact(rc.Routes()))
|
||||||
|
slices.SortFunc(routes, prefixCompare)
|
||||||
|
|
||||||
|
// Ensure that the non-matching /32 is preserved, even though it's in the domains table.
|
||||||
if !slices.EqualFunc(routes, rc.Routes(), prefixEqual) {
|
if !slices.EqualFunc(routes, rc.Routes(), prefixEqual) {
|
||||||
t.Fatalf("got %v, want %v", rc.Routes(), routes)
|
t.Errorf("added routes: got %v, want %v", rc.Routes(), routes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the contained /32 is removed, replaced by the /24.
|
||||||
|
wantRemoved := []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")}
|
||||||
|
if !slices.EqualFunc(rc.RemovedRoutes(), wantRemoved, prefixEqual) {
|
||||||
|
t.Fatalf("unexpected removed routes: %v", rc.RemovedRoutes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,3 +221,10 @@ func dnsResponse(domain, address string) []byte {
|
|||||||
func prefixEqual(a, b netip.Prefix) bool {
|
func prefixEqual(a, b netip.Prefix) bool {
|
||||||
return a == b
|
return a == b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prefixCompare(a, b netip.Prefix) int {
|
||||||
|
if a.Addr().Compare(b.Addr()) == 0 {
|
||||||
|
return a.Bits() - b.Bits()
|
||||||
|
}
|
||||||
|
return a.Addr().Compare(b.Addr())
|
||||||
|
}
|
||||||
|
@ -10,7 +10,8 @@ import (
|
|||||||
|
|
||||||
// RouteCollector is a test helper that collects the list of routes advertised
|
// RouteCollector is a test helper that collects the list of routes advertised
|
||||||
type RouteCollector struct {
|
type RouteCollector struct {
|
||||||
routes []netip.Prefix
|
routes []netip.Prefix
|
||||||
|
removedRoutes []netip.Prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *RouteCollector) AdvertiseRoute(pfx ...netip.Prefix) error {
|
func (rc *RouteCollector) AdvertiseRoute(pfx ...netip.Prefix) error {
|
||||||
@ -24,11 +25,18 @@ func (rc *RouteCollector) UnadvertiseRoute(toRemove ...netip.Prefix) error {
|
|||||||
for _, r := range routes {
|
for _, r := range routes {
|
||||||
if !slices.Contains(toRemove, r) {
|
if !slices.Contains(toRemove, r) {
|
||||||
rc.routes = append(rc.routes, r)
|
rc.routes = append(rc.routes, r)
|
||||||
|
} else {
|
||||||
|
rc.removedRoutes = append(rc.removedRoutes, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemovedRoutes returns the list of routes that were removed.
|
||||||
|
func (rc *RouteCollector) RemovedRoutes() []netip.Prefix {
|
||||||
|
return rc.removedRoutes
|
||||||
|
}
|
||||||
|
|
||||||
// Routes returns the ordered list of routes that were added, including
|
// Routes returns the ordered list of routes that were added, including
|
||||||
// possible duplicates.
|
// possible duplicates.
|
||||||
func (rc *RouteCollector) Routes() []netip.Prefix {
|
func (rc *RouteCollector) Routes() []netip.Prefix {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user