appc,feature/conn25: use custom scheme resolvers for conn25
Currently we are picking a peer for the split dns routes when we get a netmap. Use the new custom scheme resolvers, installed per app in the config in the netmap, to allow us to choose which connector peer should handle a DNS request at the time the request is made. Fixes tailscale/corp#39858 Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
+45
-11
@@ -147,6 +147,36 @@ func (e *extension) installHooks(dph *datapathHandler) error {
|
||||
if !ok {
|
||||
return errors.New("could not access system tun")
|
||||
}
|
||||
resolver := dnsManager.Resolver()
|
||||
if resolver == nil {
|
||||
return errors.New("dns manager resolver not ready")
|
||||
}
|
||||
|
||||
if err := resolver.RegisterCustomScheme(appc.DNSAddrScheme, func(addr string) (string, error) {
|
||||
scheme, appName, ok := strings.Cut(addr, ":")
|
||||
if !ok || scheme != appc.DNSAddrScheme {
|
||||
return "", fmt.Errorf("unexpected conn25 scheme %q", scheme)
|
||||
}
|
||||
|
||||
if !e.conn25.isConfigured() {
|
||||
return "", errors.New("conn25 not configured")
|
||||
}
|
||||
cfg, ok := e.conn25.getConfig()
|
||||
if !ok {
|
||||
return "", errors.New("conn25 no config found")
|
||||
}
|
||||
app, ok := cfg.appsByName[appName]
|
||||
if !ok {
|
||||
return "", errors.New("no app found for app name")
|
||||
}
|
||||
_, urlBase := e.pickConnectorURLBase(app)
|
||||
if urlBase == "" {
|
||||
return "", nil
|
||||
}
|
||||
return urlBase + "/dns-query", nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("could not register DNS resolver scheme: %w", err)
|
||||
}
|
||||
|
||||
// Set up the DNS manager to rewrite responses for app domains
|
||||
// to answer with Magic IPs.
|
||||
@@ -925,17 +955,7 @@ func makePeerAPIReq(ctx context.Context, httpClient *http.Client, urlBase string
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extension) sendAddressAssignment(ctx context.Context, as addrs) (tailcfg.NodeView, error) {
|
||||
cfg, ok := e.conn25.getConfig()
|
||||
if !ok {
|
||||
return tailcfg.NodeView{}, errors.New("not configured")
|
||||
}
|
||||
app, ok := cfg.appsByName[as.app]
|
||||
if !ok {
|
||||
e.conn25.logf("App not found for app: %s (domain: %s)", as.app, as.domain)
|
||||
return tailcfg.NodeView{}, errors.New("app not found")
|
||||
}
|
||||
|
||||
func (e *extension) pickConnectorURLBase(app appctype.Conn25Attr) (tailcfg.NodeView, string) {
|
||||
nb := e.host.NodeBackend()
|
||||
peers := appc.PickConnector(nb, app)
|
||||
var urlBase string
|
||||
@@ -947,6 +967,20 @@ func (e *extension) sendAddressAssignment(ctx context.Context, as addrs) (tailcf
|
||||
break
|
||||
}
|
||||
}
|
||||
return conn, urlBase
|
||||
}
|
||||
|
||||
func (e *extension) sendAddressAssignment(ctx context.Context, as addrs) (tailcfg.NodeView, error) {
|
||||
cfg, ok := e.conn25.getConfig()
|
||||
if !ok {
|
||||
return tailcfg.NodeView{}, errors.New("not configured")
|
||||
}
|
||||
app, ok := cfg.appsByName[as.app]
|
||||
if !ok {
|
||||
e.conn25.client.logf("App not found for app: %s (domain: %s)", as.app, as.domain)
|
||||
return tailcfg.NodeView{}, errors.New("app not found")
|
||||
}
|
||||
conn, urlBase := e.pickConnectorURLBase(app)
|
||||
if urlBase == "" {
|
||||
return tailcfg.NodeView{}, errors.New("no connector peer found to handle address assignment")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnext"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/packet"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/net/tstun"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/util/dnsname"
|
||||
"tailscale.com/util/eventbus/eventbustest"
|
||||
"tailscale.com/util/must"
|
||||
"tailscale.com/util/set"
|
||||
)
|
||||
@@ -1393,14 +1395,14 @@ type testSafeBackend struct {
|
||||
sys *tsd.System
|
||||
}
|
||||
|
||||
func newTestSafeBackend() *testSafeBackend {
|
||||
sb := &testSafeBackend{}
|
||||
sys := &tsd.System{}
|
||||
sys.Dialer.Set(&tsdial.Dialer{Logf: logger.Discard})
|
||||
sys.DNSManager.Set(&dns.Manager{})
|
||||
func newTestSafeBackend(t *testing.T) *testSafeBackend {
|
||||
sys := tsd.NewSystemWithBus(eventbustest.NewBus(t))
|
||||
dialer := tsdial.NewDialer(netmon.NewStatic())
|
||||
sys.Dialer.Set(dialer)
|
||||
ht := sys.HealthTracker.Get()
|
||||
sys.DNSManager.Set(dns.NewManager(logger.Discard, nil, ht, dialer, nil, nil, "", sys.Bus.Get()))
|
||||
sys.Tun.Set(&tstun.Wrapper{})
|
||||
sb.sys = sys
|
||||
return sb
|
||||
return &testSafeBackend{sys: sys}
|
||||
}
|
||||
|
||||
func (b *testSafeBackend) Sys() *tsd.System { return b.sys }
|
||||
@@ -1439,7 +1441,7 @@ func TestAddressAssignmentIsHandled(t *testing.T) {
|
||||
|
||||
ext := &extension{
|
||||
conn25: newConn25(logger.Discard),
|
||||
backend: newTestSafeBackend(),
|
||||
backend: newTestSafeBackend(t),
|
||||
}
|
||||
authReconfigAsyncCalled := make(chan struct{}, 1)
|
||||
if err := ext.Init(&testHost{
|
||||
@@ -2034,7 +2036,7 @@ func TestHandleAddressAssignmentStoresTransitIPs(t *testing.T) {
|
||||
|
||||
ext := &extension{
|
||||
conn25: newConn25(logger.Discard),
|
||||
backend: newTestSafeBackend(),
|
||||
backend: newTestSafeBackend(t),
|
||||
}
|
||||
authReconfigAsyncCalled := make(chan struct{}, 1)
|
||||
if err := ext.Init(&testHost{
|
||||
|
||||
Reference in New Issue
Block a user