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 }