Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support conditional start of IPv6 dns servers #9596

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/resource/definitions/network/network.proto
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ message HostDNSConfigSpec {
repeated common.NetIPPort listen_addresses = 2;
common.NetIP service_host_dns_address = 3;
bool resolve_member_names = 4;
common.NetIP service_host_dns_address_v6 = 5;
}

// HostnameSpecSpec describes node hostname.
Expand Down
42 changes: 42 additions & 0 deletions internal/app/machined/pkg/controllers/network/address_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"golang.org/x/sys/unix"

netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
"github.com/siderolabs/talos/pkg/machinery/resources/network"
)
Expand Down Expand Up @@ -170,6 +171,47 @@ func (suite *AddressSpecSuite) TestLoopback() {
suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata()))
}

func (suite *AddressSpecSuite) TestIPV6ULA() {
loopback := network.NewAddressSpec(network.NamespaceName, "lo/"+constants.HostDNSAddressV6+"/128")
*loopback.TypedSpec() = network.AddressSpecSpec{
Address: netip.MustParsePrefix(constants.HostDNSAddressV6 + "/128"),
LinkName: "lo",
Family: nethelpers.FamilyInet6,
Scope: nethelpers.ScopeGlobal,
ConfigLayer: network.ConfigDefault,
Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent),
}

for _, res := range []resource.Resource{loopback} {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
}

suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertLinkAddress("lo", constants.HostDNSAddressV6+"/128")
},
),
)

// teardown the address
for {
ready, err := suite.state.Teardown(suite.ctx, loopback.Metadata())
suite.Require().NoError(err)

if ready {
break
}

time.Sleep(100 * time.Millisecond)
}

// torn down address should be removed immediately
suite.Assert().NoError(suite.assertNoLinkAddress("lo", constants.HostDNSAddressV6+"/128"))

suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata()))
}

func (suite *AddressSpecSuite) TestDummy() {
dummyInterface := suite.uniqueDummyInterface()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (ctrl *DNSResolveCacheController) run(ctx context.Context, r controller.Run
}

pairs := allAddressPairs(cfg.TypedSpec().ListenAddresses)
forwardKubeDNSToHost := cfg.TypedSpec().ServiceHostDNSAddress.IsValid()
forwardKubeDNSToHost := cfg.TypedSpec().ServiceHostDNSAddress.IsValid() || cfg.TypedSpec().ServiceHostDNSAddressV6.IsValid()

for runCfg, runErr := range ctrl.manager.RunAll(pairs, forwardKubeDNSToHost) {
switch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ func getDynamicPort() (string, error) {
func makeAddrs(port string) []netip.AddrPort {
return []netip.AddrPort{
netip.MustParseAddrPort("127.0.0.53:" + port),
netip.MustParseAddrPort("[::1]:" + port),
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/app/machined/pkg/controllers/network/etcfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, _

if resolverStatus != nil && hostDNSCfg != nil {
dnsServers := xslices.FilterInPlace(
[]netip.Addr{hostDNSCfg.TypedSpec().ServiceHostDNSAddress},
[]netip.Addr{hostDNSCfg.TypedSpec().ServiceHostDNSAddress, hostDNSCfg.TypedSpec().ServiceHostDNSAddressV6},
netip.Addr.IsValid,
)

Expand Down
12 changes: 7 additions & 5 deletions internal/app/machined/pkg/controllers/network/etcfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ func (suite *EtcFileConfigSuite) SetupTest() {
suite.hostDNSConfig.TypedSpec().ListenAddresses = []netip.AddrPort{
netip.MustParseAddrPort("127.0.0.53:53"),
netip.MustParseAddrPort("169.254.116.108:53"),
netip.MustParseAddrPort("[fd54:616c:6f73::204f:5320:444e:531]:53"),
}
suite.hostDNSConfig.TypedSpec().ServiceHostDNSAddress = netip.MustParseAddr("169.254.116.108")
suite.hostDNSConfig.TypedSpec().ServiceHostDNSAddressV6 = netip.MustParseAddr("fd54:616c:6f73::204f:5320:444e:531")
}

func (suite *EtcFileConfigSuite) startRuntime() {
Expand Down Expand Up @@ -228,7 +230,7 @@ func (suite *EtcFileConfigSuite) TestComplete() {
etcFileContents{
hosts: "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n10.0.0.1 a b\n10.0.0.2 c d\n", //nolint:lll
resolvConf: "nameserver 127.0.0.53\n\nsearch example.com\n",
resolvGlobalConf: "nameserver 169.254.116.108\n\nsearch example.com\n",
resolvGlobalConf: "nameserver 169.254.116.108\nnameserver fd54:616c:6f73:0:204f:5320:444e:531\n\nsearch example.com\n",
},
)
}
Expand All @@ -239,7 +241,7 @@ func (suite *EtcFileConfigSuite) TestNoExtraHosts() {
etcFileContents{
hosts: "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n",
resolvConf: "nameserver 127.0.0.53\n\nsearch example.com\n",
resolvGlobalConf: "nameserver 169.254.116.108\n\nsearch example.com\n",
resolvGlobalConf: "nameserver 169.254.116.108\nnameserver fd54:616c:6f73:0:204f:5320:444e:531\n\nsearch example.com\n",
},
)
}
Expand All @@ -262,7 +264,7 @@ func (suite *EtcFileConfigSuite) TestNoSearchDomain() {
etcFileContents{
hosts: "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n",
resolvConf: "nameserver 127.0.0.53\n",
resolvGlobalConf: "nameserver 169.254.116.108\n",
resolvGlobalConf: "nameserver 169.254.116.108\nnameserver fd54:616c:6f73:0:204f:5320:444e:531\n",
},
)
}
Expand All @@ -275,7 +277,7 @@ func (suite *EtcFileConfigSuite) TestNoDomainname() {
etcFileContents{
hosts: "127.0.0.1 localhost\n33.11.22.44 foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n",
resolvConf: "nameserver 127.0.0.53\n",
resolvGlobalConf: "nameserver 169.254.116.108\n",
resolvGlobalConf: "nameserver 169.254.116.108\nnameserver fd54:616c:6f73:0:204f:5320:444e:531\n",
},
)
}
Expand All @@ -286,7 +288,7 @@ func (suite *EtcFileConfigSuite) TestOnlyResolvers() {
etcFileContents{
hosts: "",
resolvConf: "nameserver 127.0.0.53\n",
resolvGlobalConf: "nameserver 169.254.116.108\n",
resolvGlobalConf: "nameserver 169.254.116.108\nnameserver fd54:616c:6f73:0:204f:5320:444e:531\n",
},
)
}
Expand Down
12 changes: 12 additions & 0 deletions internal/app/machined/pkg/controllers/network/hostdns_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func (ctrl *HostDNSConfigController) Run(ctx context.Context, r controller.Runti
}

res.TypedSpec().ServiceHostDNSAddress = netip.Addr{}
res.TypedSpec().ServiceHostDNSAddressV6 = netip.Addr{}

if cfgProvider == nil {
res.TypedSpec().Enabled = false
Expand All @@ -117,6 +118,17 @@ func (ctrl *HostDNSConfigController) Run(ctx context.Context, r controller.Runti
res.TypedSpec().ServiceHostDNSAddress = parsed
}

if slices.ContainsFunc(
cfgProvider.Cluster().Network().PodCIDRs(),
func(cidr string) bool { return netip.MustParsePrefix(cidr).Addr().Is6() },
) {
parsed := netip.MustParseAddr(constants.HostDNSAddressV6)
newServiceAddrs = append(newServiceAddrs, parsed)

res.TypedSpec().ListenAddresses = append(res.TypedSpec().ListenAddresses, netip.AddrPortFrom(parsed, 53))
res.TypedSpec().ServiceHostDNSAddressV6 = parsed
}

return nil
}); err != nil {
return fmt.Errorf("error writing host dns config: %w", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/siderolabs/go-pointer"
"go.uber.org/zap"

cfg "github.com/siderolabs/talos/pkg/machinery/config/config"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
Expand Down Expand Up @@ -154,8 +155,6 @@ func (ctrl *NfTablesChainConfigController) Run(ctx context.Context, r controller

if cfg.Config().Machine() != nil && cfg.Config().Cluster() != nil {
if cfg.Config().Machine().Features().HostDNS().ForwardKubeDNSToHost() {
hostDNSIP := netip.MustParseAddr(constants.HostDNSAddress)

// allow traffic to host DNS
for _, protocol := range []nethelpers.Protocol{nethelpers.ProtocolUDP, nethelpers.ProtocolTCP} {
spec.Rules = append(spec.Rules,
Expand All @@ -170,7 +169,7 @@ func (ctrl *NfTablesChainConfigController) Run(ctx context.Context, r controller
),
},
MatchDestinationAddress: &network.NfTablesAddressMatch{
IncludeSubnets: []netip.Prefix{netip.PrefixFrom(hostDNSIP, hostDNSIP.BitLen())},
IncludeSubnets: hostDNSSubnets(cfg.Config().Cluster().Network()),
},
MatchLayer4: &network.NfTablesLayer4Match{
Protocol: protocol,
Expand Down Expand Up @@ -256,3 +255,20 @@ func (ctrl *NfTablesChainConfigController) Run(ctx context.Context, r controller
}
}
}

func hostDNSSubnets(clusterNetwork cfg.ClusterNetwork) []netip.Prefix {
result := []netip.Addr{hostDNSIPv4}

for _, podCIDR := range clusterNetwork.PodCIDRs() {
if netip.MustParsePrefix(podCIDR).Addr().Is6() {
result = append(result, hostDNSIPv6)
}
}

return xslices.Map(result, func(a netip.Addr) netip.Prefix { return netip.PrefixFrom(a, a.BitLen()) })
}

var (
hostDNSIPv4 = netip.MustParseAddr(constants.HostDNSAddress)
hostDNSIPv6 = netip.MustParseAddr(constants.HostDNSAddressV6)
)
14 changes: 13 additions & 1 deletion internal/pkg/dns/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func TestDNS(t *testing.T) {
},
}

for _, dnsAddr := range []string{"127.0.0.1:10700"} {
for _, dnsAddr := range []string{"127.0.0.1:10700", "[::1]:10700"} {
for _, test := range tests {
t.Run(dnsAddr+"/"+test.name, func(t *testing.T) {
stop := newManager(t, test.nameservers...)
Expand Down Expand Up @@ -115,6 +115,14 @@ func TestDNSEmptyDestinations(t *testing.T) {
require.NoError(t, err)
require.Equal(t, dnssrv.RcodeServerFailure, r.Rcode, r)

r, err = dnssrv.Exchange(createQuery("google.com"), "[::1]:10700")
require.NoError(t, err)
require.Equal(t, dnssrv.RcodeServerFailure, r.Rcode, r)

r, err = dnssrv.Exchange(createQuery("google.com"), "[::1]:10700")
require.NoError(t, err)
require.Equal(t, dnssrv.RcodeServerFailure, r.Rcode, r)

stop()
}

Expand All @@ -135,6 +143,8 @@ func TestGC_NOGC(t *testing.T) {
for _, err := range m.RunAll(slices.Values([]dns.AddressPair{
{Network: "udp", Addr: netip.MustParseAddrPort("127.0.0.1:10700")},
{Network: "udp", Addr: netip.MustParseAddrPort("127.0.0.1:10701")},
{Network: "udp", Addr: netip.MustParseAddrPort("[::1]:10700")},
{Network: "udp", Addr: netip.MustParseAddrPort("[::1]:10701")},
}), false) {
require.NoError(t, err)
}
Expand Down Expand Up @@ -195,6 +205,8 @@ func newManager(t *testing.T, nameservers ...string) func() {
for _, err := range m.RunAll(slices.Values([]dns.AddressPair{
{Network: "udp", Addr: netip.MustParseAddrPort("127.0.0.1:10700")},
{Network: "tcp", Addr: netip.MustParseAddrPort("127.0.0.1:10700")},
{Network: "udp", Addr: netip.MustParseAddrPort("[::1]:10700")},
{Network: "tcp", Addr: netip.MustParseAddrPort("[::1]:10700")},
}), false) {
if err != nil && strings.Contains(err.Error(), "failed to set TCP_FASTOPEN") {
continue
Expand Down
Loading
Loading