cURL / Mailing Lists / curl-users / Single Mail

curl-users

Problem with URLs containing numeric IPv6 address and username (+password)

From: Kai Sommerfeld <Kai.Sommerfeld_at_sun.com>
Date: Fri, 10 Dec 2004 11:44:12 +0100

Hi,

  I'm new to this list, so let me first introduce myself. My name is Kai
Sommerfeld. I'm a professional software developer working on the
StarOffice/OpenOffice.org project (www.sun.com/staroffice,
www.openoffice.org) for about 8 years now. As you may know; we're using
libcurl for our FTP client.

  I just implemented IPv6 support for the next OOo release and stumbled
over a problem with libcurl 7.12.2:

  URLs containing a numeric IPv6 address and additionally a username
(and password) do not work (e.g. ftp://user@[::1]). Those URLs always
end up with a name resolution error. Curl_resolv -> Curl_getaddrinfo
fails, because the hostname finally passed to getaddrinfo is a numeric
IPv6 address that is surrounded by square brackets. getaddrinfo
implementation does not not need to accept this as a valid hostname.

  Everything works fine if the URL contains just the address (e.g.
ftp://[::1]).

  The reason is IMHO a bug in lib/url.c -> CreateConnection(). There is
some code that is supposed to remove the square brackets from the
hostname, but unfortunately it seems to be buggy. Code does not take
into account that the conn->host.name string at this point may also
contain username (and password), although the comment above that code
clearly states exactly this.

  Please find attached a patch that should solve this issue. I just
moved the code block that adjusts conn->host.name _after_ the code that
removes username (and password) from conn->host.name.

  Regards,
Kai.

*** url.c.orig Fri Dec 10 11:39:34 2004
--- url.c Fri Dec 10 10:11:12 2004
***************
*** 1428,1434 ****
      result = CURLE_FAILED_INIT; /* correct this */
      break;
    }
!
    return result;
  }
  
--- 1428,1434 ----
      result = CURLE_FAILED_INIT; /* correct this */
      break;
    }
!
    return result;
  }
  
***************
*** 2880,2933 ****
      return CURLE_UNSUPPORTED_PROTOCOL;
    }
  
- /*************************************************************
- * Figure out the remote port number
- *
- * No matter if we use a proxy or not, we have to figure out the remote
- * port number of various reasons.
- *
- * To be able to detect port number flawlessly, we must not confuse them
- * IPv6-specified addresses in the [0::1] style. (RFC2732)
- *
- * The conn->host.name is currently [user:passwd@]host[:port] where host
- * could be a hostname, IPv4 address or IPv6 address.
- *************************************************************/
- if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
- (']' == endbracket)) {
- /* this is a RFC2732-style specified IP-address */
- conn->bits.ipv6_ip = TRUE;
-
- conn->host.name++; /* pass the starting bracket */
- tmp = strchr(conn->host.name, ']');
- *tmp = 0; /* zero terminate */
- tmp++; /* pass the ending bracket */
- if(':' != *tmp)
- tmp = NULL; /* no port number available */
- }
- else
- tmp = strrchr(conn->host.name, ':');
-
- if (tmp) {
- char *rest;
- unsigned long port;
-
- port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
-
- if (rest != (tmp+1) && *rest == '\0') {
- /* The colon really did have only digits after it,
- * so it is either a port number or a mistake */
-
- if (port > 0xffff) { /* Single unix standard says port numbers are
- * 16 bits long */
- failf(data, "Port number too large: %lu", port);
- return CURLE_URL_MALFORMAT;
- }
-
- *tmp = '\0'; /* cut off the name there */
- conn->remote_port = (unsigned short)port;
- }
- }
-
    if(data->change.proxy && *data->change.proxy) {
      /* If this is supposed to use a proxy, we need to figure out the proxy
         host name name, so that we can re-use an existing connection
--- 2880,2885 ----
***************
*** 3119,3124 ****
--- 3071,3124 ----
      return CURLE_OUT_OF_MEMORY;
  
    /*************************************************************
+ * Figure out the remote port number
+ *
+ * No matter if we use a proxy or not, we have to figure out the remote
+ * port number of various reasons.
+ *
+ * To be able to detect port number flawlessly, we must not confuse them
+ * IPv6-specified addresses in the [0::1] style. (RFC2732)
+ *
+ * The conn->host.name is currently host[:port] where host could be a
+ * hostname, IPv4 address or IPv6 address.
+ *************************************************************/
+ if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
+ (']' == endbracket)) {
+ /* this is a RFC2732-style specified IP-address */
+ conn->bits.ipv6_ip = TRUE;
+
+ conn->host.name++; /* pass the starting bracket */
+ tmp = strchr(conn->host.name, ']');
+ *tmp = 0; /* zero terminate */
+ tmp++; /* pass the ending bracket */
+ if(':' != *tmp)
+ tmp = NULL; /* no port number available */
+ }
+ else
+ tmp = strrchr(conn->host.name, ':');
+
+ if (tmp) {
+ char *rest;
+ unsigned long port;
+
+ port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
+
+ if (rest != (tmp+1) && *rest == '\0') {
+ /* The colon really did have only digits after it,
+ * so it is either a port number or a mistake */
+
+ if (port > 0xffff) { /* Single unix standard says port numbers are
+ * 16 bits long */
+ failf(data, "Port number too large: %lu", port);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ *tmp = '\0'; /* cut off the name there */
+ conn->remote_port = (unsigned short)port;
+ }
+ }
+
+ /*************************************************************
     * Check the current list of connections to see if we can
     * re-use an already existing one or if we have to create a
     * new one.
Received on 2004-12-10