mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 08:09:58 +00:00

Adds an OriginDialerService that takes over the roles of both DialUDP and DialTCP towards the origin. This provides the possibility to leverage dialer "middleware" to inject virtual origins, such as the DNS resolver service. DNS Resolver service also gains access to the DialTCP operation to service TCP DNS requests. Minor refactoring includes changes to remove the needs previously provided by the warp-routing configuration. This configuration cannot be disabled by cloudflared so many of the references have been adjusted or removed. Closes TUN-9470
155 lines
4.3 KiB
Go
155 lines
4.3 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 := NewDNSResolverService(NewDNSDialer(), &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 := NewDNSResolverService(NewDNSDialer(), &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 := NewDNSResolverService(NewDNSDialer(), &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 := NewDNSResolverService(NewDNSDialer(), &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_DialUDPUsesResolvedAddress(t *testing.T) {
|
|
log := zerolog.Nop()
|
|
mockDialer := &mockDialer{expected: defaultResolverAddr}
|
|
service := NewDNSResolverService(mockDialer, &log)
|
|
mockResolver := &mockPeekResolver{}
|
|
service.resolver = mockResolver
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
func TestDNSResolver_DialTCPUsesResolvedAddress(t *testing.T) {
|
|
log := zerolog.Nop()
|
|
mockDialer := &mockDialer{expected: defaultResolverAddr}
|
|
service := NewDNSResolverService(mockDialer, &log)
|
|
mockResolver := &mockPeekResolver{}
|
|
service.resolver = mockResolver
|
|
|
|
// Attempt a dial to 127.0.0.2:53 which should be ignored and instead resolve to 127.0.0.1:53
|
|
_, err := service.DialTCP(t.Context(), 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) DialTCP(ctx context.Context, addr netip.AddrPort) (net.Conn, error) {
|
|
if d.expected != addr {
|
|
return nil, errors.New("unexpected address dialed")
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (d *mockDialer) DialUDP(addr netip.AddrPort) (net.Conn, error) {
|
|
if d.expected != addr {
|
|
return nil, errors.New("unexpected address dialed")
|
|
}
|
|
return nil, nil
|
|
}
|