Unverified Commit 8fba2d6a authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

url: convert the zone id from a IPv6 URL to correct scope id

Reported-by: GitYuanQu on github
Fixes #3902
Closes #3914
parent 9406d93e
Loading
Loading
Loading
Loading
+22 −43
Original line number Diff line number Diff line
@@ -2004,59 +2004,38 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
  if(hostname[0] == '[') {
    /* This looks like an IPv6 address literal. See if there is an address
       scope. */
    char *percent = strchr(++hostname, '%');
    char *zoneid;
    size_t hlen;
    uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
    conn->bits.ipv6_ip = TRUE;
    if(percent) {
      unsigned int identifier_offset = 3;

    /* cut off the brackets! */
    hostname++;
    hlen = strlen(hostname);
    hostname[hlen - 1] = 0;
    if(!uc && zoneid) {
      char *endp;
      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 == ']') {
        /* The address scope was well formed.  Knock it out of the
           hostname. */
        memmove(percent, endp, strlen(endp) + 1);
      scope = strtoul(zoneid, &endp, 10);
      if(!*endp && (scope < UINT_MAX)) {
        /* A plain number, use it direcly as a scope id. */
        conn->scope_id = (unsigned int)scope;
      }
#ifdef HAVE_IF_NAMETOINDEX
      else {
        /* Zone identifier is not numeric */
#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX)
        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,
        scopeidx = if_nametoindex(zoneid);
        if(!scopeidx)
          infof(data, "Invalid zoneid id: %s; %s\n", zoneid,
                strerror(errno));
          }
        }
        if(scopeidx > 0) {
          char *p = percent + identifier_offset + strlen(ifname);

          /* Remove zone identifier from hostname */
          memmove(percent, p, strlen(p) + 1);
          conn->scope_id = scopeidx;
        }
        else
#endif /* HAVE_NET_IF_H && IFNAMSIZ */
          infof(data, "Invalid IPv6 address format\n");
          conn->scope_id = scopeidx;

      }
#endif /* HAVE_IF_NAMETOINDEX */
      free(zoneid);
    }
    percent = strchr(hostname, ']');
    if(percent)
      /* terminate IPv6 numerical at end bracket */
      *percent = 0;
  }

  /* make sure the connect struct gets its own copy of the host name */