Skip to content
Draft
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
64 changes: 34 additions & 30 deletions gateway/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should flag that this is dead / removed now (it's not in the default autoconf resolver or in the fallbacks)

}

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)
Expand All @@ -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"
Expand All @@ -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
}

Expand All @@ -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...)
}
18 changes: 15 additions & 3 deletions gateway/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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() {
Expand All @@ -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)

Expand Down Expand Up @@ -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)
}
Loading