github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/namesys/dns.go (about)

     1  package namesys
     2  
     3  import (
     4  	"errors"
     5  	"net"
     6  	"strings"
     7  
     8  	isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain"
     9  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    10  
    11  	path "github.com/ipfs/go-ipfs/path"
    12  )
    13  
    14  type LookupTXTFunc func(name string) (txt []string, err error)
    15  
    16  // DNSResolver implements a Resolver on DNS domains
    17  type DNSResolver struct {
    18  	lookupTXT LookupTXTFunc
    19  	// TODO: maybe some sort of caching?
    20  	// cache would need a timeout
    21  }
    22  
    23  // NewDNSResolver constructs a name resolver using DNS TXT records.
    24  func NewDNSResolver() Resolver {
    25  	return &DNSResolver{lookupTXT: net.LookupTXT}
    26  }
    27  
    28  // newDNSResolver constructs a name resolver using DNS TXT records,
    29  // returning a resolver instead of NewDNSResolver's Resolver.
    30  func newDNSResolver() resolver {
    31  	return &DNSResolver{lookupTXT: net.LookupTXT}
    32  }
    33  
    34  // Resolve implements Resolver.
    35  func (r *DNSResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
    36  	return r.ResolveN(ctx, name, DefaultDepthLimit)
    37  }
    38  
    39  // ResolveN implements Resolver.
    40  func (r *DNSResolver) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
    41  	return resolve(ctx, r, name, depth, "/ipns/")
    42  }
    43  
    44  // resolveOnce implements resolver.
    45  // TXT records for a given domain name should contain a b58
    46  // encoded multihash.
    47  func (r *DNSResolver) resolveOnce(ctx context.Context, name string) (path.Path, error) {
    48  	if !isd.IsDomain(name) {
    49  		return "", errors.New("not a valid domain name")
    50  	}
    51  
    52  	log.Infof("DNSResolver resolving %s", name)
    53  	txt, err := r.lookupTXT(name)
    54  	if err != nil {
    55  		return "", err
    56  	}
    57  
    58  	for _, t := range txt {
    59  		p, err := parseEntry(t)
    60  		if err == nil {
    61  			return p, nil
    62  		}
    63  	}
    64  
    65  	return "", ErrResolveFailed
    66  }
    67  
    68  func parseEntry(txt string) (path.Path, error) {
    69  	p, err := path.ParseKeyToPath(txt) // bare IPFS multihashes
    70  	if err == nil {
    71  		return p, nil
    72  	}
    73  
    74  	return tryParseDnsLink(txt)
    75  }
    76  
    77  func tryParseDnsLink(txt string) (path.Path, error) {
    78  	parts := strings.SplitN(txt, "=", 2)
    79  	if len(parts) == 2 && parts[0] == "dnslink" {
    80  		return path.ParsePath(parts[1])
    81  	}
    82  
    83  	return "", errors.New("not a valid dnslink entry")
    84  }