Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / dirmngr / dns-stuff.c
index 8b25e02..7324aae 100644 (file)
 #else
 # if HAVE_SYSTEM_RESOLVER
 #  include <netinet/in.h>
+#  include <arpa/nameser.h>
 #  include <resolv.h>
 # endif
 # include <netdb.h>
 #endif
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
 #include <string.h>
 #include <unistd.h>
 
@@ -94,9 +98,8 @@
 #ifndef T_SRV
 #define T_SRV 33
 #endif
-#ifndef T_CERT
-# define T_CERT 37
-#endif
+#undef T_CERT
+#define T_CERT 37
 
 /* The standard SOCKS and TOR ports.  */
 #define SOCKS_PORT 1080
 #define DEFAULT_TIMEOUT 30
 
 
+#define RESOLV_CONF_NAME "/etc/resolv.conf"
+
 /* Two flags to enable verbose and debug mode.  */
 static int opt_verbose;
 static int opt_debug;
@@ -391,6 +396,39 @@ libdns_error_to_gpg_error (int serr)
 #endif /*USE_LIBDNS*/
 
 
+/* Return true if resolve.conf changed since it was last loaded.  */
+#ifdef USE_LIBDNS
+static int
+resolv_conf_changed_p (void)
+{
+#if defined(HAVE_W32_SYSTEM) || !defined(HAVE_STAT)
+  return 0;
+#else
+  static time_t last_mtime;
+  const char *fname = RESOLV_CONF_NAME;
+  struct stat statbuf;
+  int changed = 0;
+
+  if (stat (fname, &statbuf))
+    {
+      log_error ("stat'ing '%s' failed: %s\n",
+                 fname, gpg_strerror (gpg_error_from_syserror ()));
+      last_mtime = 1; /* Force a "changed" result the next time stat
+                       * works.  */
+    }
+  else if (!last_mtime)
+    last_mtime = statbuf.st_mtime;
+  else if (last_mtime != statbuf.st_mtime)
+    {
+      changed = 1;
+      last_mtime = statbuf.st_mtime;
+    }
+
+  return changed;
+#endif
+}
+#endif /*USE_LIBDNS*/
+
 #ifdef USE_LIBDNS
 /* Initialize libdns.  Returns 0 on success; prints a diagnostic and
  * returns an error code on failure.  */
@@ -496,7 +534,8 @@ libdns_init (void)
 #else /* Unix */
       const char *fname;
 
-      fname = "/etc/resolv.conf";
+      fname = RESOLV_CONF_NAME;
+      resolv_conf_changed_p (); /* Reset timestamp.  */
       err = libdns_error_to_gpg_error
         (dns_resconf_loadpath (ld.resolv_conf, fname));
       if (err)
@@ -526,7 +565,7 @@ libdns_init (void)
           /* No DNS resolution type found in the list.  This might be
            * due to systemd based systems which allow for custom
            * keywords which are not known to us and thus we do not
-           * know whether DNS is wanted or not.  Becuase DNS is
+           * know whether DNS is wanted or not.  Because DNS is
            * important for our infrastructure, we forcefully append
            * DNS to the end of the list.  */
           if (strlen (ld.resolv_conf->lookup)+2 < sizeof ld.resolv_conf->lookup)
@@ -653,6 +692,14 @@ libdns_res_open (struct dns_resolver **r_res)
 
   *r_res = NULL;
 
+  /* Force a reload if resolv.conf has changed.  */
+  if (resolv_conf_changed_p ())
+    {
+      if (opt_debug)
+        log_debug ("dns: resolv.conf changed - forcing reload\n");
+      libdns_reinit_pending = 1;
+    }
+
   if (libdns_reinit_pending)
     {
       libdns_reinit_pending = 0;
@@ -844,7 +891,7 @@ resolve_name_libdns (const char *name, unsigned short port,
             (*r_canonname)[strlen (*r_canonname)-1] = 0;
         }
 
-      dai = xtrymalloc (sizeof *dai + ent->ai_addrlen -1);
+      dai = xtrymalloc (sizeof *dai);
       if (dai == NULL)
         {
           err = gpg_error_from_syserror ();
@@ -968,7 +1015,7 @@ resolve_name_standard (const char *name, unsigned short port,
       if (opt_disable_ipv6 && ai->ai_family == AF_INET6)
         continue;
 
-      dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
+      dai = xtrymalloc (sizeof *dai);
       dai->family = ai->ai_family;
       dai->socktype = ai->ai_socktype;
       dai->protocol = ai->ai_protocol;
@@ -1036,7 +1083,7 @@ resolve_dns_name (const char *name, unsigned short port,
 #ifdef USE_LIBDNS
 /* Resolve an address using libdns.  */
 static gpg_error_t
-resolve_addr_libdns (const struct sockaddr *addr, int addrlen,
+resolve_addr_libdns (const struct sockaddr_storage *addr, int addrlen,
                      unsigned int flags, char **r_name)
 {
   gpg_error_t err;
@@ -1050,13 +1097,13 @@ resolve_addr_libdns (const struct sockaddr *addr, int addrlen,
 
   /* First we turn ADDR into a DNS name (with ".arpa" suffix).  */
   err = 0;
-  if (addr->sa_family == AF_INET6)
+  if (addr->ss_family == AF_INET6)
     {
       const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)addr;
       if (!dns_aaaa_arpa (host, sizeof host, (void*)&a6->sin6_addr))
         err = gpg_error (GPG_ERR_INV_OBJ);
     }
-  else if (addr->sa_family == AF_INET)
+  else if (addr->ss_family == AF_INET)
     {
       const struct sockaddr_in *a4 = (const struct sockaddr_in *)addr;
       if (!dns_a_arpa (host, sizeof host, (void*)&a4->sin_addr))
@@ -1144,18 +1191,19 @@ resolve_addr_libdns (const struct sockaddr *addr, int addrlen,
       buflen = sizeof ptr.host;
 
       p = buffer;
-      if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+      if (addr->ss_family == AF_INET6 && (flags & DNS_WITHBRACKET))
         {
           *p++ = '[';
           buflen -= 2;
         }
-      ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
+      ec = getnameinfo ((const struct sockaddr *)addr,
+                        addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
       if (ec)
         {
           err = map_eai_to_gpg_error (ec);
           goto leave;
         }
-      if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+      if (addr->ss_family == AF_INET6 && (flags & DNS_WITHBRACKET))
         strcat (buffer, "]");
     }
 
@@ -1169,7 +1217,7 @@ resolve_addr_libdns (const struct sockaddr *addr, int addrlen,
 
 /* Resolve an address using the standard system function.  */
 static gpg_error_t
-resolve_addr_standard (const struct sockaddr *addr, int addrlen,
+resolve_addr_standard (const struct sockaddr_storage *addr, int addrlen,
                        unsigned int flags, char **r_name)
 {
   gpg_error_t err;
@@ -1187,20 +1235,22 @@ resolve_addr_standard (const struct sockaddr *addr, int addrlen,
   if ((flags & DNS_NUMERICHOST) || tor_mode)
     ec = EAI_NONAME;
   else
-    ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
+    ec = getnameinfo ((const struct sockaddr *)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))
+      if (addr->ss_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))
+      ec = getnameinfo ((const struct sockaddr *)addr,
+                        addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
+      if (!ec && addr->ss_family == AF_INET6 && (flags & DNS_WITHBRACKET))
         strcat (buffer, "]");
     }
 
@@ -1229,7 +1279,7 @@ resolve_addr_standard (const struct sockaddr *addr, int addrlen,
 
 /* A wrapper around getnameinfo.  */
 gpg_error_t
-resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+resolve_dns_addr (const struct sockaddr_storage *addr, int addrlen,
                   unsigned int flags, char **r_name)
 {
   gpg_error_t err;