dirmngr: Do not use a SRV record for HKP if a port was specified.
authorWerner Koch <wk@gnupg.org>
Mon, 9 Jan 2017 09:11:20 +0000 (10:11 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 9 Jan 2017 09:28:25 +0000 (10:28 +0100)
* 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 <wk@gnupg.org>
dirmngr/http.c
dirmngr/http.h
dirmngr/ks-engine-hkp.c

index 7a02804..0a47d9f 100644 (file)
@@ -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)
index 2a36fda..32556a4 100644 (file)
@@ -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). */
index 283e805..9b757a3 100644 (file)
@@ -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;