diff options
Diffstat (limited to 'dirmngr/dns-stuff.c')
-rw-r--r-- | dirmngr/dns-stuff.c | 230 |
1 files changed, 219 insertions, 11 deletions
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c index 6ec440d38..a7953638c 100644 --- a/dirmngr/dns-stuff.c +++ b/dirmngr/dns-stuff.c @@ -46,6 +46,9 @@ #include <string.h> #include <unistd.h> +/* William Ahern's DNS library, included as a source copy. */ +#include "dns.h" + #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ # undef USE_NPTH #endif @@ -125,6 +128,8 @@ standard_resolver_p (void) gpg_error_t enable_dns_tormode (int new_circuit) { + /* XXX: dns.c doesn't support SOCKS credentials. */ + if (!*tor_credentials || new_circuit) { static unsigned int counter; @@ -193,6 +198,191 @@ map_eai_to_gpg_error (int ec) return err; } +struct +{ + struct dns_resolv_conf *resolv_conf; + struct dns_hosts *hosts; + struct dns_hints *hints; + + struct sockaddr_storage socks_host; +} libdns; + +static gpg_error_t +libdns_error_to_gpg_error (int error) +{ + gpg_err_code_t ec; + + switch (error) + { + case 0: + return 0; + + default: + /* XXX */ + fprintf (stderr, "libdns: %s\n", dns_strerror (error)); + ec = GPG_ERR_GENERAL; + break; + } + return gpg_error (ec); +} + +static gpg_error_t +libdns_init (void) +{ + int error; + + libdns.resolv_conf = dns_resconf_open (&error); + if (! libdns.resolv_conf) + goto leave; + +#if 0 + error = dns_resconf_pton (&libdns.resolv_conf->nameserver[0], + "[127.0.0.1]:53"); + if (error) + goto leave; +#else + error = dns_resconf_loadpath (libdns.resolv_conf, "/etc/resolv.conf"); + if (error) + goto leave; + + error = dns_nssconf_loadpath (libdns.resolv_conf, "/etc/nsswitch.conf"); + if (error) + goto leave; +#endif + + libdns.hosts = dns_hosts_open (&error); + if (! libdns.hosts) + goto leave; + + /* dns_hints_local for stub mode, dns_hints_root for recursive. */ + libdns.hints = dns_hints_local (libdns.resolv_conf, &error); + if (! libdns.hints) + goto leave; + + /* XXX */ + leave: + return libdns_error_to_gpg_error (error); +} + + +static gpg_error_t +resolve_name_libdns (const char *name, unsigned short port, + int want_family, int want_socktype, + dns_addrinfo_t *r_dai, char **r_canonname) +{ + gpg_error_t err = 0; + dns_addrinfo_t daihead = NULL; + dns_addrinfo_t dai; + struct dns_resolver *res; + struct dns_addrinfo *ai = NULL; + struct addrinfo hints; + struct addrinfo *ent; + char portstr_[21]; + char *portstr = portstr_; + int ret; + + err = libdns_init (); + if (err) + return err; + + *r_dai = NULL; + if (r_canonname) + *r_canonname = NULL; + + memset (&hints, 0, sizeof hints); + hints.ai_family = want_family; + hints.ai_socktype = want_socktype; + hints.ai_flags = AI_ADDRCONFIG; + if (r_canonname) + hints.ai_flags |= AI_CANONNAME; + + if (port) + snprintf (portstr_, sizeof portstr_, "%hu", port); + else + portstr = NULL; + + res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL, + dns_opts (/*.socks_host=&libdns.socks_host*/), &ret); + if (! res) + return libdns_error_to_gpg_error (ret); + + ai = dns_ai_open (name, portstr, 0, &hints, res, &ret); + if (! ai) + goto leave; + + /* XXX this is blocking. */ + do { + ret = dns_ai_nextent (&ent, ai); + switch (ret) { + case 0: + if (r_canonname && ! *r_canonname && ent && ent->ai_canonname) + { + *r_canonname = xtrystrdup (ent->ai_canonname); + if (!*r_canonname) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + + dai = xtrymalloc (sizeof *dai + ent->ai_addrlen - 1); + if (dai == NULL) + { + err = ENOMEM; + goto leave; + } + + dai->family = ent->ai_family; + dai->socktype = ent->ai_socktype; + dai->protocol = ent->ai_protocol; + dai->addrlen = ent->ai_addrlen; + memcpy (dai->addr, ent->ai_addr, ent->ai_addrlen); + dai->next = daihead; + daihead = dai; + + xfree (ent); + break; + + case ENOENT: + break; + + case EAGAIN: + if (dns_ai_elapsed (ai) > 30) + log_assert (! "XXX: query timed-out"); + + dns_ai_poll (ai, 1); + break; + + default: + goto leave; + } + } while (ret != ENOENT); + + if (ret == ENOENT && daihead != NULL) + ret = 0; /* We got some results, we're good. */ + + leave: + dns_ai_close (ai); + dns_res_close (res); + + if (ret && ! err) + err = libdns_error_to_gpg_error (ret); + + if (err) + { + if (r_canonname) + { + xfree (*r_canonname); + *r_canonname = NULL; + } + free_dns_addrinfo (daihead); + } + else + *r_dai = daihead; + + return err; +} + /* Resolve a name using the standard system function. */ static gpg_error_t @@ -376,11 +566,10 @@ resolve_dns_name (const char *name, unsigned short port, int want_family, int want_socktype, dns_addrinfo_t *r_ai, char **r_canonname) { -#ifdef NOTYET if (!standard_resolver) return resolve_name_libdns (name, port, want_family, want_socktype, r_ai, r_canonname); -#endif + return resolve_name_standard (name, port, want_family, want_socktype, r_ai, r_canonname); } @@ -475,6 +664,16 @@ is_onion_address (const char *name) } +/* libdns version of get_dns_cert. */ +static gpg_error_t +get_dns_cert_libdns (const char *name, int want_certtype, + void **r_key, size_t *r_keylen, + unsigned char **r_fpr, size_t *r_fprlen, char **r_url) +{ + return gpg_error (ENOTSUP); +} + + /* Standard resolver version of get_dns_cert. */ static gpg_error_t get_dns_cert_standard (const char *name, int want_certtype, @@ -701,11 +900,10 @@ get_dns_cert (const char *name, int want_certtype, *r_fprlen = 0; *r_url = NULL; -#ifdef NOTYET if (!standard_resolver) return get_dns_cert_libdns (name, want_certtype, r_key, r_keylen, r_fpr, r_fprlen, r_url); -#endif + return get_dns_cert_standard (name, want_certtype, r_key, r_keylen, r_fpr, r_fprlen, r_url); } @@ -728,6 +926,14 @@ priosort(const void *a,const void *b) static int getsrv_standard (const char *name, struct srventry **list) { + return gpg_error (ENOTSUP); +} + + +/* libdns based helper for getsrv. */ +static int +getsrv_libdns (const char *name, struct srventry **list) +{ #ifdef HAVE_SYSTEM_RESOLVER union { unsigned char ans[2048]; @@ -850,12 +1056,8 @@ getsrv (const char *name, struct srventry **list) *list = NULL; - if (0) - ; -#ifdef NOTYET - else if (!standard_resolver) + if (!standard_resolver) srvcount = getsrv_libdns (name, list); -#endif else srvcount = getsrv_standard (name, list); @@ -939,6 +1141,14 @@ getsrv (const char *name, struct srventry **list) } +/* libdns version of get_dns_cname. */ +gpg_error_t +get_dns_cname_libdns (const char *name, char **r_cname) +{ + return gpg_error (ENOTSUP); +} + + /* Standard resolver version of get_dns_cname. */ gpg_error_t get_dns_cname_standard (const char *name, char **r_cname) @@ -1022,10 +1232,8 @@ get_dns_cname (const char *name, char **r_cname) { *r_cname = NULL; -#ifdef NOTYET if (!standard_resolver) return get_dns_cname_libdns (name, r_cname); -#endif return get_dns_cname_standard (name, r_cname); } |