From c2cbe2f87c480c62239dc4c2cbb352acd98cd267 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 9 Jan 2017 10:11:20 +0100 Subject: [PATCH] dirmngr: Do not use a SRV record for HKP if a port was specified. * dirmngr/http.h (parsed_uri_s): Add field EXPLICIT_PORT. * dirmngr/http.c (do_parse_uri): That it. * dirmngr/ks-engine-hkp.c (map_host): Add arg NO_SRV. (make_host_part): Ditto. (ks_hkp_resolve): Set NO_SRV from EXPLICIT_PORT. (ks_hkp_search): Ditto. (ks_hkp_get): Ditto. (ks_hkp_put): Ditto. -- This implements the behaviour of the keyserver helpers from 1.4 and 2.0. Signed-off-by: Werner Koch --- dirmngr/http.c | 2 ++ dirmngr/http.h | 1 + dirmngr/ks-engine-hkp.c | 65 +++++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/dirmngr/http.c b/dirmngr/http.c index 7a028047d..0a47d9f59 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -1169,6 +1169,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part, uri->opaque = 0; uri->v6lit = 0; uri->onion = 0; + uri->explicit_port = 0; /* A quick validity check. */ if (strspn (p, VALID_URI_CHARS) != n) @@ -1241,6 +1242,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part, { *p3++ = '\0'; uri->port = atoi (p3); + uri->explicit_port = 1; } if ((n = remove_escapes (uri->host)) < 0) diff --git a/dirmngr/http.h b/dirmngr/http.h index 2a36fdaa8..32556a4e0 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -53,6 +53,7 @@ struct parsed_uri_s unsigned int opaque:1;/* Unknown scheme; PATH has the rest. */ unsigned int v6lit:1; /* Host was given as a literal v6 address. */ unsigned int onion:1; /* .onion address given. */ + unsigned int explicit_port :1; /* The port was explicitly specified. */ char *auth; /* username/password for basic auth. */ char *host; /* Host (converted to lowercase). */ unsigned short port; /* Port (always set if the host is set). */ diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 283e805f0..9b757a3a2 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -374,19 +374,20 @@ add_host (const char *name, int is_pool, /* Map the host name NAME to the actual to be used host name. This - allows us to manage round robin DNS names. We use our own strategy - to choose one of the hosts. For example we skip those hosts which - failed for some time and we stick to one host for a time - independent of DNS retry times. If FORCE_RESELECT is true a new - host is always selected. The selected host is stored as a malloced - string at R_HOST; on error NULL is stored. If we know the port - used by the selected host, a string representation is written to - R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not - NULL it will receive flags which are to be passed to http_open. If - R_POOLNAME is not NULL a malloced name of the pool is stored or - NULL if it is not a pool. */ + * allows us to manage round robin DNS names. We use our own strategy + * to choose one of the hosts. For example we skip those hosts which + * failed for some time and we stick to one host for a time + * independent of DNS retry times. If FORCE_RESELECT is true a new + * host is always selected. If NO_SRV is set no service record lookup + * will be done. The selected host is stored as a malloced string at + * R_HOST; on error NULL is stored. If we know the port used by the + * selected host from a service record, a string representation is + * written to R_PORTSTR, otherwise it is left untouched. If + * R_HTTPFLAGS is not NULL it will receive flags which are to be + * passed to http_open. If R_POOLNAME is not NULL a malloced name of + * the pool is stored or NULL if it is not a pool. */ static gpg_error_t -map_host (ctrl_t ctrl, const char *name, int force_reselect, +map_host (ctrl_t ctrl, const char *name, int force_reselect, int no_srv, char **r_host, char *r_portstr, unsigned int *r_httpflags, char **r_poolname) { @@ -444,7 +445,7 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect, } hi = hosttable[idx]; - if (!is_ip_address (name)) + if (!no_srv && !is_ip_address (name)) { /* Check for SRV records. */ err = get_dns_srv (name, "hkp", NULL, &srvs, &srvscount); @@ -848,13 +849,13 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri) /* Build the remote part of the URL from SCHEME, HOST and an optional - PORT. Returns an allocated string at R_HOSTPORT or NULL on failure - If R_POOLNAME is not NULL it receives a malloced string with the - poolname. */ + * PORT. If NO_SRV is set no SRV record lookup will be done. Returns + * an allocated string at R_HOSTPORT or NULL on failure If R_POOLNAME + * is not NULL it receives a malloced string with the poolname. */ static gpg_error_t make_host_part (ctrl_t ctrl, const char *scheme, const char *host, unsigned short port, - int force_reselect, + int force_reselect, int no_srv, char **r_hostport, unsigned int *r_httpflags, char **r_poolname) { gpg_error_t err; @@ -864,11 +865,18 @@ make_host_part (ctrl_t ctrl, *r_hostport = NULL; portstr[0] = 0; - err = map_host (ctrl, host, force_reselect, + err = map_host (ctrl, host, force_reselect, no_srv, &hostname, portstr, r_httpflags, r_poolname); if (err) return err; + /* If map_host did not return a port (from a SRV record) but a port + * has been specified (implicitly or explicitly) then use that port. + * Only in the case that a port was not specified (which might be a + * bug in https.c) we will later make sure that it has been set. */ + if (!*portstr && port) + snprintf (portstr, sizeof portstr, "%hu", port); + /* Map scheme and port. */ if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https")) { @@ -882,12 +890,6 @@ make_host_part (ctrl_t ctrl, if (! *portstr) strcpy (portstr, "11371"); } - if (port) - snprintf (portstr, sizeof portstr, "%hu", port); - else - { - /*fixme_do_srv_lookup ()*/ - } *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL); xfree (hostname); @@ -913,7 +915,11 @@ ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri) gpg_error_t err; char *hostport = NULL; - err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1, + /* NB: With an explicitly given port we do not want to consult a + * service record because that might be in conflict with the port + * from such a service record. */ + err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + 1, uri->explicit_port, &hostport, NULL, NULL); if (err) { @@ -1219,7 +1225,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, xfree (hostport); hostport = NULL; xfree (httphost); httphost = NULL; - err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect, + err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect, uri->explicit_port, &hostport, &httpflags, &httphost); if (err) goto leave; @@ -1360,7 +1367,8 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) /* Build the request string. */ xfree (hostport); hostport = NULL; xfree (httphost); httphost = NULL; - err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect, + err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect, uri->explicit_port, &hostport, &httpflags, &httphost); if (err) goto leave; @@ -1472,7 +1480,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen) again: xfree (hostport); hostport = NULL; xfree (httphost); httphost = NULL; - err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect, + err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, + reselect, uri->explicit_port, &hostport, &httpflags, &httphost); if (err) goto leave;