mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
dirmngr: Keep track of domains used for WKD queries
* dirmngr/domaininfo.c: New file. * dirmngr/Makefile.am (dirmngr_SOURCES): Add file. * dirmngr/server.c (cmd_wkd_get): Check whether the domain is already known and tell domaininfo about the results. -- This adds a registry for domain information to eventually avoid useless queries for domains which do not support WKD. The missing part is a background task to check whether a queried domain supports WKD at all and to expire old entries. Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 65038e6852185c20413d8f6602218ee636413b77)
This commit is contained in:
parent
3e72143023
commit
6c1dcd79cf
@ -16,6 +16,8 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
@ -57,6 +59,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
|
||||
|
||||
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
||||
certcache.c certcache.h \
|
||||
domaininfo.c \
|
||||
loadswdb.c \
|
||||
cdb.h cdblib.c misc.c dirmngr-err.h \
|
||||
ocsp.c ocsp.h validate.c validate.h \
|
||||
|
@ -17,6 +17,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@ -1871,6 +1873,7 @@ handle_signal (int signo)
|
||||
|
||||
case SIGUSR1:
|
||||
cert_cache_print_stats ();
|
||||
domaininfo_print_stats ();
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
|
@ -17,6 +17,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
#ifndef DIRMNGR_H
|
||||
@ -248,4 +250,14 @@ gpg_error_t gnupg_http_tls_verify_cb (void *opaque,
|
||||
gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force);
|
||||
|
||||
|
||||
/*-- domaininfo.c --*/
|
||||
void domaininfo_print_stats (void);
|
||||
int domaininfo_is_wkd_not_supported (const char *domain);
|
||||
void domaininfo_set_no_name (const char *domain);
|
||||
void domaininfo_set_wkd_supported (const char *domain);
|
||||
void domaininfo_set_wkd_not_supported (const char *domain);
|
||||
void domaininfo_set_wkd_not_found (const char *domain);
|
||||
|
||||
|
||||
|
||||
#endif /*DIRMNGR_H*/
|
||||
|
244
dirmngr/domaininfo.c
Normal file
244
dirmngr/domaininfo.c
Normal file
@ -0,0 +1,244 @@
|
||||
/* domaininfo.c - Gather statistics about accessed domains
|
||||
* Copyright (C) 2017 Werner Koch
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dirmngr.h"
|
||||
|
||||
|
||||
#define NO_OF_DOMAINBUCKETS 103
|
||||
|
||||
/* Object to keep track of a domain name. */
|
||||
struct domaininfo_s
|
||||
{
|
||||
struct domaininfo_s *next;
|
||||
unsigned int no_name:1; /* Domain name not found. */
|
||||
unsigned int wkd_not_found:1; /* A WKD query failed. */
|
||||
unsigned int wkd_supported:1; /* One WKD entry was found. */
|
||||
unsigned int wkd_not_supported:1; /* Definitely does not support WKD. */
|
||||
char name[1];
|
||||
};
|
||||
typedef struct domaininfo_s *domaininfo_t;
|
||||
|
||||
/* And the hashed array. */
|
||||
static domaininfo_t domainbuckets[NO_OF_DOMAINBUCKETS];
|
||||
|
||||
|
||||
/* The hash function we use. Must not call a system function. */
|
||||
static inline u32
|
||||
hash_domain (const char *domain)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char*)domain;
|
||||
u32 hashval = 0;
|
||||
u32 carry;
|
||||
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s == '.')
|
||||
continue;
|
||||
hashval = (hashval << 4) + *s;
|
||||
if ((carry = (hashval & 0xf0000000)))
|
||||
{
|
||||
hashval ^= (carry >> 24);
|
||||
hashval ^= carry;
|
||||
}
|
||||
}
|
||||
|
||||
return hashval % NO_OF_DOMAINBUCKETS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
domaininfo_print_stats (void)
|
||||
{
|
||||
int bidx;
|
||||
domaininfo_t di;
|
||||
int count, no_name, wkd_not_found, wkd_supported, wkd_not_supported;
|
||||
|
||||
for (bidx = 0; bidx < NO_OF_DOMAINBUCKETS; bidx++)
|
||||
{
|
||||
count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0;
|
||||
for (di = domainbuckets[bidx]; di; di = di->next)
|
||||
{
|
||||
count++;
|
||||
if (di->no_name)
|
||||
no_name++;
|
||||
if (di->wkd_not_found)
|
||||
wkd_not_found++;
|
||||
if (di->wkd_supported)
|
||||
wkd_supported++;
|
||||
if (di->wkd_not_supported)
|
||||
wkd_not_supported++;
|
||||
}
|
||||
if (count)
|
||||
log_info ("domaininfo: chain %3d length=%d nn=%d nf=%d s=%d ns=%d\n",
|
||||
bidx, count, no_name,
|
||||
wkd_not_found, wkd_supported, wkd_not_supported);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return true if DOMAIN definitely does not support WKD. Noet that
|
||||
* DOMAIN is expected to be lowercase. */
|
||||
int
|
||||
domaininfo_is_wkd_not_supported (const char *domain)
|
||||
{
|
||||
domaininfo_t di;
|
||||
|
||||
for (di = domainbuckets[hash_domain (domain)]; di; di = di->next)
|
||||
if (!strcmp (di->name, domain))
|
||||
return !!di->wkd_not_supported;
|
||||
|
||||
return 0; /* We don't know. */
|
||||
}
|
||||
|
||||
|
||||
/* Core update function. DOMAIN is expected to be lowercase.
|
||||
* CALLBACK is called to update the existing or the newly inserted
|
||||
* item. */
|
||||
static void
|
||||
insert_or_update (const char *domain,
|
||||
void (*callback)(domaininfo_t di, int insert_mode))
|
||||
{
|
||||
domaininfo_t di;
|
||||
domaininfo_t di_new;
|
||||
u32 hash;
|
||||
|
||||
hash = hash_domain (domain);
|
||||
for (di = domainbuckets[hash]; di; di = di->next)
|
||||
if (!strcmp (di->name, domain))
|
||||
{
|
||||
callback (di, 0); /* Update */
|
||||
return;
|
||||
}
|
||||
|
||||
di_new = xtrycalloc (1, sizeof *di + strlen (domain));
|
||||
if (!di_new)
|
||||
return; /* Out of core - we ignore this. */
|
||||
|
||||
/* Need to do another lookup because the malloc is a system call and
|
||||
* thus the hash array may have been changed by another thread. */
|
||||
for (di = domainbuckets[hash]; di; di = di->next)
|
||||
if (!strcmp (di->name, domain))
|
||||
{
|
||||
callback (di, 0); /* Update */
|
||||
xfree (di_new);
|
||||
return;
|
||||
}
|
||||
|
||||
callback (di_new, 1); /* Insert */
|
||||
di = di_new;
|
||||
di->next = domainbuckets[hash];
|
||||
domainbuckets[hash] = di;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for domaininfo_set_no_name. */
|
||||
static void
|
||||
set_no_name_cb (domaininfo_t di, int insert_mode)
|
||||
{
|
||||
(void)insert_mode;
|
||||
|
||||
di->no_name = 1;
|
||||
/* Obviously the domain is in this case also not supported. */
|
||||
di->wkd_not_supported = 1;
|
||||
|
||||
/* The next should already be 0 but we clear it anyway in the case
|
||||
* of a temporary DNS failure. */
|
||||
di->wkd_supported = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Mark DOMAIN as not existent. */
|
||||
void
|
||||
domaininfo_set_no_name (const char *domain)
|
||||
{
|
||||
insert_or_update (domain, set_no_name_cb);
|
||||
}
|
||||
|
||||
|
||||
/* Helper for domaininfo_set_wkd_supported. */
|
||||
static void
|
||||
set_wkd_supported_cb (domaininfo_t di, int insert_mode)
|
||||
{
|
||||
(void)insert_mode;
|
||||
|
||||
di->wkd_supported = 1;
|
||||
/* The next will already be set unless the domain enabled WKD in the
|
||||
* meantime. Thus we need to clear it. */
|
||||
di->wkd_not_supported = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Mark DOMAIN as supporting WKD. */
|
||||
void
|
||||
domaininfo_set_wkd_supported (const char *domain)
|
||||
{
|
||||
insert_or_update (domain, set_wkd_supported_cb);
|
||||
}
|
||||
|
||||
|
||||
/* Helper for domaininfo_set_wkd_not_supported. */
|
||||
static void
|
||||
set_wkd_not_supported_cb (domaininfo_t di, int insert_mode)
|
||||
{
|
||||
(void)insert_mode;
|
||||
|
||||
di->wkd_not_supported = 1;
|
||||
di->wkd_supported = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Mark DOMAIN as not supporting WKD queries (e.g. no policy file). */
|
||||
void
|
||||
domaininfo_set_wkd_not_supported (const char *domain)
|
||||
{
|
||||
insert_or_update (domain, set_wkd_not_supported_cb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Helper for domaininfo_set_wkd_not_found. */
|
||||
static void
|
||||
set_wkd_not_found_cb (domaininfo_t di, int insert_mode)
|
||||
{
|
||||
/* Set the not found flag but there is no need to do this if we
|
||||
* already know that the domain either does not support WKD or we
|
||||
* know that it supports WKD. */
|
||||
if (insert_mode)
|
||||
di->wkd_not_found = 1;
|
||||
else if (!di->wkd_not_supported && !di->wkd_supported)
|
||||
di->wkd_not_found = 1;
|
||||
|
||||
/* Better clear this flag in case we had a DNS failure in the
|
||||
* past. */
|
||||
di->no_name = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Update a counter for DOMAIN to keep track of failed WKD queries. */
|
||||
void
|
||||
domaininfo_set_wkd_not_found (const char *domain)
|
||||
{
|
||||
insert_or_update (domain, set_wkd_not_found_cb);
|
||||
}
|
@ -18,6 +18,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@ -833,11 +835,13 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
|
||||
char *mbox = NULL;
|
||||
char *domainbuf = NULL;
|
||||
char *domain; /* Points to mbox or domainbuf. */
|
||||
char *domain_orig;/* Points to mbox. */
|
||||
char sha1buf[20];
|
||||
char *uri = NULL;
|
||||
char *encodedhash = NULL;
|
||||
int opt_submission_addr;
|
||||
int opt_policy_flags;
|
||||
int is_wkd_query; /* True if this is a real WKD query. */
|
||||
int no_log = 0;
|
||||
char portstr[20] = { 0 };
|
||||
|
||||
@ -846,6 +850,7 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
|
||||
if (has_option (line, "--quick"))
|
||||
ctrl->timeout = opt.connect_quick_timeout;
|
||||
line = skip_options (line);
|
||||
is_wkd_query = !(opt_policy_flags || opt_submission_addr);
|
||||
|
||||
mbox = mailbox_from_userid (line);
|
||||
if (!mbox || !(domain = strchr (mbox, '@')))
|
||||
@ -854,6 +859,18 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
|
||||
goto leave;
|
||||
}
|
||||
*domain++ = 0;
|
||||
domain_orig = domain;
|
||||
|
||||
/* First check whether we already know that the domain does not
|
||||
* support WKD. */
|
||||
if (is_wkd_query)
|
||||
{
|
||||
if (domaininfo_is_wkd_not_supported (domain_orig))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for SRV records. */
|
||||
if (1)
|
||||
@ -962,6 +979,29 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
|
||||
err = ks_action_fetch (ctrl, uri, outfp);
|
||||
es_fclose (outfp);
|
||||
ctrl->server_local->inhibit_data_logging = 0;
|
||||
/* Register the result under the domain name of MBOX. */
|
||||
switch (gpg_err_code (err))
|
||||
{
|
||||
case 0:
|
||||
domaininfo_set_wkd_supported (domain_orig);
|
||||
break;
|
||||
|
||||
case GPG_ERR_NO_NAME:
|
||||
/* There is no such domain. */
|
||||
domaininfo_set_no_name (domain_orig);
|
||||
break;
|
||||
|
||||
case GPG_ERR_NO_DATA:
|
||||
if (is_wkd_query) /* Mark that - we will latter do a check. */
|
||||
domaininfo_set_wkd_not_found (domain_orig);
|
||||
else if (opt_policy_flags) /* No policy file - no support. */
|
||||
domaininfo_set_wkd_not_supported (domain_orig);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Don't register other errors. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user