aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2019-11-12 19:29:47 +0000
committerWerner Koch <[email protected]>2019-11-12 19:35:12 +0000
commit12def3a84e0358528347107dc88cfe740a54941f (patch)
tree50fa8ff917a26e4dc5f963e03718133d9e0b0896
parentdirmngr: Tune down err on missing ldapservers file (diff)
downloadgnupg-12def3a84e0358528347107dc88cfe740a54941f.tar.gz
gnupg-12def3a84e0358528347107dc88cfe740a54941f.zip
dirmngr: Use IPv4 or IPv6 interface only if available.
* dirmngr/dns-stuff.c (cached_inet_support): New variable. (dns_stuff_housekeeping): New. (check_inet_support): New. * dirmngr/http.c (connect_server): Use only detected interfaces. * dirmngr/dirmngr.c (housekeeping_thread): Flush the new cache. -- This currently works only for Windows but that is where users really ran into problems. The old workaround was to configure disable-ipv4 or disable-ipv6. Signed-off-by: Werner Koch <[email protected]>
-rw-r--r--dirmngr/dirmngr.c1
-rw-r--r--dirmngr/dns-stuff.c104
-rw-r--r--dirmngr/dns-stuff.h7
-rw-r--r--dirmngr/http.c10
4 files changed, 119 insertions, 3 deletions
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index f7dd029f6..7948e3f24 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -1962,6 +1962,7 @@ housekeeping_thread (void *arg)
memset (&ctrlbuf, 0, sizeof ctrlbuf);
dirmngr_init_default_ctrl (&ctrlbuf);
+ dns_stuff_housekeeping ();
ks_hkp_housekeeping (curtime);
if (network_activity_seen)
{
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index e48aca730..4e381c00d 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -149,6 +149,15 @@ static char tor_nameserver[40+20];
static char tor_socks_user[30];
static char tor_socks_password[20];
+/* To avoid checking the interface too often we cache the result. */
+static struct
+{
+ unsigned int valid:1;
+ unsigned int v4:1;
+ unsigned int v6:1;
+} cached_inet_support;
+
+
#ifdef USE_LIBDNS
/* Libdns global data. */
@@ -686,6 +695,21 @@ reload_dns_stuff (int force)
#else
(void)force;
#endif
+
+ /* We also flush the IPv4/v6 support flag cache. */
+ cached_inet_support.valid = 0;
+}
+
+
+/* Called from time to time from the housekeeping thread. */
+void
+dns_stuff_housekeeping (void)
+{
+ /* With the current housekeeping interval of 10 minutes we flush
+ * that case so that a new or removed interface will be detected not
+ * later than 10 minutes after it changed. This way the user does
+ * not need a reload. */
+ cached_inet_support.valid = 0;
}
@@ -2387,3 +2411,83 @@ get_dns_cname (ctrl_t ctrl, const char *name, char **r_cname)
err ? gpg_strerror (err) : *r_cname);
return err;
}
+
+
+/* Check whether the machine has any usable inet devices up and
+ * running. We put this into dns because on Windows this is
+ * implemented using getaddrinfo and thus easiest done here. */
+void
+check_inet_support (int *r_v4, int *r_v6)
+{
+ if (cached_inet_support.valid)
+ {
+ *r_v4 = cached_inet_support.v4;
+ *r_v6 = cached_inet_support.v6;
+ return;
+ }
+
+ *r_v4 = *r_v6 = 0;
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ gpg_error_t err;
+ int ret;
+ struct addrinfo *aibuf = NULL;
+ struct addrinfo *ai;
+
+ ret = getaddrinfo ("..localmachine", NULL, NULL, &aibuf);
+ if (ret)
+ {
+ err = map_eai_to_gpg_error (ret);
+ log_error ("%s: getaddrinfo failed: %s\n",__func__, gpg_strerror (err));
+ aibuf = NULL;
+ }
+
+ for (ai = aibuf; ai; ai = ai->ai_next)
+ {
+ if (opt_debug)
+ {
+ log_debug ("%s: family: %d\n", __func__, ai->ai_family);
+ if (ai->ai_family == AF_INET6 || ai->ai_family == AF_INET)
+ {
+ char buffer[46];
+ DWORD buflen;
+ buflen = sizeof buffer;
+ if (WSAAddressToString (ai->ai_addr, (DWORD)ai->ai_addrlen,
+ NULL, buffer, &buflen))
+ log_debug ("%s: WSAAddressToString failed: ec=%u\n",
+ __func__, (unsigned int)WSAGetLastError ());
+ else
+ log_debug ("%s: addr: %s\n", __func__, buffer);
+ }
+ }
+ if (ai->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 *v6addr = (struct sockaddr_in6 *)ai->ai_addr;
+ if (!IN6_IS_ADDR_LINKLOCAL (&v6addr->sin6_addr))
+ *r_v6 = 1;
+ }
+ else if (ai->ai_family == AF_INET)
+ {
+ *r_v4 = 1;
+ }
+ }
+
+ if (aibuf)
+ freeaddrinfo (aibuf);
+ }
+#else /*!HAVE_W32_SYSTEM*/
+ {
+ /* For now we assume that we have both protocols. */
+ *r_v4 = *r_v6 = 1;
+ }
+#endif /*!HAVE_W32_SYSTEM*/
+
+ if (opt_verbose)
+ log_info ("detected interfaces:%s%s\n",
+ *r_v4? " IPv4":"", *r_v6? " IPv4":"");
+
+ cached_inet_support.valid = 1;
+ cached_inet_support.v4 = *r_v4;
+ cached_inet_support.v6 = *r_v6;
+}
diff --git a/dirmngr/dns-stuff.h b/dirmngr/dns-stuff.h
index 06a43122a..415eac59c 100644
--- a/dirmngr/dns-stuff.h
+++ b/dirmngr/dns-stuff.h
@@ -134,6 +134,9 @@ void set_dns_nameserver (const char *ipaddr);
/* SIGHUP action handler for this module. */
void reload_dns_stuff (int force);
+/* Housekeeping for this module. */
+void dns_stuff_housekeeping (void);
+
void free_dns_addrinfo (dns_addrinfo_t ai);
/* Function similar to getaddrinfo. */
@@ -170,4 +173,8 @@ gpg_error_t get_dns_srv (ctrl_t ctrl,
struct srventry **list, unsigned int *r_count);
+/* Store true in the variable if such an IP interface is usable. */
+void check_inet_support (int *r_v4, int *r_v6);
+
+
#endif /*GNUPG_DIRMNGR_DNS_STUFF_H*/
diff --git a/dirmngr/http.c b/dirmngr/http.c
index 8e0701fab..c6dc077da 100644
--- a/dirmngr/http.c
+++ b/dirmngr/http.c
@@ -2908,7 +2908,7 @@ connect_server (ctrl_t ctrl, const char *server, unsigned short port,
unsigned int srvcount = 0;
int hostfound = 0;
int anyhostaddr = 0;
- int srv, connected;
+ int srv, connected, v4_valid, v6_valid;
gpg_error_t last_err = 0;
struct srventry *serverlist = NULL;
@@ -2918,6 +2918,8 @@ connect_server (ctrl_t ctrl, const char *server, unsigned short port,
init_sockets ();
#endif /*Windows*/
+ check_inet_support (&v4_valid, &v6_valid);
+
/* Onion addresses require special treatment. */
if (is_onion_address (server))
{
@@ -2996,9 +2998,11 @@ connect_server (ctrl_t ctrl, const char *server, unsigned short port,
for (ai = aibuf; ai && !connected; ai = ai->next)
{
- if (ai->family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4))
+ if (ai->family == AF_INET
+ && ((flags & HTTP_FLAG_IGNORE_IPv4) || !v4_valid))
continue;
- if (ai->family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6))
+ if (ai->family == AF_INET6
+ && ((flags & HTTP_FLAG_IGNORE_IPv6) || !v6_valid))
continue;
if (sock != ASSUAN_INVALID_FD)