diff --git a/CHANGELOG.md b/CHANGELOG.md index 288c95056..aadf7a2bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,10 @@ The following emojis are used to highlight certain changes: - The default `MaximumAllowedCid` limit for incoming CIDs can be adjusted using `bitswap.MaxCidSize` or `server.MaxCidSize` options - 🛠 `bitswap/client`: The `RebroadcastDelay` option now takes a `time.Duration` value. This is a potentially BREAKING CHANGE. The time-varying functionality of `delay.Delay` was never used, so it was replaced with a fixed duration value. This also removes the `github.com/ipfs/go-ipfs-delay` dependency. - `filestore`: Support providing filestore-blocks. A new `provider.MultihashProvider` parameter has been added to `filestore.New()`. When used, the blocks handled by the Filestore's `FileManager` will be provided on write (Put and PutMany). +- `gateway`: DNS resolver defaults moved to `autoconf.FallbackDNSResolvers` + - `NewDNSResolver(nil)` uses `autoconf.FallbackDNSResolvers`, preserving existing behavior for users who did not pass custom config + - Pass empty map `NewDNSResolver(map[string]string{})` to use only system DNS + - For custom or dynamic DNS resolvers, use `autoconf.ExpandDNSResolvers()` to merge network defaults with your own resolvers ### Removed diff --git a/gateway/dns.go b/gateway/dns.go index c161ed8d5..fe89a10e3 100644 --- a/gateway/dns.go +++ b/gateway/dns.go @@ -4,16 +4,12 @@ import ( "fmt" "strings" + "github.com/ipfs/boxo/autoconf" "github.com/libp2p/go-doh-resolver" dns "github.com/miekg/dns" madns "github.com/multiformats/go-multiaddr-dns" ) -var defaultResolvers = map[string]string{ - "eth.": "https://dns.eth.limo/dns-query", - "crypto.": "https://resolver.unstoppable.io/dns-query", -} - func newResolver(url string, opts ...doh.Option) (madns.BasicResolver, error) { if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") { return nil, fmt.Errorf("invalid DoH resolver URL: %s", url) @@ -22,13 +18,18 @@ func newResolver(url string, opts ...doh.Option) (madns.BasicResolver, error) { return doh.NewResolver(url, opts...) } -// NewDNSResolver creates a new DNS resolver based on the default resolvers and -// the provided resolvers. +// NewDNSResolver creates a new DNS resolver based on the provided resolvers. // // The argument 'resolvers' is a map of [FQDNs] to URLs for custom DNS resolution. // URLs starting with "https://" indicate [DoH] endpoints. Support for other resolver // types may be added in the future. // +// If 'resolvers' is nil, it defaults to {".": "auto"} and uses [autoconf.FallbackDNSResolvers] +// for common non-ICANN TLDs. Pass an empty map {} to explicitly use only the system DNS resolver. +// +// For dynamic network-based DNS resolver configuration, use [autoconf.ExpandDNSResolvers] +// to merge autoconf-provided resolvers with custom resolvers before calling this function. +// // Example: // - Custom resolver for ENS: "eth." → "https://eth.link/dns-query" // - Override the default OS resolver: "." → "https://doh.applied-privacy.net/query" @@ -38,18 +39,40 @@ func newResolver(url string, opts ...doh.Option) (madns.BasicResolver, error) { func NewDNSResolver(resolvers map[string]string, dohOpts ...doh.Option) (*madns.Resolver, error) { var opts []madns.Option var err error - - domains := make(map[string]struct{}) // to track overridden default resolvers rslvrs := make(map[string]madns.BasicResolver) // to reuse resolvers for the same URL + // Use autoconf fallback defaults when nil (not when empty map) + // These are created without dohOpts (standard configuration) + if resolvers == nil { + for domain, urls := range autoconf.FallbackDNSResolvers { + if len(urls) == 0 { + continue + } + url := urls[0] + + rslv, ok := rslvrs[url] + if !ok { + rslv, err = newResolver(url) + if err != nil { + return nil, fmt.Errorf("bad resolver for %s: %w", domain, err) + } + rslvrs[url] = rslv + } + + opts = append(opts, madns.WithDomainResolver(domain, rslv)) + } + + return madns.NewResolver(opts...) + } + + // Handle user-provided resolvers with custom dohOpts for domain, url := range resolvers { if domain != "." && !dns.IsFqdn(domain) { return nil, fmt.Errorf("invalid domain %s; must be FQDN", domain) } - domains[domain] = struct{}{} if url == "" { - // allow overriding of implicit defaults with the default resolver + // allow clearing resolver for a domain continue } @@ -69,24 +92,5 @@ func NewDNSResolver(resolvers map[string]string, dohOpts ...doh.Option) (*madns. } } - // fill in defaults if not overridden by the user - for domain, url := range defaultResolvers { - _, ok := domains[domain] - if ok { - continue - } - - rslv, ok := rslvrs[url] - if !ok { - rslv, err = newResolver(url) - if err != nil { - return nil, fmt.Errorf("bad resolver for %s: %w", domain, err) - } - rslvrs[url] = rslv - } - - opts = append(opts, madns.WithDomainResolver(domain, rslv)) - } - return madns.NewResolver(opts...) } diff --git a/gateway/dns_test.go b/gateway/dns_test.go index 424a12c2a..d0d9e45f9 100644 --- a/gateway/dns_test.go +++ b/gateway/dns_test.go @@ -41,7 +41,7 @@ func TestAddNewDNSResolver(t *testing.T) { require.Equal(t, dnslinkValue, res[0]) } -func TestOverrideDNSDefaults(t *testing.T) { +func TestCustomDNSResolver(t *testing.T) { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -50,7 +50,7 @@ func TestOverrideDNSDefaults(t *testing.T) { require.NoError(t, err) defer l.Close() - dnslinkName := "dnslink-test.eth" + dnslinkName := "dnslink-test.foo" dnslinkValue := "dnslink=/ipfs/bafkqaaa" go func() { @@ -59,7 +59,7 @@ func TestOverrideDNSDefaults(t *testing.T) { listenAddr := l.Addr().(*net.TCPAddr) r, err := NewDNSResolver(map[string]string{ - "eth.": fmt.Sprintf("http://%s:%d", listenAddr.IP, listenAddr.Port), + "foo.": fmt.Sprintf("http://%s:%d", listenAddr.IP, listenAddr.Port), }) require.NoError(t, err) @@ -117,3 +117,15 @@ func dnslinkServerHandlerFunc(t *testing.T, dnslinkName string, txtResponse stri } } } + +func TestDNSResolverNilUsesAutoconfFallback(t *testing.T) { + r, err := NewDNSResolver(nil) + require.NoError(t, err) + require.NotNil(t, r) +} + +func TestDNSResolverEmptyMapUsesSystemDNS(t *testing.T) { + r, err := NewDNSResolver(map[string]string{}) + require.NoError(t, err) + require.NotNil(t, r) +}