[git] GnuPG - branch, master, updated. gnupg-2.1.9-65-g5e7ac03

by Werner Koch cvs at cvs.gnupg.org
Sun Oct 25 16:51:34 CET 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  5e7ac031f513ad3b60e4f092fa72b3bec0676515 (commit)
       via  0e3c9f184a5fb3e41277700d690febc2eee9600a (commit)
       via  927f34603d942868af6a7bd0f347681bbad76a94 (commit)
       via  816505958ac4308ee0dfe787d1b706982428b6cc (commit)
      from  7f65e84ac035e8f7a25639a6b09eb6000115e337 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 5e7ac031f513ad3b60e4f092fa72b3bec0676515
Author: Werner Koch <wk at gnupg.org>
Date:   Sun Oct 25 16:38:07 2015 +0100

    dirmngr: Add workaround for broken getaddrinfo.
    
    * dirmngr/dns-stuff.c (resolve_name_standard): On failure retry by
    first resolving the CNAME.
    (get_dns_cname): New.
    
    * dirmngr/t-dns-stuff.c (main): Add option --cname.
    --
    
    At least the getaddrinfo implementation in glibc 2.19-13 from Debian
    returns EAI_NONAME if the CNAME points to a too long list of A/AAAA
    addresses.  Looking at the wire the data is correctly returned from
    the server but getaddrinfo seems to get confused by truncation and
    retry.  To fix this we resolve the CNAME again and call getaddrinfo
    again with the canonical name.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 0d4400f..009802a 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 d784ccf..f3b622d 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 fd1c43a..c3effad 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 f216d06..4ecbd64 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 816b744..35858f6 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"

commit 0e3c9f184a5fb3e41277700d690febc2eee9600a
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Oct 24 16:27:47 2015 +0200

    dirmngr: Better handle systems without IPv6 or IPv4.
    
    * dirmngr/dns-stuff.c (resolve_name_standard): Use AI_ADDRCONFIG.

diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index dc5cb89..d784ccf 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -146,8 +146,9 @@ resolve_name_standard (const char *name, unsigned short port,
   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;
+    hints.ai_flags |= AI_CANONNAME;
 
   if (port)
     snprintf (portstr, sizeof portstr, "%hu", port);

commit 927f34603d942868af6a7bd0f347681bbad76a94
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Oct 24 12:25:17 2015 +0200

    dirmngr: Replace use of getnameinfo by resolve_dns_addr.
    
    * dirmngr/ks-engine-hkp.c (my_getnameinfo): Remove.
    (map_host): Use resolve_dns_addr.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index 809204d..340b012 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -234,52 +234,6 @@ select_random_host (int *table)
 }
 
 
-/* Simplified version of getnameinfo which also returns a numeric
-   hostname inside of brackets.  The caller should provide a buffer
-   for HOST which is 2 bytes larger than the largest hostname.  If
-   NUMERIC is true the returned value is numeric IP address.  Returns
-   0 on success or an EAI error code.  True is stored at R_ISNUMERIC
-   if HOST has a numeric IP address. */
-static int
-my_getnameinfo (dns_addrinfo_t ai, char *host, size_t hostlen,
-                int numeric, int *r_isnumeric)
-{
-  int ec;
-  char *p;
-
-  *r_isnumeric = 0;
-
-  if (hostlen < 5)
-    return EAI_OVERFLOW;
-
-  if (numeric)
-    ec = EAI_NONAME;
-  else
-    ec = getnameinfo (ai->addr, ai->addrlen,
-                      host, hostlen, NULL, 0, NI_NAMEREQD);
-
-  if (!ec && *host == '[')
-    ec = EAI_FAIL;  /* A name may never start with a bracket.  */
-  else if (ec == EAI_NONAME)
-    {
-      p = host;
-      if (ai->family == AF_INET6)
-        {
-          *p++ = '[';
-          hostlen -= 2;
-        }
-      ec = getnameinfo (ai->addr, ai->addrlen,
-                        p, hostlen, NULL, 0, NI_NUMERICHOST);
-      if (!ec && ai->family == AF_INET6)
-        strcat (host, "]");
-
-      *r_isnumeric = 1;
-    }
-
-  return ec;
-}
-
-
 /* Map the host name NAME to the actual to be used host name.  This
    allows us to manage round robin DNS names.  We use our own strategy
    to choose one of the hosts.  For example we skip those hosts which
@@ -373,10 +327,10 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
 
           for (ai = aibuf; ai; ai = ai->next)
             {
-              char tmphost[NI_MAXHOST + 2];
+              gpg_error_t tmperr;
+              char *tmphost;
               int tmpidx;
-              int is_numeric;
-              int ec;
+              int is_numeric = 0;
               int i;
 
               if (ai->family != AF_INET && ai->family != AF_INET6)
@@ -387,37 +341,35 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
               if (!is_pool && !is_ip_address (name))
                 {
                   /* This is a hostname but not a pool.  Use the name
-                     as given without going through getnameinfo.  */
-                  if (strlen (name)+1 > sizeof tmphost)
-                    {
-                      ec = EAI_SYSTEM;
-                      gpg_err_set_errno (EINVAL);
-                    }
+                     as given without going through resolve_dns_addr.  */
+                  tmphost = xtrystrdup (name);
+                  if (!tmphost)
+                    tmperr = gpg_error_from_syserror ();
                   else
-                    {
-                      ec = 0;
-                      strcpy (tmphost, name);
-                    }
-                  is_numeric = 0;
+                    tmperr = 0;
                 }
               else
-                ec = my_getnameinfo (ai, tmphost, sizeof tmphost,
-                                     0, &is_numeric);
+                {
+                  tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
+                                             DNS_WITHBRACKET, &tmphost);
+                  if (tmphost && is_ip_address (tmphost))
+                    is_numeric = 1;
+                }
 
-              if (ec)
+              if (tmperr)
                 {
-                  log_info ("getnameinfo failed while checking '%s': %s\n",
-                            name, gai_strerror (ec));
+                  log_info ("resolve_dns_addr failed while checking '%s': %s\n",
+                            name, gpg_strerror (tmperr));
                 }
               else if (refidx+1 >= reftblsize)
                 {
-                  log_error ("getnameinfo returned for '%s': '%s'"
-                            " [index table full - ignored]\n", name, tmphost);
+                  log_error ("resolve_dns_addr for '%s': '%s'"
+                             " [index table full - ignored]\n", name, tmphost);
                 }
               else
                 {
                   tmpidx = find_hostinfo (tmphost);
-                  log_info ("getnameinfo returned for '%s': '%s'%s\n",
+                  log_info ("resolve_dns_addr for '%s': '%s'%s\n",
                             name, tmphost,
                             tmpidx == -1? "" : " [already known]");
 
@@ -436,13 +388,19 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
 
                       if (!is_numeric)
                         {
-                          ec = my_getnameinfo (ai, tmphost, sizeof tmphost,
-                                               1, &is_numeric);
-                          if (!ec && !(ipaddr = xtrystrdup (tmphost)))
-                            ec = EAI_SYSTEM;
-                          if (ec)
-                            log_info ("getnameinfo failed: %s\n",
-                                      gai_strerror (ec));
+                          xfree (tmphost);
+                          tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
+                                                     (DNS_NUMERICHOST
+                                                      | DNS_WITHBRACKET),
+                                                     &tmphost);
+                          if (tmperr)
+                            log_info ("resolve_dns_addr failed: %s\n",
+                                      gpg_strerror (tmperr));
+                          else
+                            {
+                              ipaddr = tmphost;
+                              tmphost = NULL;
+                            }
                         }
 
                       if (ai->family == AF_INET6)
@@ -467,6 +425,7 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
                         reftbl[refidx++] = tmpidx;
                     }
                 }
+              xfree (tmphost);
             }
         }
       reftbl[refidx] = -1;
diff --git a/dirmngr/t-dns-stuff.c b/dirmngr/t-dns-stuff.c
index 0511f93..f216d06 100644
--- a/dirmngr/t-dns-stuff.c
+++ b/dirmngr/t-dns-stuff.c
@@ -225,7 +225,7 @@ main (int argc, char **argv)
                                    | (opt_bracket? DNS_WITHBRACKET:0)),
                                   &host);
           if (err)
-            printf ("[getnameinfo failed: %s]", gpg_strerror (err));
+            printf ("[resolve_dns_addr failed: %s]", gpg_strerror (err));
           else
             {
               printf ("%s", host);
@@ -236,7 +236,7 @@ main (int argc, char **argv)
                                   (opt_bracket? DNS_WITHBRACKET:0),
                                   &host);
           if (err)
-            printf ("[getnameinfo failed (2): %s]", gpg_strerror (err));
+            printf ("[resolve_dns_addr failed (2): %s]", gpg_strerror (err));
           else
             {
               if (!is_ip_address (host))

commit 816505958ac4308ee0dfe787d1b706982428b6cc
Author: Werner Koch <wk at gnupg.org>
Date:   Sat Oct 24 16:27:47 2015 +0200

    dirmngr: Implement a getnameinfo wrapper.
    
    * dirmngr/dns-stuff.h (DNS_NUMERICHOST): New.
    (DNS_WITHBRACKET): New.
    * dirmngr/dns-stuff.c (resolve_name_standard): Factor code out to...
    (map_eai_to_gpg_error): new.
    (resolve_addr_standard): New.
    (resolve_dns_addr): New.
    
    * dirmngr/ks-engine-hkp.c (is_ip_address): Move to ...
    * dirmngr/dns-stuff.c (is_ip_address): here.  Add support for non
    bracketed v6 addresses.
    
    * dirmngr/t-dns-stuff.c: Remove header netdb.h.
    (main): Add option --bracket.  Use resolve_dns_name instead of
    getnameinfo.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index 300d086..dc5cb89 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -54,6 +54,11 @@
 #include "host2net.h"
 #include "dns-stuff.h"
 
+
+#if AF_UNSPEC != 0
+# error AF_UNSPEC does not have the value 0
+#endif
+
 /* Not every installation has gotten around to supporting SRVs or
    CERTs yet... */
 #ifndef T_SRV
@@ -96,6 +101,30 @@ free_dns_addrinfo (dns_addrinfo_t ai)
 }
 
 
+static gpg_error_t
+map_eai_to_gpg_error (int ec)
+{
+  gpg_error_t err;
+
+  switch (ec)
+    {
+    case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
+    case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
+    case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
+    case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
+    case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
+    case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
+    case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
+    case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
+    case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
+    case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
+    case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
+    default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
+    }
+  return err;
+}
+
+
 /* Resolve a name using the standard system function.  */
 static gpg_error_t
 resolve_name_standard (const char *name, unsigned short port,
@@ -132,21 +161,7 @@ resolve_name_standard (const char *name, unsigned short port,
   if (ret)
     {
       aibuf = NULL;
-      switch (ret)
-        {
-        case EAI_AGAIN:     err = gpg_error (GPG_ERR_EAGAIN); break;
-        case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
-        case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
-        case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
-        case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
-        case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
-        case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
-        case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
-        case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
-        case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
-        case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
-        default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
-        }
+      err = map_eai_to_gpg_error (ret);
       goto leave;
     }
 
@@ -193,6 +208,66 @@ resolve_name_standard (const char *name, unsigned short port,
 }
 
 
+/* Resolve an address using the standard system function.  */
+static gpg_error_t
+resolve_addr_standard (const struct sockaddr *addr, int addrlen,
+                       unsigned int flags, char **r_name)
+{
+  gpg_error_t err;
+  int ec;
+  char *buffer, *p;
+  int buflen;
+
+  *r_name = NULL;
+
+  buflen = NI_MAXHOST;
+  buffer = xtrymalloc (buflen + 2 + 1);
+  if (!buffer)
+    return gpg_error_from_syserror ();
+
+  if ((flags & DNS_NUMERICHOST) || tor_mode)
+    ec = EAI_NONAME;
+  else
+    ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
+
+  if (!ec && *buffer == '[')
+    ec = EAI_FAIL;  /* A name may never start with a bracket.  */
+  else if (ec == EAI_NONAME)
+    {
+      p = buffer;
+      if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+        {
+          *p++ = '[';
+          buflen -= 2;
+        }
+      ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
+      if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+        strcat (buffer, "]");
+    }
+
+  if (ec)
+    err = map_eai_to_gpg_error (ec);
+  else
+    {
+      p = xtryrealloc (buffer, strlen (buffer)+1);
+      if (!p)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          buffer = p;
+          err = 0;
+        }
+    }
+
+  if (err)
+    xfree (buffer);
+  else
+    *r_name = buffer;
+
+  return err;
+}
+
+
 /* This a wrapper around getaddrinfo with slighly different semantics.
    NAME is the name to resolve.
    PORT is the requested port or 0.
@@ -219,6 +294,85 @@ resolve_dns_name (const char *name, unsigned short port,
 }
 
 
+gpg_error_t
+resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+                  unsigned int flags, char **r_name)
+{
+#ifdef USE_ADNS_disabled_for_now
+  return resolve_addr_adns (addr, addrlen, flags, r_name);
+#else
+  return resolve_addr_standard (addr, addrlen, flags, r_name);
+#endif
+}
+
+
+/* Check whether NAME is an IP address.  Returns true if it is either
+   an IPv6 or IPv4 numerical address.  */
+int
+is_ip_address (const char *name)
+{
+  const char *s;
+  int ndots, dblcol, n;
+
+  if (*name == '[')
+    return 1; /* yes: A legal DNS name may not contain this character;
+                 this mut be bracketed v6 address.  */
+  if (*name == '.')
+    return 0; /* No.  A leading dot is not a valid IP address.  */
+
+  /* Check whether this is a v6 address.  */
+  ndots = n = dblcol = 0;
+  for (s=name; *s; s++)
+    {
+      if (*s == ':')
+        {
+          ndots++;
+          if (s[1] == ':')
+            {
+              ndots++;
+              if (dblcol)
+                return 0; /* No: Only one "::" allowed.  */
+              dblcol++;
+              if (s[1])
+                s++;
+            }
+          n = 0;
+        }
+      else if (*s == '.')
+        goto legacy;
+      else if (!strchr ("0123456789abcdefABCDEF", *s))
+        return 0; /* No: Not a hex digit.  */
+      else if (++n > 4)
+        return 0; /* To many digits in a group.  */
+    }
+  if (ndots > 7)
+    return 0; /* No: Too many colons.  */
+  else if (ndots > 1)
+    return 1; /* Yes: At least 2 colons indicate an v6 address.  */
+
+ legacy:
+  /* Check whether it is legacy IP address.  */
+  ndots = n = 0;
+  for (s=name; *s; s++)
+    {
+      if (*s == '.')
+        {
+          if (s[1] == '.')
+            return 0; /* No:  Douple dot. */
+          if (atoi (s+1) > 255)
+            return 0; /* No:  Ipv4 byte value too large.  */
+          ndots++;
+          n = 0;
+        }
+      else if (!strchr ("0123456789", *s))
+        return 0; /* No: Not a digit.  */
+      else if (++n > 3)
+        return 0; /* No: More than 3 digits.  */
+    }
+  return !!(ndots == 3);
+}
+
+
 #ifdef USE_ADNS
 /* Init ADNS and store the new state at R_STATE.  Returns 0 on
    success; prints an error message and returns an error code on
diff --git a/dirmngr/dns-stuff.h b/dirmngr/dns-stuff.h
index 13c47df..fd1c43a 100644
--- a/dirmngr/dns-stuff.h
+++ b/dirmngr/dns-stuff.h
@@ -40,7 +40,16 @@
 # include <sys/socket.h>
 #endif
 
+/*
+ * Flags used with resolve_dns_addr.
+ */
+#define DNS_NUMERICHOST        1  /* Force numeric output format.  */
+#define DNS_WITHBRACKET        2  /* Put brackets around numeric v6
+                                     addresses.  */
 
+/*
+ * Constants for use with get_dns_cert.
+ */
 #define DNS_CERTTYPE_ANY       0 /* Internal catch all type. */
 /* Certificate types according to RFC-4398:  */
 #define DNS_CERTTYPE_PKIX      1 /* X.509 as per PKIX. */
@@ -58,6 +67,8 @@
 #define DNS_CERTTYPE_RRBASE 1024 /* Base of special constants.  */
 #define DNS_CERTTYPE_RR61   (DNS_CERTTYPE_RRBASE + 61)
 
+
+
 struct dns_addrinfo_s;
 typedef struct dns_addrinfo_s *dns_addrinfo_t;
 struct dns_addrinfo_s
@@ -87,17 +98,25 @@ gpg_error_t enable_dns_tormode (void);
 
 void free_dns_addrinfo (dns_addrinfo_t ai);
 
-/* Provide function similar to getaddrinfo.  */
+/* Function similar to getaddrinfo.  */
 gpg_error_t resolve_dns_name (const char *name, unsigned short port,
                               int want_family, int want_socktype,
                               dns_addrinfo_t *r_dai, char **r_canonname);
 
+/* Function similar to getnameinfo.  */
+gpg_error_t resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+                              unsigned int flags, char **r_name);
+
+/* Return true if NAME is a numerical IP address.  */
+int is_ip_address (const char *name);
+
 /* 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,
                           unsigned char **r_fpr, size_t *r_fprlen,
                           char **r_url);
 
+
 int getsrv (const char *name,struct srventry **list);
 
 
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index 444f305..809204d 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -280,38 +280,6 @@ my_getnameinfo (dns_addrinfo_t ai, char *host, size_t hostlen,
 }
 
 
-/* Check whether NAME is an IP address.  */
-static int
-is_ip_address (const char *name)
-{
-  int ndots, n;
-
-  if (*name == '[')
-    return 1;
-  /* Check whether it is legacy IP address.  */
-  if (*name == '.')
-    return 0; /* No.  */
-  ndots = n = 0;
-  for (; *name; name++)
-    {
-      if (*name == '.')
-        {
-          if (name[1] == '.')
-            return 0; /* No. */
-          if (atoi (name+1) > 255)
-            return 0; /* Value too large.  */
-          ndots++;
-          n = 0;
-        }
-      else if (!strchr ("012345678", *name))
-        return 0; /* Not a digit.  */
-      else if (++n > 3)
-        return 0; /* More than 3 digits.  */
-    }
-  return !!(ndots == 3);
-}
-
-
 /* Map the host name NAME to the actual to be used host name.  This
    allows us to manage round robin DNS names.  We use our own strategy
    to choose one of the hosts.  For example we skip those hosts which
diff --git a/dirmngr/t-dns-stuff.c b/dirmngr/t-dns-stuff.c
index 63d4cdd..0511f93 100644
--- a/dirmngr/t-dns-stuff.c
+++ b/dirmngr/t-dns-stuff.c
@@ -22,9 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
-#ifndef HAVE_W32_SYSTEM
-# include <netdb.h>
-#endif
+
 
 #include "util.h"
 #include "dns-stuff.h"
@@ -45,6 +43,7 @@ main (int argc, char **argv)
   int opt_tor = 0;
   int opt_cert = 0;
   int opt_srv = 0;
+  int opt_bracket = 0;
   char const *name = NULL;
 
   gpgrt_init ();
@@ -66,6 +65,7 @@ main (int argc, char **argv)
                  "  --verbose         print timings etc.\n"
                  "  --debug           flyswatter\n"
                  "  --use-tor         use Tor\n"
+                 "  --bracket         enclose v6 addresses in brackets\n"
                  "  --cert            lookup a CERT RR\n"
                  "  --srv             lookup a SRV RR\n"
                  , stdout);
@@ -87,6 +87,11 @@ main (int argc, char **argv)
           opt_tor = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--bracket"))
+        {
+          opt_bracket = 1;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--cert"))
         {
           any_options = opt_cert = 1;
@@ -194,8 +199,7 @@ main (int argc, char **argv)
     {
       char *cname;
       dns_addrinfo_t aibuf, ai;
-      int ret;
-      char hostbuf[1025];
+      char *host;
 
       printf ("Lookup on '%s'\n", name);
 
@@ -216,14 +220,30 @@ main (int argc, char **argv)
                   ai->family == AF_INET?  "inet4" : "?    ",
                   ai->socktype, ai->protocol);
 
-          ret = getnameinfo (ai->addr, ai->addrlen,
-                             hostbuf, sizeof hostbuf,
-                             NULL, 0,
-                             NI_NUMERICHOST);
-          if (ret)
-            printf ("[getnameinfo failed: %s]\n", gai_strerror (ret));
+          err = resolve_dns_addr (ai->addr, ai->addrlen,
+                                  (DNS_NUMERICHOST
+                                   | (opt_bracket? DNS_WITHBRACKET:0)),
+                                  &host);
+          if (err)
+            printf ("[getnameinfo failed: %s]", gpg_strerror (err));
+          else
+            {
+              printf ("%s", host);
+              xfree (host);
+            }
+
+          err = resolve_dns_addr (ai->addr, ai->addrlen,
+                                  (opt_bracket? DNS_WITHBRACKET:0),
+                                  &host);
+          if (err)
+            printf ("[getnameinfo failed (2): %s]", gpg_strerror (err));
           else
-            printf ("%s\n", hostbuf);
+            {
+              if (!is_ip_address (host))
+                printf ("  (%s)", host);
+              xfree (host);
+            }
+          putchar ('\n');
         }
       xfree (cname);
       free_dns_addrinfo (aibuf);

-----------------------------------------------------------------------

Summary of changes:
 dirmngr/Makefile.am     |   4 +-
 dirmngr/dns-stuff.c     | 316 +++++++++++++++++++++++++++++++++++++++++++++---
 dirmngr/dns-stuff.h     |  24 +++-
 dirmngr/ks-engine-hkp.c | 141 ++++++---------------
 dirmngr/t-dns-stuff.c   |  67 ++++++++--
 dirmngr/t-http.c        |   1 +
 6 files changed, 416 insertions(+), 137 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list