1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

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 <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-11-12 20:29:47 +01:00
parent 754a03f5a2
commit 392e068e9f
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
4 changed files with 119 additions and 3 deletions

View file

@ -148,6 +148,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 gobal data. */
@ -676,6 +685,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;
}
@ -2372,3 +2396,83 @@ get_dns_cname (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;
}