Commit 9317eced authored by Till Maas's avatar Till Maas Committed by Daniel Stenberg
Browse files

URL parser: IPv6 zone identifiers are now supported

parent 0bc4938e
Loading
Loading
Loading
Loading
+1 −10
Original line number Original line Diff line number Diff line
@@ -180,16 +180,7 @@ may have been fixed since this was written!
  --cflags suffers from the same effects with CFLAGS/CPPFLAGS.
  --cflags suffers from the same effects with CFLAGS/CPPFLAGS.


30. You need to use -g to the command line tool in order to use RFC2732-style
30. You need to use -g to the command line tool in order to use RFC2732-style
  IPv6 numerical addresses in URLs.
  or RFC6874-style IPv6 numerical addresses in URLs.

29. IPv6 URLs with zone ID is not nicely supported.
  http://www.ietf.org/internet-drafts/draft-fenner-literal-zone-02.txt (expired)
  specifies the use of a plus sign instead of a percent when specifying zone
  IDs in URLs to get around the problem of percent signs being
  special. According to the reporter, Firefox deals with the URL _with_ a
  percent letter (which seems like a blatant URL spec violation).
  libcurl supports zone IDs where the percent sign is URL-escaped (i.e. %25):
  http://curl.haxx.se/bug/view.cgi?id=555


26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in
26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in
  "system context" will make it use wrong(?) user name - at least when compared
  "system context" will make it use wrong(?) user name - at least when compared
+3 −3
Original line number Original line Diff line number Diff line
@@ -956,9 +956,9 @@ IPv6
  When this style is used, the -g option must be given to stop curl from
  When this style is used, the -g option must be given to stop curl from
  interpreting the square brackets as special globbing characters.  Link local
  interpreting the square brackets as special globbing characters.  Link local
  and site local addresses including a scope identifier, such as fe80::1234%1,
  and site local addresses including a scope identifier, such as fe80::1234%1,
  may also be used, but the scope portion must be numeric and the percent
  may also be used, but the scope portion must be numeric or match an existing
  character must be URL escaped. The previous example in an SFTP URL might
  network interface on Linux and the percent character must be URL escaped. The
  look like:
  previous example in an SFTP URL might look like:


    sftp://[fe80::1234%251]/
    sftp://[fe80::1234%251]/


+57 −12
Original line number Original line Diff line number Diff line
@@ -3951,23 +3951,59 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
  if(result != CURLE_OK)
  if(result != CURLE_OK)
    return result;
    return result;


  if(conn->host.name[0] == '[') {
  if(conn->host.name[0] == '[' && !data->state.this_is_a_follow) {
    /* This looks like an IPv6 address literal.  See if there is an address
    /* This looks like an IPv6 address literal.  See if there is an address
       scope.  */
       scope if there is no location header */
    char *percent = strstr (conn->host.name, "%25");
    char *percent = strchr(conn->host.name, '%');
    if(percent) {
    if(percent) {
      unsigned int identifier_offset = 3;
      char *endp;
      char *endp;
      unsigned long scope = strtoul (percent + 3, &endp, 10);
      unsigned long scope;
      if(strncmp("%25", percent, 3) != 0) {
        infof(data,
              "Please URL encode %% as %%25, see RFC 6874.\n");
        identifier_offset = 1;
      }
      scope = strtoul(percent + identifier_offset, &endp, 10);
      if(*endp == ']') {
      if(*endp == ']') {
        /* The address scope was well formed.  Knock it out of the
        /* The address scope was well formed.  Knock it out of the
           hostname. */
           hostname. */
        memmove(percent, endp, strlen(endp)+1);
        memmove(percent, endp, strlen(endp)+1);
        if(!data->state.this_is_a_follow)
          /* Don't honour a scope given in a Location: header */
        conn->scope = (unsigned int)scope;
        conn->scope = (unsigned int)scope;
      }
      }
      else
      else {
        /* Zone identifier is not numeric */
#ifdef HAVE_NET_IF_H
        char ifname[IFNAMSIZ + 2];
        char *square_bracket;
        unsigned int scopeidx = 0;
        strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2);
        /* Ensure nullbyte termination */
        ifname[IFNAMSIZ + 1] = '\0';
        square_bracket = strchr(ifname, ']');
        if(square_bracket) {
          /* Remove ']' */
          *square_bracket = '\0';
          scopeidx = if_nametoindex(ifname);
          if(scopeidx == 0) {
            infof(data, "Invalid network interface: %s; %s\n", ifname,
                  strerror(errno));
          }
        }
        if(scopeidx > 0) {
          /* Remove zone identifier from hostname */
          memmove(percent,
                  percent + identifier_offset + strlen(ifname),
                  identifier_offset + strlen(ifname));
          conn->scope = scopeidx;
        }
        else {
#endif /* HAVE_NET_IF_H */
          infof(data, "Invalid IPv6 address format\n");
          infof(data, "Invalid IPv6 address format\n");
#ifdef HAVE_NET_IF_H
        }
#endif /* HAVE_NET_IF_H */
      }
    }
    }
  }
  }


@@ -4350,12 +4386,21 @@ static CURLcode parse_proxy(struct SessionHandle *data,
  /* start scanning for port number at this point */
  /* start scanning for port number at this point */
  portptr = proxyptr;
  portptr = proxyptr;


  /* detect and extract RFC2732-style IPv6-addresses */
  /* detect and extract RFC6874-style IPv6-addresses */
  if(*proxyptr == '[') {
  if(*proxyptr == '[') {
    char *ptr = ++proxyptr; /* advance beyond the initial bracket */
    char *ptr = ++proxyptr; /* advance beyond the initial bracket */
    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '%') ||
    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
                   (*ptr == '.')))
      ptr++;
      ptr++;
    if(*ptr == '%') {
      /* There might be a zone identifier */
      if(strncmp("%25", ptr, 3))
        infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
      ptr++;
      /* Allow unresered characters as defined in RFC 3986 */
      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
        ptr++;
    }
    if(*ptr == ']')
    if(*ptr == ']')
      /* yeps, it ended nicely with a bracket as well */
      /* yeps, it ended nicely with a bracket as well */
      *ptr++ = 0;
      *ptr++ = 0;