[Pkg-gnupg-commit] [gnupg2] 113/180: dirmngr: Implement CNAME and SRV record lookup via libdns.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Sat Dec 24 22:29:16 UTC 2016
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch master
in repository gnupg2.
commit 4c13e4e3debe0e55e86ae29c095f2d86eb0a6f11
Author: Werner Koch <wk at gnupg.org>
Date: Wed Dec 14 10:47:53 2016 +0100
dirmngr: Implement CNAME and SRV record lookup via libdns.
* dirmngr/dns-stuff.c (dns_free): New macro.
(libdns): Move var to the top.
(libdns_error_to_gpg_error): Map error codes to the new gpg-error
codes.
(resolve_name_libdns): Restructure code.
(getsrv_libdns): New.
(get_dns_cname_libdns): New.
Signed-off-by: Werner Koch <wk at gnupg.org>
---
dirmngr/dns-stuff.c | 347 ++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 283 insertions(+), 64 deletions(-)
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index bcf3639..33ef3eb 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -49,6 +49,12 @@
/* William Ahern's DNS library, included as a source copy. */
#include "dns.h"
+/* dns.c has a dns_p_free but it is not exported. We use our own
+ * wrapper here so that we do not accidentally use xfree which would
+ * be wrong for dns.c allocated data. */
+#define dns_free(a) free ((a))
+
+
#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
# undef USE_NPTH
#endif
@@ -105,6 +111,16 @@ static char tor_nameserver[40+20];
/* A string to hold the credentials presented to Tor. */
static char tor_credentials[50];
+/* Libdns gobal data. */
+struct
+{
+ struct dns_resolv_conf *resolv_conf;
+ struct dns_hosts *hosts;
+ struct dns_hints *hints;
+
+ struct sockaddr_storage socks_host;
+} libdns;
+
/* Calling this function with YES set to True forces the use of the
* standard resolver even if dirmngr has been built with support for
@@ -216,34 +232,42 @@ 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)
+libdns_error_to_gpg_error (int serr)
{
gpg_err_code_t ec;
- switch (error)
+ switch (serr)
{
- case 0:
- return 0;
+ case 0: ec = 0; break;
+
+ case DNS_ENOBUFS: ec = GPG_ERR_BUFFER_TOO_SHORT; break;
+ case DNS_EILLEGAL: ec = GPG_ERR_INV_OBJ; break;
+ case DNS_EORDER: ec = GPG_ERR_INV_ORDER; break;
+ case DNS_ESECTION: ec = GPG_ERR_DNS_SECTION; break;
+ case DNS_EUNKNOWN: ec = GPG_ERR_DNS_UNKNOWN; break;
+ case DNS_EADDRESS: ec = GPG_ERR_DNS_ADDRESS; break;
+ case DNS_ENOQUERY: ec = GPG_ERR_DNS_NO_QUERY; break;
+ case DNS_ENOANSWER:ec = GPG_ERR_DNS_NO_ANSWER; break;
+ case DNS_EFETCHED: ec = GPG_ERR_ALREADY_FETCHED; break;
+ case DNS_ESERVICE: ec = GPG_ERR_NOT_SUPPORTED; break;
+ case DNS_ENONAME: ec = GPG_ERR_NO_NAME; break;
+ case DNS_EFAIL: ec = GPG_ERR_SERVER_FAILED; break;
+ case DNS_ECONNFIN: ec = GPG_ERR_DNS_CLOSED; break;
+ case DNS_EVERIFY: ec = GPG_ERR_DNS_VERIFY; break;
default:
- /* XXX */
- fprintf (stderr, "libdns: %s\n", dns_strerror (error));
- ec = GPG_ERR_GENERAL;
+ if (serr >= 0)
+ ec = gpg_err_code_from_errno (serr);
+ else
+ ec = GPG_ERR_DNS_UNKNOWN;
break;
}
return gpg_error (ec);
}
+
static gpg_error_t
libdns_init (void)
{
@@ -288,25 +312,25 @@ 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;
+ gpg_error_t err;
dns_addrinfo_t daihead = NULL;
dns_addrinfo_t dai;
- struct dns_resolver *res;
+ struct dns_resolver *res = NULL;
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;
+ char *portstr = NULL;
+ int derr;
*r_dai = NULL;
if (r_canonname)
*r_canonname = NULL;
+ err = libdns_init ();
+ if (err)
+ goto leave;
+
memset (&hints, 0, sizeof hints);
hints.ai_family = want_family;
hints.ai_socktype = want_socktype;
@@ -315,24 +339,52 @@ resolve_name_libdns (const char *name, unsigned short port,
hints.ai_flags |= AI_CANONNAME;
if (port)
- snprintf (portstr_, sizeof portstr_, "%hu", port);
- else
- portstr = NULL;
+ {
+ snprintf (portstr_, sizeof portstr_, "%hu", port);
+ portstr = portstr_;
+ }
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);
+ dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
+ if (!res)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
- ai = dns_ai_open (name, portstr, 0, &hints, res, &ret);
- if (! ai)
- goto leave;
+ ai = dns_ai_open (name, portstr, 0, &hints, res, &derr);
+ if (!ai)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ /* Loop over all records. */
+ for (;;)
+ {
+ err = libdns_error_to_gpg_error (dns_ai_nextent (&ent, ai));
+ if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ {
+ if (daihead)
+ err = 0; /* We got some results, we're good. */
+ break; /* Ready. */
+ }
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ {
+ if (dns_ai_elapsed (ai) > 30)
+ {
+ err = gpg_error (GPG_ERR_DNS_TIMEOUT);
+ goto leave;
+ }
+
+ my_unprotect ();
+ dns_ai_poll (ai, 1);
+ my_protect ();
+ continue;
+ }
+ if (err)
+ 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);
@@ -343,10 +395,10 @@ resolve_name_libdns (const char *name, unsigned short port,
}
}
- dai = xtrymalloc (sizeof *dai + ent->ai_addrlen - 1);
+ dai = xtrymalloc (sizeof *dai + ent->ai_addrlen -1);
if (dai == NULL)
{
- err = ENOMEM;
+ err = gpg_error_from_syserror ();
goto leave;
}
@@ -359,33 +411,12 @@ resolve_name_libdns (const char *name, unsigned short port,
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)
@@ -946,14 +977,123 @@ priosort(const void *a,const void *b)
static gpg_error_t
getsrv_libdns (const char *name, struct srventry **list, int *r_count)
{
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ gpg_error_t err;
+ struct dns_resolver *res = NULL;
+ struct dns_packet *ans = NULL;
+ struct dns_rr rr;
+ struct dns_rr_i rri;
+ char host[DNS_D_MAXNAME + 1];
+ int derr;
+ int srvcount=0;
+
+ err = libdns_init ();
+ if (err)
+ goto leave;
+
+ res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
+ dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
+ if (!res)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ if (dns_d_anchor (host, sizeof host, name, strlen (name)) >= sizeof host)
+ {
+ err = gpg_error (GPG_ERR_ENAMETOOLONG);
+ goto leave;
+ }
+
+ err = libdns_error_to_gpg_error
+ (dns_res_submit (res, name, DNS_T_SRV, DNS_C_IN));
+ if (err)
+ goto leave;
+
+ /* Loop until we found a record. */
+ while ((err = libdns_error_to_gpg_error (dns_res_check (res))))
+ {
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ {
+ if (dns_res_elapsed (res) > 30)
+ {
+ err = gpg_error (GPG_ERR_DNS_TIMEOUT);
+ goto leave;
+ }
+
+ my_unprotect ();
+ dns_res_poll (res, 1);
+ my_protect ();
+ }
+ else if (err)
+ goto leave;
+ }
+ ans = dns_res_fetch (res, &derr);
+ if (!ans)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ /* Check the rcode. */
+ switch (dns_p_rcode (ans))
+ {
+ case DNS_RC_NOERROR: break;
+ case DNS_RC_NXDOMAIN: err = gpg_error (GPG_ERR_NO_NAME); break;
+ default: err = GPG_ERR_SERVER_FAILED; break;
+ }
+ if (err)
+ goto leave;
+
+ memset (&rri, 0, sizeof rri);
+ dns_rr_i_init (&rri, ans);
+ rri.section = DNS_S_ALL & ~DNS_S_QD;
+ rri.name = host;
+ rri.type = DNS_T_SRV;
+
+ while (dns_rr_grep (&rr, 1, &rri, ans, &derr))
+ {
+ struct dns_srv dsrv;
+ struct srventry *srv;
+ struct srventry *newlist;
+
+ err = libdns_error_to_gpg_error (dns_srv_parse(&dsrv, &rr, ans));
+ if (err)
+ goto leave;
+
+ newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
+ if (!newlist)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ *list = newlist;
+ memset (&(*list)[srvcount], 0, sizeof(struct srventry));
+ srv = &(*list)[srvcount];
+ srvcount++;
+ srv->priority = dsrv.priority;
+ srv->weight = dsrv.weight;
+ srv->port = dsrv.port;
+ mem2str (srv->target, dsrv.target, sizeof srv->target);
+ }
+
+ *r_count = srvcount;
+
+ leave:
+ if (err)
+ {
+ xfree (*list);
+ *list = NULL;
+ }
+ dns_free (ans);
+ dns_res_close (res);
+ return err;
}
/* Standard resolver based helper for getsrv. Note that it is
* expected that NULL is stored at the address of LIST and 0 is stored
* at the address of R_COUNT. */
-static int
+static gpg_error_t
getsrv_standard (const char *name, struct srventry **list, int *r_count)
{
#ifdef HAVE_SYSTEM_RESOLVER
@@ -1171,11 +1311,90 @@ 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);
+ gpg_error_t err;
+ struct dns_resolver *res = NULL;
+ struct dns_packet *ans = NULL;
+ struct dns_rr rr;
+ struct dns_cname cname;
+ int derr;
+
+ err = libdns_init ();
+ if (err)
+ goto leave;
+
+ res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
+ dns_opts (/*.socks_host=&libdns.socks_host*/), &derr);
+ if (!res)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ err = libdns_error_to_gpg_error
+ (dns_res_submit (res, name, DNS_T_CNAME, DNS_C_IN));
+ if (err)
+ goto leave;
+
+ /* Loop until we found a record. */
+ while ((err = libdns_error_to_gpg_error (dns_res_check (res))))
+ {
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ {
+ if (dns_res_elapsed (res) > 30)
+ {
+ err = gpg_error (GPG_ERR_DNS_TIMEOUT);
+ goto leave;
+ }
+
+ my_unprotect ();
+ dns_res_poll (res, 1);
+ my_protect ();
+ }
+ else if (err)
+ goto leave;
+ }
+ ans = dns_res_fetch (res, &derr);
+ if (!ans)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ /* Check the rcode. */
+ switch (dns_p_rcode (ans))
+ {
+ case DNS_RC_NOERROR: break;
+ case DNS_RC_NXDOMAIN: err = gpg_error (GPG_ERR_NO_NAME); break;
+ default: err = GPG_ERR_SERVER_FAILED; break;
+ }
+ if (err)
+ goto leave;
+
+ /* Parse the result into CNAME. */
+ err = libdns_error_to_gpg_error (dns_p_study (ans));
+ if (err)
+ goto leave;
+
+ if (!dns_d_cname (&cname, sizeof cname, name, strlen (name), ans, &derr))
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ /* Copy result. */
+ *r_cname = xtrystrdup (cname.host);
+ if (!*r_cname)
+ err = gpg_error_from_syserror ();
+
+ leave:
+ dns_free (ans);
+ dns_res_close (res);
+ return err;
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git
More information about the Pkg-gnupg-commit
mailing list