Commit 9a452ba3 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

FTP: fix IPv6 host using link-local address

... and make sure we can connect the data connection to a host name that
is longer than 48 bytes.

Also simplifies the code somewhat by re-using the original host name
more, as it is likely still in the DNS cache.

Original-Patch-by: Vojtěch Král
Bug: http://curl.haxx.se/bug/view.cgi?id=1468
parent 659d252b
Loading
Loading
Loading
Loading
+23 −33
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
@@ -294,10 +294,10 @@ static void freedirs(struct ftp_conn *ftpc)
    ftpc->dirs = NULL;
    ftpc->dirdepth = 0;
  }
  if(ftpc->file) {
    free(ftpc->file);
    ftpc->file = NULL;
  }
  Curl_safefree(ftpc->file);

  /* no longer of any use */
  Curl_safefree(ftpc->newhost);
}

/* Returns non-zero if the given string contains CR (\r) or LF (\n),
@@ -1917,6 +1917,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
  unsigned short connectport; /* the local port connect() should use! */
  char *str=&data->state.buffer[4];  /* start on the first letter */

  /* if we come here again, make sure the former name is cleared */
  Curl_safefree(ftpc->newhost);

  if((ftpc->count1 == 0) &&
     (ftpcode == 229)) {
    /* positive EPSV response */
@@ -1949,18 +1952,10 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
        if(ptr) {
          ftpc->newport = (unsigned short)(num & 0xffff);

          if(conn->bits.tunnel_proxy ||
             conn->proxytype == CURLPROXY_SOCKS5 ||
             conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
             conn->proxytype == CURLPROXY_SOCKS4 ||
             conn->proxytype == CURLPROXY_SOCKS4A)
            /* proxy tunnel -> use other host info because ip_addr_str is the
               proxy address not the ftp host */
            snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
                     conn->host.name);
          else
            /* use the same IP we are already connected to */
            snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
          /* use the original host name again */
          ftpc->newhost = strdup(conn->host.name);
          if(!ftpc->newhost)
            return CURLE_OUT_OF_MEMORY;
        }
      }
      else
@@ -2001,26 +1996,21 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,

    /* we got OK from server */
    if(data->set.ftp_skip_ip) {
      /* told to ignore the remotely given IP but instead use the one we used
      /* told to ignore the remotely given IP but instead use the host we used
         for the control connection */
      infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
      infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
            ip[0], ip[1], ip[2], ip[3],
            conn->ip_addr_str);
      if(conn->bits.tunnel_proxy ||
         conn->proxytype == CURLPROXY_SOCKS5 ||
         conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
         conn->proxytype == CURLPROXY_SOCKS4 ||
         conn->proxytype == CURLPROXY_SOCKS4A)
        /* proxy tunnel -> use other host info because ip_addr_str is the
           proxy address not the ftp host */
        snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
      else
        snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
                 conn->ip_addr_str);
            conn->host.name);

      /* use the original host name again */
      ftpc->newhost = strdup(conn->host.name);
    }
    else
      snprintf(ftpc->newhost, sizeof(ftpc->newhost),
               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
      ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

    if(!ftpc->newhost)
      return CURLE_OUT_OF_MEMORY;

    ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
  }
  else if(ftpc->count1 == 0) {
+5 −6
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
@@ -147,10 +147,9 @@ struct ftp_conn {
  curl_off_t known_filesize; /* file size is different from -1, if wildcard
                                LIST parsing was done and wc_statemach set
                                it */
  /* newhost must be able to hold a full IP-style address in ASCII, which
     in the IPv6 case means 5*8-1 = 39 letters */
#define NEWHOST_BUFSIZE 48
  char newhost[NEWHOST_BUFSIZE]; /* this is the pair to connect the DATA... */
  /* newhost is the (allocated) IP addr or host name to connect the data
     connection to */
  char *newhost;          /* this is the pair to connect the DATA... */
  unsigned short newport; /* connection to */

};