gpg: Print the actual used keyserver address.

* dirmngr/ks-engine-hkp.c (ks_hkp_search, ks_hkp_get): Print SOURCE
status lines.
* g10/call-dirmngr.c (ks_status_parm_s): New.
(ks_search_parm_s): Add field stparm.
(ks_status_cb): New.
(ks_search_data_cb): Send source to the data callback.
(gpg_dirmngr_ks_search): Change callback prototope to include the
SPECIAL arg.  Adjust all users.  Use ks_status_cb.
(gpg_dirmngr_ks_get): Add arg r_source and use ks_status_cb.
* g10/keyserver.c (search_line_handler): Adjust callback and print
"data source" disgnostic.
(keyserver_get): Print data source diagnostic.
--

It has often been requested that the actually used IP of a keyservers
is shown in with gpg --recv-key and --search-key.  This is helpful if
the keyserver is actually a pool of keyservers.  This patch does this.
This commit is contained in:
Werner Koch 2014-03-14 16:12:54 +01:00
parent 5d321eb00b
commit a401f768ca
5 changed files with 115 additions and 25 deletions

View File

@ -77,7 +77,7 @@ change_slashes (char *name)
/* /*
* Check whether STRINGS starts with KEYWORD. The keyword is * Check whether STRING starts with KEYWORD. The keyword is
* delimited by end of string, a space or a tab. Returns NULL if not * delimited by end of string, a space or a tab. Returns NULL if not
* found or a pointer into STRING to the next non-space character * found or a pointer into STRING to the next non-space character
* after the KEYWORD (which may be end of string). * after the KEYWORD (which may be end of string).

View File

@ -454,8 +454,7 @@ mark_host_dead (const char *name)
/* Mark a host in the hosttable as dead or - if ALIVE is true - as /* Mark a host in the hosttable as dead or - if ALIVE is true - as
alive. If the host NAME does not exist a warning status message is alive. */
printed. */
gpg_error_t gpg_error_t
ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
{ {
@ -974,6 +973,10 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
if (err) if (err)
goto leave; goto leave;
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
if (err)
goto leave;
/* Peek at the response. */ /* Peek at the response. */
{ {
int c = es_getc (fp); int c = es_getc (fp);
@ -1082,6 +1085,10 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
if (err) if (err)
goto leave; goto leave;
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
if (err)
goto leave;
/* Return the read stream and close the HTTP context. */ /* Return the read stream and close the HTTP context. */
*r_fp = fp; *r_fp = fp;
fp = NULL; fp = NULL;

View File

@ -40,6 +40,13 @@
#include "call-dirmngr.h" #include "call-dirmngr.h"
/* Parameter structure used to gather status info. */
struct ks_status_parm_s
{
char *source;
};
/* Parameter structure used with the KS_SEARCH command. */ /* Parameter structure used with the KS_SEARCH command. */
struct ks_search_parm_s struct ks_search_parm_s
{ {
@ -47,8 +54,9 @@ struct ks_search_parm_s
membuf_t saveddata; /* Buffer to build complete lines. */ membuf_t saveddata; /* Buffer to build complete lines. */
char *helpbuf; /* NULL or malloced buffer. */ char *helpbuf; /* NULL or malloced buffer. */
size_t helpbufsize; /* Allocated size of HELPBUF. */ size_t helpbufsize; /* Allocated size of HELPBUF. */
gpg_error_t (*data_cb)(void*, char*); /* Callback. */ gpg_error_t (*data_cb)(void*, int, char*); /* Callback. */
void *data_cb_value; /* First argument for DATA_CB. */ void *data_cb_value; /* First argument for DATA_CB. */
struct ks_status_parm_s *stparm; /* Link to the status parameter. */
}; };
@ -234,6 +242,29 @@ close_context (ctrl_t ctrl, assuan_context_t ctx)
} }
/* Status callback for ks_get and ks_search. */
static gpg_error_t
ks_status_cb (void *opaque, const char *line)
{
struct ks_status_parm_s *parm = opaque;
gpg_error_t err = 0;
const char *s;
if ((s = has_leading_keyword (line, "SOURCE")))
{
if (!parm->source)
{
parm->source = xtrystrdup (s);
if (!parm->source)
err = gpg_error_from_syserror ();
}
}
return err;
}
/* Data callback for the KS_SEARCH command. */ /* Data callback for the KS_SEARCH command. */
static gpg_error_t static gpg_error_t
@ -248,6 +279,22 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen)
if (parm->lasterr) if (parm->lasterr)
return 0; return 0;
if (parm->stparm->source)
{
err = parm->data_cb (parm->data_cb_value, 1, parm->stparm->source);
if (err)
{
parm->lasterr = err;
return err;
}
/* Clear it so that we won't get back here unless the server
accidentally sends a second source status line. Note that
will not see all accidentally sent source lines because it
depends on whether data lines have been send in between. */
xfree (parm->stparm->source);
parm->stparm->source = NULL;
}
if (!data) if (!data)
return 0; /* Ignore END commands. */ return 0; /* Ignore END commands. */
@ -270,7 +317,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen)
fixedbuf[linelen] = 0; fixedbuf[linelen] = 0;
if (linelen && fixedbuf[linelen-1] == '\r') if (linelen && fixedbuf[linelen-1] == '\r')
fixedbuf[linelen-1] = 0; fixedbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, fixedbuf); err = parm->data_cb (parm->data_cb_value, 0, fixedbuf);
} }
else else
{ {
@ -289,7 +336,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen)
parm->helpbuf[linelen] = 0; parm->helpbuf[linelen] = 0;
if (linelen && parm->helpbuf[linelen-1] == '\r') if (linelen && parm->helpbuf[linelen-1] == '\r')
parm->helpbuf[linelen-1] = 0; parm->helpbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, parm->helpbuf); err = parm->data_cb (parm->data_cb_value, 0, parm->helpbuf);
} }
if (err) if (err)
parm->lasterr = err; parm->lasterr = err;
@ -306,17 +353,18 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen)
/* Run the KS_SEARCH command using the search string SEARCHSTR. All /* Run the KS_SEARCH command using the search string SEARCHSTR. All
data lines are passed to the CB function. That function is called data lines are passed to the CB function. That function is called
with CB_VALUE as its first argument and the decoded data line as with CB_VALUE as its first argument, a 0 as second argument, and
second argument. The callback function may modify the data line the decoded data line as third argument. The callback function may
and it is guaranteed that this data line is a complete line with a modify the data line and it is guaranteed that this data line is a
terminating 0 character but without the linefeed. NULL is passed complete line with a terminating 0 character but without the
to the callback to indicate EOF. */ linefeed. NULL is passed to the callback to indicate EOF. */
gpg_error_t gpg_error_t
gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
gpg_error_t (*cb)(void*, char *), void *cb_value) gpg_error_t (*cb)(void*, int, char *), void *cb_value)
{ {
gpg_error_t err; gpg_error_t err;
assuan_context_t ctx; assuan_context_t ctx;
struct ks_status_parm_s stparm;
struct ks_search_parm_s parm; struct ks_search_parm_s parm;
char line[ASSUAN_LINELENGTH]; char line[ASSUAN_LINELENGTH];
@ -336,18 +384,21 @@ gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
xfree (escsearchstr); xfree (escsearchstr);
} }
memset (&stparm, 0, sizeof stparm);
memset (&parm, 0, sizeof parm); memset (&parm, 0, sizeof parm);
init_membuf (&parm.saveddata, 1024); init_membuf (&parm.saveddata, 1024);
parm.data_cb = cb; parm.data_cb = cb;
parm.data_cb_value = cb_value; parm.data_cb_value = cb_value;
parm.stparm = &stparm;
err = assuan_transact (ctx, line, ks_search_data_cb, &parm, err = assuan_transact (ctx, line, ks_search_data_cb, &parm,
NULL, NULL, NULL, NULL); NULL, NULL, ks_status_cb, &stparm);
if (!err) if (!err)
err = cb (cb_value, NULL); /* Send EOF. */ err = cb (cb_value, 0, NULL); /* Send EOF. */
xfree (get_membuf (&parm.saveddata, NULL)); xfree (get_membuf (&parm.saveddata, NULL));
xfree (parm.helpbuf); xfree (parm.helpbuf);
xfree (stparm.source);
close_context (ctrl, ctx); close_context (ctrl, ctx);
return err; return err;
@ -382,24 +433,32 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen)
don't need to escape the patterns before sending them to the don't need to escape the patterns before sending them to the
server. server.
If R_SOURCE is not NULL the source of the data is stored as a
malloced string there. If a source is not known NULL is stored.
If there are too many patterns the function returns an error. That If there are too many patterns the function returns an error. That
could be fixed by issuing several search commands or by could be fixed by issuing several search commands or by
implementing a different interface. However with long keyids we implementing a different interface. However with long keyids we
are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */ are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */
gpg_error_t gpg_error_t
gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern,
estream_t *r_fp, char **r_source)
{ {
gpg_error_t err; gpg_error_t err;
assuan_context_t ctx; assuan_context_t ctx;
struct ks_status_parm_s stparm;
struct ks_get_parm_s parm; struct ks_get_parm_s parm;
char *line = NULL; char *line = NULL;
size_t linelen; size_t linelen;
membuf_t mb; membuf_t mb;
int idx; int idx;
memset (&stparm, 0, sizeof stparm);
memset (&parm, 0, sizeof parm); memset (&parm, 0, sizeof parm);
*r_fp = NULL; *r_fp = NULL;
if (r_source)
*r_source = NULL;
err = open_context (ctrl, &ctx); err = open_context (ctrl, &ctx);
if (err) if (err)
@ -433,7 +492,7 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp)
goto leave; goto leave;
} }
err = assuan_transact (ctx, line, ks_get_data_cb, &parm, err = assuan_transact (ctx, line, ks_get_data_cb, &parm,
NULL, NULL, NULL, NULL); NULL, NULL, ks_status_cb, &stparm);
if (err) if (err)
goto leave; goto leave;
@ -441,8 +500,15 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp)
*r_fp = parm.memfp; *r_fp = parm.memfp;
parm.memfp = NULL; parm.memfp = NULL;
if (r_source)
{
*r_source = stparm.source;
stparm.source = NULL;
}
leave: leave:
es_fclose (parm.memfp); es_fclose (parm.memfp);
xfree (stparm.source);
xfree (line); xfree (line);
close_context (ctrl, ctx); close_context (ctrl, ctx);
return err; return err;

View File

@ -22,9 +22,10 @@
void gpg_dirmngr_deinit_session_data (ctrl_t ctrl); void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
gpg_error_t (*cb)(void*, char *), gpg_error_t (*cb)(void*, int, char *),
void *cb_value); void *cb_value);
gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[], estream_t *r_fp); gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[],
estream_t *r_fp, char **r_source);
gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl, gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl,
const char *url, estream_t *r_fp); const char *url, estream_t *r_fp);
gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen,

View File

@ -831,17 +831,29 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
/* This is a callback used by call-dirmngr.c to process the result of /* This is a callback used by call-dirmngr.c to process the result of
KS_SEARCH command. LINE is the actual data line received with all KS_SEARCH command. If SPECIAL is 0, LINE is the actual data line
escaping removed and guaranteed to be exactly one line with received with all escaping removed and guaranteed to be exactly one
stripped LF; an EOF is indicated by LINE passed as NULL. LINE may line with stripped LF; an EOF is indicated by LINE passed as NULL.
be modified after return. */ If special is 1, the line conatins the source of the information
(usually an URL). LINE may be modified after return. */
static gpg_error_t static gpg_error_t
search_line_handler (void *opaque, char *line) search_line_handler (void *opaque, int special, char *line)
{ {
struct search_line_handler_parm_s *parm = opaque; struct search_line_handler_parm_s *parm = opaque;
gpg_error_t err = 0; gpg_error_t err = 0;
struct keyrec *keyrec; struct keyrec *keyrec;
if (special == 1)
{
log_info ("data source: %s\n", line);
return 0;
}
else if (special)
{
log_debug ("unknown value %d for special search callback", special);
return 0;
}
if (parm->eof_seen && line) if (parm->eof_seen && line)
{ {
log_debug ("ooops: unexpected data after EOF\n"); log_debug ("ooops: unexpected data after EOF\n");
@ -1478,6 +1490,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
char **pattern; char **pattern;
int idx, npat; int idx, npat;
estream_t datastream; estream_t datastream;
char *source = NULL;
/* Create an array filled with a search pattern for each key. The /* Create an array filled with a search pattern for each key. The
array is delimited by a NULL entry. */ array is delimited by a NULL entry. */
@ -1561,10 +1574,13 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
} }
err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream); err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream, &source);
for (idx=0; idx < npat; idx++) for (idx=0; idx < npat; idx++)
xfree (pattern[idx]); xfree (pattern[idx]);
xfree (pattern); xfree (pattern);
if (opt.verbose)
log_info ("data source: %s\n", source);
if (!err) if (!err)
{ {
void *stats_handle; void *stats_handle;
@ -1590,7 +1606,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
import_release_stats_handle (stats_handle); import_release_stats_handle (stats_handle);
} }
es_fclose (datastream); es_fclose (datastream);
xfree (source);
return err; return err;
} }