#include #include #include #include #include #include #include #include #include "ipfs/cid/cid.h" #include "ipfs/path/path.h" #include "ipfs/namesys/namesys.h" #include "ipfs/dnslink/dnslink.h" /*type LookupTXTFunc func(name string) (txt []string, err error) // DNSResolver implements a Resolver on DNS domains type DNSResolver struct { lookupTXT LookupTXTFunc // TODO: maybe some sort of caching? // cache would need a timeout } // NewDNSResolver constructs a name resolver using DNS TXT records. func NewDNSResolver() Resolver { return &DNSResolver{lookupTXT: net.LookupTXT} } // newDNSResolver constructs a name resolver using DNS TXT records, // returning a resolver instead of NewDNSResolver's Resolver. func newDNSResolver() resolver { return &DNSResolver{lookupTXT: net.LookupTXT} } // Resolve implements Resolver. func (r *DNSResolver) Resolve(ctx context.Context, name string) (path.Path, error) { return r.ResolveN(ctx, name, DefaultDepthLimit) } // ResolveN implements Resolver. func (r *DNSResolver) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) { return resolve(ctx, r, name, depth, "/ipns/") } type lookupRes struct { path path.Path error error }*/ // resolveOnce implements resolver. // TXT records for a given domain name should contain a b58 // encoded multihash. int ipfs_dns_resolver_resolve_once (char **path, char *name) { char **segments, *domain, *dnslink, buf[500], dlprefix[] = "_dnslink."; int p1[2], p2[2], r, l, c=2; struct pollfd event[2], *e; DNSResolver dnsr; segments = ipfs_path_split_n(name, "/", 2); domain = segments[0]; *path = NULL; if (!ipfs_isdomain_is_domain(domain)) { return ErrInvalidDomain; } //log.Infof("DNSResolver resolving %s", domain); if (pipe(p1) || pipe(p2)) { return ErrPipe; } dnsr.lookupTXT = ipfs_dnslink_resolv_lookupTXT; r = fork(); switch(r) { case -1: return ErrPipe; case 0: // child close(p1[STDIN_FILENO]); // we don't need to read at child process. return ipfs_dns_work_domain (p1[STDOUT_FILENO], &dnsr, domain); } close(p1[STDOUT_FILENO]); // we don't need to write at main process. r = fork(); switch(r) { case -1: return ErrPipe; case 0: // child close(p2[STDIN_FILENO]); // we don't need to read at child process. l = strlen(domain) + sizeof(dlprefix); dnslink = malloc(l); if (!dnslink) { return ErrAllocFailed; } dnslink[--l] = '\0'; strncpy (dnslink, dlprefix, l); strncat (dnslink, domain, l - strlen(dnslink)); return ipfs_dns_work_domain (p2[STDOUT_FILENO], &dnsr, dnslink); } close(p2[STDOUT_FILENO]); // we don't need to write at main process. memset(&event, 0, sizeof(struct pollfd)); event[0].fd = p1[STDIN_FILENO]; event[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; event[1].fd = p2[STDIN_FILENO]; event[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; e = event; do { r = poll(e, c, -1); if (r == -1) { return ErrPoll; } for (r = 0 ; r < c ; r++) { if (e[r].revents & POLLIN) { r = read(e[r].fd, buf, sizeof(buf)); if (r > 0) { buf[r] = '\0'; *path = malloc(r+1); if (*path) { *path[r] = '\0'; strncpy(*path, buf, r); } } else if (r <= 0) { return ErrPoll; } } } if (event[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { event[0].events = 0; e++; c--; wait(&r); } if (event[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { event[1].events = 0; c--; wait(&r); } } while (c); // wait for child process finish. if (!*path) { return ErrResolveFailed; } if (ipfs_path_segments_length (segments) > 1) { name = *path + strlen(*path) - 1; while (*name == '/') { *name-- = '\0'; } name = *path; *path = ipfs_path_from_segments (name, segments+1); free (name); if (!*path) { return ErrResolveFailed; } } ipfs_path_free_segments (&segments); return 0; } int ipfs_dns_work_domain (int output, DNSResolver *r, char *name) { char **txt, *path; int i, err = r->lookupTXT(&txt, name); if (err) { return err; } for (i = 0 ; txt[i] ; i++) { err = ipfs_dns_parse_entry (&path, txt[i]); if (!err) { err = (write (output, path, strlen(path)) != strlen(path)); free (path); if (err) { return ErrPipe; } return 0; } } return ErrResolveFailed; } int ipfs_dns_parse_entry (char **path, char *txt) { char buf[500]; int err; err = ipfs_path_parse_from_cid(buf, txt); // bare IPFS multihashes if (! err) { *path = malloc(strlen(buf) + 1); if (!*path) { return ErrAllocFailed; } memcpy(*path, buf, strlen(buf) + 1); return 0; } return ipfs_dns_try_parse_dns_link(path, txt); } int ipfs_dns_try_parse_dns_link(char **path, char *txt) { char **parts = ipfs_path_split_n(txt, "=", 2), buf[500]; int err; if (ipfs_path_segments_length(parts) == 2 && strcmp(parts[0], "dnslink")==0) { err = ipfs_path_parse(buf, parts[1]); if (err == 0) { *parts = malloc(strlen(buf) + 1); if (! *parts) { return ErrAllocFailed; } memcpy(*parts, buf, strlen(buf) + 1); return 0; } return err; } return ErrInvalidDNSLink; }