Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

make DNS resolver pluggable #10

Merged
merged 12 commits into from
Apr 23, 2021
Merged
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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

Package namesys defines `Resolver` and `Publisher` interfaces for IPNS paths, that is, paths in the form of `/ipns/<name_to_be_resolved>`. A "resolved" IPNS path becomes an `/ipfs/<cid>` path.

Traditionally, these paths would be in the form of `/ipns/peer_id`, which references an IPNS record in a distributed `ValueStore` (usually the IPFS DHT).
Traditionally, these paths would be in the form of `/ipns/{libp2p-key}`, which references an IPNS record in a distributed `ValueStore` (usually the IPFS DHT).

Additionally, the /ipns/ namespace can also be used with domain names that use DNSLink (/ipns/my.domain.example, see https://dnslink.io) and proquint strings.
Additionally, the `/ipns/` namespace can also be used with domain names that use DNSLink (`/ipns/en.wikipedia-on-ipfs.org`, see https://docs.ipfs.io/concepts/dnslink/).

The package provides implementations for all three resolvers.

Expand Down
29 changes: 10 additions & 19 deletions dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ import (

path "github.com/ipfs/go-path"
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
isd "github.com/jbenet/go-is-domain"
dns "github.com/miekg/dns"
)

const ethTLD = "eth"
const linkTLD = "domains"

// LookupTXTFunc is a generic type for a function that lookups TXT record values.
type LookupTXTFunc func(name string) (txt []string, err error)
// LookupTXTFunc is a function that lookups TXT record values.
type LookupTXTFunc func(ctx context.Context, name string) (txt []string, err error)

// DNSResolver implements a Resolver on DNS domains
type DNSResolver struct {
Expand All @@ -27,8 +24,8 @@ type DNSResolver struct {
}

// NewDNSResolver constructs a name resolver using DNS TXT records.
func NewDNSResolver() *DNSResolver {
return &DNSResolver{lookupTXT: net.LookupTXT}
func NewDNSResolver(lookup LookupTXTFunc) *DNSResolver {
return &DNSResolver{lookupTXT: lookup}
}

// Resolve implements Resolver.
Expand All @@ -55,7 +52,7 @@ func (r *DNSResolver) resolveOnceAsync(ctx context.Context, name string, options
segments := strings.SplitN(name, "/", 2)
domain := segments[0]

if !isd.IsDomain(domain) {
if _, ok := dns.IsDomainName(domain); !ok {
out <- onceResult{err: fmt.Errorf("not a valid domain name: %s", domain)}
close(out)
return out
Expand All @@ -68,17 +65,11 @@ func (r *DNSResolver) resolveOnceAsync(ctx context.Context, name string, options
fqdn = domain + "."
}

if strings.HasSuffix(fqdn, "."+ethTLD+".") {
// This is an ENS name. As we're resolving via an arbitrary DNS server
// that may not know about .eth we need to add our link domain suffix.
fqdn += linkTLD + "."
}

rootChan := make(chan lookupRes, 1)
go workDomain(r, fqdn, rootChan)
go workDomain(ctx, r, fqdn, rootChan)

subChan := make(chan lookupRes, 1)
go workDomain(r, "_dnslink."+fqdn, subChan)
go workDomain(ctx, r, "_dnslink."+fqdn, subChan)

appendPath := func(p path.Path) (path.Path, error) {
if len(segments) > 1 {
Expand Down Expand Up @@ -139,10 +130,10 @@ func (r *DNSResolver) resolveOnceAsync(ctx context.Context, name string, options
return out
}

func workDomain(r *DNSResolver, name string, res chan lookupRes) {
func workDomain(ctx context.Context, r *DNSResolver, name string, res chan lookupRes) {
defer close(res)

txt, err := r.lookupTXT(name)
txt, err := r.lookupTXT(ctx, name)
if err != nil {
if dnsErr, ok := err.(*net.DNSError); ok {
// If no TXT records found, return same error as when no text
Expand Down
19 changes: 16 additions & 3 deletions dns_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package namesys

import (
"context"
"fmt"
"testing"

Expand All @@ -11,7 +12,7 @@ type mockDNS struct {
entries map[string][]string
}

func (m *mockDNS) lookupTXT(name string) (txt []string, err error) {
func (m *mockDNS) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
txt, ok := m.entries[name]
if !ok {
return nil, fmt.Errorf("no TXT entry for %s", name)
Expand Down Expand Up @@ -126,7 +127,16 @@ func newMockDNS() *mockDNS {
"fqdn.example.com.": {
"dnslink=/ipfs/QmYvMB9yrsSf7RKBghkfwmHJkzJhW2ZgVwq3LxBXXPasFr",
},
"www.wealdtech.eth.domains.": {
"en.wikipedia-on-ipfs.org.": {
"dnslink=/ipfs/bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze",
},
"custom.non-icann.tldextravaganza.": {
"dnslink=/ipfs/bafybeieto6mcuvqlechv4iadoqvnffondeiwxc2bcfcewhvpsd2odvbmvm",
},
"singlednslabelshouldbeok.": {
"dnslink=/ipfs/bafybeih4a6ylafdki6ailjrdvmr7o4fbbeceeeuty4v3qyyouiz5koqlpi",
},
"www.wealdtech.eth.": {
"dnslink=/ipns/ipfs.example.com",
},
},
Expand Down Expand Up @@ -166,7 +176,10 @@ func TestDNSResolution(t *testing.T) {
testResolution(t, r, "double.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
testResolution(t, r, "conflict.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjE", nil)
testResolution(t, r, "fqdn.example.com.", opts.DefaultDepthLimit, "/ipfs/QmYvMB9yrsSf7RKBghkfwmHJkzJhW2ZgVwq3LxBXXPasFr", nil)
testResolution(t, r, "en.wikipedia-on-ipfs.org", 2, "/ipfs/bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze", nil)
testResolution(t, r, "custom.non-icann.tldextravaganza.", 2, "/ipfs/bafybeieto6mcuvqlechv4iadoqvnffondeiwxc2bcfcewhvpsd2odvbmvm", nil)
testResolution(t, r, "singlednslabelshouldbeok", 2, "/ipfs/bafybeih4a6ylafdki6ailjrdvmr7o4fbbeceeeuty4v3qyyouiz5koqlpi", nil)
testResolution(t, r, "www.wealdtech.eth", 1, "/ipns/ipfs.example.com", ErrResolveRecursion)
testResolution(t, r, "www.wealdtech.eth", 2, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
testResolution(t, r, "www.wealdtech.eth.domains", 2, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
testResolution(t, r, "www.wealdtech.eth", 2, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module github.com/ipfs/go-namesys

require (
github.com/bren2010/proquint v0.0.0-20160323162903-38337c27106d
github.com/gogo/protobuf v1.3.2
github.com/hashicorp/golang-lru v0.5.4
github.com/ipfs/go-cid v0.0.7
Expand All @@ -13,15 +12,16 @@ require (
github.com/ipfs/go-log v1.0.4
github.com/ipfs/go-path v0.0.9
github.com/ipfs/interface-go-ipfs-core v0.4.0
github.com/jbenet/go-is-domain v1.0.5
github.com/jbenet/goprocess v0.1.4
github.com/libp2p/go-libp2p v0.13.0
github.com/libp2p/go-libp2p-core v0.8.0
github.com/libp2p/go-libp2p-kad-dht v0.11.1
github.com/libp2p/go-libp2p-peerstore v0.2.6
github.com/libp2p/go-libp2p-record v0.1.3
github.com/libp2p/go-libp2p-testing v0.4.0
github.com/miekg/dns v1.1.41
github.com/multiformats/go-multiaddr v0.3.1
github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/multiformats/go-multihash v0.0.14
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc
)
Expand Down
Loading