aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dirmngr/Makefile.am4
-rw-r--r--dirmngr/dns-stuff.c133
-rw-r--r--dirmngr/dns-stuff.h3
-rw-r--r--dirmngr/t-dns-stuff.c23
-rw-r--r--dirmngr/t-http.c1
5 files changed, 161 insertions, 3 deletions
diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 0d4400fad..009802ad6 100644
--- a/dirmngr/Makefile.am
+++ b/dirmngr/Makefile.am
@@ -140,9 +140,9 @@ t_ldap_parse_uri_SOURCES = \
http.c dns-stuff.c \
$(ldap_url) $(t_common_src)
t_ldap_parse_uri_CFLAGS = -DWITHOUT_NPTH=1
-t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd)
+t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd) $(DNSLIBS)
t_dns_stuff_SOURCES = t-dns-stuff.c dns-stuff.c
-t_dns_stuff_LDADD = $(t_common_ldadd)
+t_dns_stuff_LDADD = $(t_common_ldadd) $(DNSLIBS)
$(PROGRAMS) : $(libcommon) $(libcommonpth)
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index d784ccf97..f3b622de3 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -163,7 +163,29 @@ resolve_name_standard (const char *name, unsigned short port,
{
aibuf = NULL;
err = map_eai_to_gpg_error (ret);
- goto leave;
+ if (gpg_err_code (err) == GPG_ERR_NO_NAME)
+ {
+ /* There seems to be a bug in the glibc getaddrinfo function
+ if the CNAME points to a long list of A and AAAA records
+ in which case the function return NO_NAME. Let's do the
+ CNAME redirection again. */
+ char *cname;
+
+ if (get_dns_cname (name, &cname))
+ goto leave; /* Still no success. */
+
+ ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf);
+ xfree (cname);
+ if (ret)
+ {
+ aibuf = NULL;
+ err = map_eai_to_gpg_error (ret);
+ goto leave;
+ }
+ err = 0; /* Yep, now it worked. */
+ }
+ else
+ goto leave;
}
if (r_canonname && aibuf && aibuf->ai_canonname)
@@ -1011,3 +1033,112 @@ getsrv (const char *name,struct srventry **list)
return -1;
}
#endif /*USE_DNS_SRV*/
+
+
+gpg_error_t
+get_dns_cname (const char *name, char **r_cname)
+{
+ gpg_error_t err;
+ int rc;
+
+ *r_cname = NULL;
+
+#ifdef USE_ADNS
+ {
+ adns_state state;
+ adns_answer *answer = NULL;
+
+ if (my_adns_init (&state))
+ return gpg_error (GPG_ERR_GENERAL);
+
+ rc = adns_synchronous (state, name, adns_r_cname, adns_qf_quoteok_query,
+ &answer);
+ if (rc)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("DNS query failed: %s\n", gpg_strerror (err));
+ adns_finish (state);
+ return err;
+ }
+ if (answer->status != adns_s_ok
+ || answer->type != adns_r_cname || answer->nrrs != 1)
+ {
+ err = gpg_error (GPG_ERR_GENERAL);
+ log_error ("DNS query returned an error or no records: %s (%s)\n",
+ adns_strerror (answer->status),
+ adns_errabbrev (answer->status));
+ adns_free (answer);
+ adns_finish (state);
+ return err;
+ }
+ *r_cname = xtrystrdup (answer->rrs.str[0]);
+ if (!*r_cname)
+ err = gpg_error_from_syserror ();
+ else
+ err = 0;
+
+ adns_free (answer);
+ adns_finish (state);
+ return err;
+ }
+#else /*!USE_ADNS*/
+ {
+ unsigned char answer[2048];
+ HEADER *header = (HEADER *)answer;
+ unsigned char *pt, *emsg;
+ int r;
+ char *cname;
+ int cnamesize = 1025;
+ u16 count;
+
+ /* Do not allow a query using the standard resolver in Tor mode. */
+ if (tor_mode)
+ return -1;
+
+ r = res_query (name, C_IN, T_CERT, answer, sizeof answer);
+ if (r < sizeof (HEADER) || r > sizeof answer)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+ if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
+ return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found. */
+ if (count != 1)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+
+ emsg = &answer[r];
+ pt = &answer[sizeof(HEADER)];
+ rc = dn_skipname (pt, emsg);
+ if (rc == -1)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+
+ pt += rc + QFIXEDSZ;
+ if (pt >= emsg)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+
+ rc = dn_skipname (pt, emsg);
+ if (rc == -1)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+ pt += rc + 2 + 2 + 4;
+ if (pt+2 >= emsg)
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+ pt += 2; /* Skip rdlen */
+
+ cname = xtrymalloc (cnamesize);
+ if (!cname)
+ return gpg_error_from_syserror ();
+
+ rc = dn_expand (answer, emsg, pt, cname, cnamesize -1);
+ if (rc == -1)
+ {
+ xfree (cname);
+ return gpg_error (GPG_ERR_SERVER_FAILED);
+ }
+ *r_cname = xtryrealloc (cname, strlen (cname)+1);
+ if (!*r_cname)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (cname);
+ return err;
+ }
+ return 0;
+ }
+#endif /*!USE_ADNS*/
+}
diff --git a/dirmngr/dns-stuff.h b/dirmngr/dns-stuff.h
index fd1c43acb..c3effad83 100644
--- a/dirmngr/dns-stuff.h
+++ b/dirmngr/dns-stuff.h
@@ -110,6 +110,9 @@ gpg_error_t resolve_dns_addr (const struct sockaddr *addr, int addrlen,
/* Return true if NAME is a numerical IP address. */
int is_ip_address (const char *name);
+/* Get the canonical name for NAME. */
+gpg_error_t get_dns_cname (const char *name, char **r_cname);
+
/* Return a CERT record or an arbitray RR. */
gpg_error_t get_dns_cert (const char *name, int want_certtype,
void **r_key, size_t *r_keylen,
diff --git a/dirmngr/t-dns-stuff.c b/dirmngr/t-dns-stuff.c
index f216d06eb..4ecbd64f0 100644
--- a/dirmngr/t-dns-stuff.c
+++ b/dirmngr/t-dns-stuff.c
@@ -44,6 +44,7 @@ main (int argc, char **argv)
int opt_cert = 0;
int opt_srv = 0;
int opt_bracket = 0;
+ int opt_cname = 0;
char const *name = NULL;
gpgrt_init ();
@@ -68,6 +69,7 @@ main (int argc, char **argv)
" --bracket enclose v6 addresses in brackets\n"
" --cert lookup a CERT RR\n"
" --srv lookup a SRV RR\n"
+ " --cname lookup a CNAME RR\n"
, stdout);
exit (0);
}
@@ -102,6 +104,11 @@ main (int argc, char **argv)
any_options = opt_srv = 1;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--cname"))
+ {
+ any_options = opt_cname = 1;
+ argc--; argv++;
+ }
else if (!strncmp (*argv, "--", 2))
{
fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
@@ -177,6 +184,22 @@ main (int argc, char **argv)
xfree (fpr);
xfree (url);
}
+ else if (opt_cname)
+ {
+ char *cname;
+
+ printf ("CNAME lookup on '%s'\n", name);
+ err = get_dns_cname (name, &cname);
+ if (err)
+ printf ("get_dns_cname failed: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+ else
+ {
+ printf ("CNAME found: '%s'\n", cname);
+ }
+
+ xfree (cname);
+ }
else if (opt_srv)
{
struct srventry *srv;
diff --git a/dirmngr/t-http.c b/dirmngr/t-http.c
index 816b74490..35858f649 100644
--- a/dirmngr/t-http.c
+++ b/dirmngr/t-http.c
@@ -36,6 +36,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <assuan.h>
#include "util.h"
#include "logging.h"