Files
cloudflared/ingress/origins/dns_test.go
Devin Carr 9ca8b41cf7 TUN-9472: Add virtual DNS service
Adds a new reserved service to route UDP requests towards the local DNS
resolver.

Closes TUN-9472
2025-06-27 13:09:29 -07:00

135 lines
3.6 KiB
Go

package origins
import (
"context"
"errors"
"net"
"net/netip"
"testing"
"github.com/rs/zerolog"
)
func TestDNSResolver_DefaultResolver(t *testing.T) {
log := zerolog.Nop()
service := NewDNSResolver(&log)
mockResolver := &mockPeekResolver{
address: "127.0.0.2:53",
}
service.resolver = mockResolver
if service.address != defaultResolverAddr {
t.Errorf("resolver address should be the default: %s, was: %s", defaultResolverAddr, service.address)
}
}
func TestDNSResolver_UpdateResolverAddress(t *testing.T) {
log := zerolog.Nop()
service := NewDNSResolver(&log)
mockResolver := &mockPeekResolver{}
service.resolver = mockResolver
expectedAddr := netip.MustParseAddrPort("127.0.0.2:53")
addresses := []string{
"127.0.0.2:53",
"127.0.0.2", // missing port should be added (even though this is unlikely to happen)
}
for _, addr := range addresses {
mockResolver.address = addr
// Update the resolver address
err := service.update(t.Context())
if err != nil {
t.Error(err)
}
// Validate expected
if service.address != expectedAddr {
t.Errorf("resolver address should be: %s, was: %s", expectedAddr, service.address)
}
}
}
func TestDNSResolver_UpdateResolverAddressInvalid(t *testing.T) {
log := zerolog.Nop()
service := NewDNSResolver(&log)
mockResolver := &mockPeekResolver{}
service.resolver = mockResolver
invalidAddresses := []string{
"999.999.999.999",
"localhost",
"255.255.255",
}
for _, addr := range invalidAddresses {
mockResolver.address = addr
// Update the resolver address should not update for these invalid addresses
err := service.update(t.Context())
if err == nil {
t.Error("service update should throw an error")
}
// Validate expected
if service.address != defaultResolverAddr {
t.Errorf("resolver address should not be updated from default: %s, was: %s", defaultResolverAddr, service.address)
}
}
}
func TestDNSResolver_UpdateResolverErrorIgnored(t *testing.T) {
log := zerolog.Nop()
service := NewDNSResolver(&log)
resolverErr := errors.New("test resolver error")
mockResolver := &mockPeekResolver{err: resolverErr}
service.resolver = mockResolver
// Update the resolver address should not update when the resolver cannot complete the lookup
err := service.update(t.Context())
if err != resolverErr {
t.Error("service update should throw an error")
}
// Validate expected
if service.address != defaultResolverAddr {
t.Errorf("resolver address should not be updated from default: %s, was: %s", defaultResolverAddr, service.address)
}
}
func TestDNSResolver_DialUsesResolvedAddress(t *testing.T) {
log := zerolog.Nop()
service := NewDNSResolver(&log)
mockResolver := &mockPeekResolver{}
service.resolver = mockResolver
mockDialer := &mockDialer{expected: defaultResolverAddr}
service.dialer = mockDialer
// Attempt a dial to 127.0.0.2:53 which should be ignored and instead resolve to 127.0.0.1:53
_, err := service.DialUDP(netip.MustParseAddrPort("127.0.0.2:53"))
if err != nil {
t.Error(err)
}
}
type mockPeekResolver struct {
err error
address string
}
func (r *mockPeekResolver) addr() (network, address string) {
return "udp", r.address
}
func (r *mockPeekResolver) lookupNetIP(ctx context.Context, host string) ([]netip.Addr, error) {
// We can return an empty result as it doesn't matter as long as the lookup doesn't fail
return []netip.Addr{}, r.err
}
type mockDialer struct {
expected netip.AddrPort
}
func (d *mockDialer) DialUDP(addr netip.AddrPort) (net.Conn, error) {
if d.expected != addr {
return nil, errors.New("unexpected address dialed")
}
return nil, nil
}