From a21330af436c0b9c6e8628f6f15acf1f0e2d37c0 Mon Sep 17 00:00:00 2001 From: Jose Marcial Vieira Bisneto Date: Sun, 27 Nov 2016 10:57:28 -0300 Subject: [PATCH] Initial implementation of namesys/dns.c --- include/ipfs/namesys/namesys.h | 17 ++- namesys/dns.c | 213 +++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 namesys/dns.c diff --git a/include/ipfs/namesys/namesys.h b/include/ipfs/namesys/namesys.h index b98ef88..6fedbd0 100644 --- a/include/ipfs/namesys/namesys.h +++ b/include/ipfs/namesys/namesys.h @@ -8,12 +8,16 @@ NULL, "ErrAllocFailed", "ErrNULLPointer", + "ErrPipe", + "ErrPoll", "Could not publish name." "Could not resolve name.", "Could not resolve name (recursion limit exceeded).", "expired record", "unrecognized validity type", - "not a valid proquint string" + "not a valid proquint string", + "not a valid domain name", + "not a valid dnslink entry" }; #else extern char *ErrNamesys; @@ -22,12 +26,16 @@ enum { ErrAllocFailed = 1, ErrNULLPointer, + ErrPipe, + ErrPoll, ErrPublishFailed, ErrResolveFailed, ErrResolveRecursion, ErrExpiredRecord, ErrUnrecognizedValidity, - ErrInvalidProquint + ErrInvalidProquint, + ErrInvalidDomain, + ErrInvalidDNSLink } NamesysErrs; typedef struct s_resolvers { @@ -73,4 +81,9 @@ int IsExtendedTLD (char *s); int IsTLD (char *s); int IsDomain (char *s); + + int DNSResolverResolveOnce (DNSResolver *r, char **path, char *name); + int workDomain (int output, DNSResolver *r, char *name); + int parseEntry (char **Path, char *txt); + int tryParseDnsLink (char **Path, char *txt); #endif //NAMESYS_H diff --git a/namesys/dns.c b/namesys/dns.c new file mode 100644 index 0000000..3ed6a90 --- /dev/null +++ b/namesys/dns.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipfs/cid/cid.h" +#include "ipfs/path/path.h" +#include "ipfs/namesys/namesys.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 DNSResolverResolveOnce (char **path, char *name) +{ + char **segments, *domain, *dnslink, buf[500], dlprefix[] = "_dnslink."; + int p1[2], p2[2], r, c=2; + struct pollfd event[2], *e; + + segments = SplitN(name, "/", 2); + domain = segments[0]; + + *path = NULL; + + if (!IsDomain(domain)) { + return ErrInvalidDomain; + } + //log.Infof("DNSResolver resolving %s", domain); + + if (pipe(p1) || pipe(p2)) { + return ErrPipe; + } + + dnslink = malloc(strlen(domain) + sizeof(dlprefix)); + if (!dnslink) { + return ErrAllocFailed; + } + strcpy (dnslink, dlprefix); + strcat (dnslink, domain); + + 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 workDomain (p1[STDOUT_FILENO], r, 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. + return workDomain (p2[STDOUT_FILENO], r, 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) { + strcpy(*path, buf); + } + } 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 (SegmentsLength (segments) > 1) { + name = *path + strlen(*path) - 1; + while (*name == '/') { + *name-- = '\0'; + } + name = *path; + *path = PathFromSegments (name, segments+1); + free (name); + if (!*path) { + return ErrResolveFailed; + } + } + FreeSegments (&segments); + return 0; +} + +int workDomain (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 = parseEntry (&path, txt[i]); + if (!err) { + err = (write (output, path, strlen(path)) != strlen(path)); + free (path); + if (err) { + return ErrPipe; + } + return 0; + } + } + return ErrResolveFailed; +} + +int parseEntry (char **path, char *txt) +{ + char buf[500]; + int err; + + err = ParseCidToPath(buf, txt); // bare IPFS multihashes + if (! err) { + *path = malloc(strlen(buf) + 1); + if (!*path) { + return ErrAllocFailed; + } + strcpy(*path, buf); + return 0; + } + return tryParseDnsLink(path, txt); +} + +int tryParseDnsLink(char **path, char *txt) +{ + char **parts = SplitN(txt, "=", 2), buf[500]; + int err; + + if (SegmentsLength(parts) == 2 && strcmp(parts[0], "dnslink")==0) { + err = ParsePath(buf, parts[1]); + if (err == 0) { + *parts = malloc(strlen(buf) + 1); + if (! *parts) { + return ErrAllocFailed; + } + strcpy(*parts, buf); + return 0; + } + return err; + } + return ErrInvalidDNSLink; +}