net/dns: make MagicDNS IPv6 registration opt-out now, not opt-in

This adds a new ControlKnob to make MagicDNS IPv6 registration
(telling systemd/etc) opt-out rather than opt-in.

Updates #15404

Change-Id: If008e1cb046b792c6aff7bb1d7c58638f7d650b1
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-02-16 18:56:51 -10:00
committed by Brad Fitzpatrick
parent a6390ca008
commit a7a864419d
5 changed files with 91 additions and 34 deletions
+3 -5
View File
@@ -73,11 +73,9 @@ func (c *Config) serviceIPs(knobs *controlknobs.Knobs) []netip.Addr {
return []netip.Addr{tsaddr.TailscaleServiceIPv6()}
}
// TODO(bradfitz,mikeodr,raggi): include IPv6 here too; tailscale/tailscale#15404
// And add a controlknobs knob to disable dual stack.
//
// For now, opt-in for testing.
if magicDNSDualStack() {
// See https://github.com/tailscale/tailscale/issues/15404 for the background
// on the opt-in debug knob and the controlknob opt-out.
if magicDNSDualStack() || !knobs.ShouldForceRegisterMagicDNSIPv4Only() {
return []netip.Addr{
tsaddr.TailscaleServiceIP(),
tsaddr.TailscaleServiceIPv6(),
+3 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/google/go-cmp/cmp"
dns "golang.org/x/net/dns/dnsmessage"
"tailscale.com/control/controlknobs"
"tailscale.com/health"
"tailscale.com/net/netmon"
"tailscale.com/net/tsdial"
@@ -93,7 +94,8 @@ func TestDNSOverTCP(t *testing.T) {
bus := eventbustest.NewBus(t)
dialer := tsdial.NewDialer(netmon.NewStatic())
dialer.SetBus(bus)
m := NewManager(t.Logf, &f, health.NewTracker(bus), dialer, nil, nil, "", bus)
cknobs := &controlknobs.Knobs{}
m := NewManager(t.Logf, &f, health.NewTracker(bus), dialer, nil, cknobs, "", bus)
m.resolver.TestOnlySetHook(f.SetResolver)
m.Set(Config{
Hosts: hosts(
+61 -27
View File
@@ -28,6 +28,7 @@ import (
"tailscale.com/net/dns/publicdns"
"tailscale.com/net/dns/resolver"
"tailscale.com/net/netmon"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tsdial"
"tailscale.com/tstest"
"tailscale.com/types/dnstype"
@@ -172,6 +173,8 @@ func TestCompileHostEntries(t *testing.T) {
}
}
var serviceAddr46 = []netip.Addr{tsaddr.TailscaleServiceIP(), tsaddr.TailscaleServiceIPv6()}
func TestManager(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skipf("test's assumptions break because of https://github.com/tailscale/corp/issues/1662")
@@ -189,6 +192,7 @@ func TestManager(t *testing.T) {
split bool
bs OSConfig
os OSConfig
knobs *controlknobs.Knobs
rs resolver.Config
goos string // empty means "linux"
}{
@@ -231,7 +235,7 @@ func TestManager(t *testing.T) {
"bar.tld.", "2.3.4.5"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
},
rs: resolver.Config{
Hosts: hosts(
@@ -317,7 +321,7 @@ func TestManager(t *testing.T) {
"bradfitz.ts.com.", "2.3.4.5"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -340,7 +344,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -359,7 +363,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -377,7 +381,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -386,6 +390,33 @@ func TestManager(t *testing.T) {
"corp.com.", "2.2.2.2"),
},
},
{
name: "controlknob-disable-v6-registration",
in: Config{
DefaultResolvers: mustRes("1.1.1.1", "9.9.9.9"),
SearchDomains: fqdns("tailscale.com", "universe.tf"),
Routes: upstreams("ts.com", ""),
Hosts: hosts(
"dave.ts.com.", "1.2.3.4",
"bradfitz.ts.com.", "2.3.4.5"),
},
knobs: (func() *controlknobs.Knobs {
k := new(controlknobs.Knobs)
k.ForceRegisterMagicDNSIPv4Only.Store(true)
return k
})(),
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"), // without IPv6
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
Routes: upstreams(".", "1.1.1.1", "9.9.9.9"),
Hosts: hosts(
"dave.ts.com.", "1.2.3.4",
"bradfitz.ts.com.", "2.3.4.5"),
LocalDomains: fqdns("ts.com."),
},
},
{
name: "routes",
in: Config{
@@ -397,7 +428,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("coffee.shop"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf", "coffee.shop"),
},
rs: resolver.Config{
@@ -432,7 +463,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("coffee.shop"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf", "coffee.shop"),
},
rs: resolver.Config{
@@ -452,7 +483,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
MatchDomains: fqdns("bigco.net", "corp.com"),
},
@@ -477,7 +508,7 @@ func TestManager(t *testing.T) {
},
split: false,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -502,7 +533,7 @@ func TestManager(t *testing.T) {
},
split: false,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -527,7 +558,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("coffee.shop"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf", "coffee.shop"),
},
rs: resolver.Config{
@@ -549,7 +580,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
MatchDomains: fqdns("ts.com"),
},
@@ -575,7 +606,7 @@ func TestManager(t *testing.T) {
},
split: false,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -601,7 +632,7 @@ func TestManager(t *testing.T) {
},
split: false,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -627,7 +658,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("coffee.shop"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf", "coffee.shop"),
},
rs: resolver.Config{
@@ -653,7 +684,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
MatchDomains: fqdns("corp.com", "ts.com"),
},
@@ -683,7 +714,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -715,7 +746,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -740,7 +771,7 @@ func TestManager(t *testing.T) {
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("tailscale.com", "universe.tf"),
},
rs: resolver.Config{
@@ -768,7 +799,7 @@ func TestManager(t *testing.T) {
DefaultResolvers: mustRes("2a07:a8c0::c3:a884"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
},
rs: resolver.Config{
Routes: upstreams(".", "2a07:a8c0::c3:a884"),
@@ -780,7 +811,7 @@ func TestManager(t *testing.T) {
DefaultResolvers: mustRes("https://dns.nextdns.io/c3a884"),
},
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
},
rs: resolver.Config{
Routes: upstreams(".", "https://dns.nextdns.io/c3a884"),
@@ -796,7 +827,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("optimistic-display.ts.net"),
MatchDomains: fqdns("ts.net"),
},
@@ -821,7 +852,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("optimistic-display.ts.net"),
},
rs: resolver.Config{
@@ -844,7 +875,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("optimistic-display.ts.net"),
},
rs: resolver.Config{
@@ -885,7 +916,7 @@ func TestManager(t *testing.T) {
},
},
},
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("ts.com", "universe.tf"),
MatchDomains: fqdns("corp.com", "ts.com"),
},
@@ -912,7 +943,7 @@ func TestManager(t *testing.T) {
},
split: true,
os: OSConfig{
Nameservers: mustIPs("100.100.100.100"),
Nameservers: serviceAddr46,
SearchDomains: fqdns("ts.com", "universe.tf"),
MatchDomains: fqdns("corp.com", "ts.com"),
},
@@ -946,7 +977,10 @@ func TestManager(t *testing.T) {
if goos == "" {
goos = "linux"
}
knobs := &controlknobs.Knobs{}
knobs := test.knobs
if knobs == nil {
knobs = &controlknobs.Knobs{}
}
bus := eventbustest.NewBus(t)
dialer := tsdial.NewDialer(netmon.NewStatic())
dialer.SetBus(bus)