diff options
author | Daniel Stenberg <daniel@haxx.se> | 2006-01-19 23:52:03 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2006-01-19 23:52:03 +0000 |
commit | fcfd6d950408d41f0ff7e664205f76146f180da8 (patch) | |
tree | e09443987f8a02aba6c784e0b2fec4f4f03a82d8 /lib | |
parent | c31451cf135f1290647cc6ad3d50e70bfe1b5aac (diff) |
Duane Cathey was one of our friends who reported that curl -P [IP]
(CURLOPT_FTPPORT) didn't work for ipv6-enabed curls if the IP wasn't a
"native" IP while it works fine for ipv6-disabled builds!
In the process of fixing this, I removed the support for LPRT since I can't
think of many reasons to keep doing it and asking on the mailing list didn't
reveal anyone else that could either. The code that sends EPRT and PORT is
now also a lot simpler than before (IMHO).
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ftp.c | 187 | ||||
-rw-r--r-- | lib/url.c | 5 | ||||
-rw-r--r-- | lib/urldata.h | 6 |
3 files changed, 88 insertions, 110 deletions
@@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2006, 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 @@ -763,7 +763,11 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) return result; } -typedef enum { EPRT, LPRT, PORT, DONE } ftpport; +typedef enum { + EPRT, + PORT, + DONE +} ftpport; static CURLcode ftp_state_use_port(struct connectdata *conn, ftpport fcmd) /* start with this */ @@ -773,6 +777,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, struct FTP *ftp = conn->proto.ftp; struct SessionHandle *data=conn->data; curl_socket_t portsock= CURL_SOCKET_BAD; + char myhost[256] = ""; #ifdef ENABLE_IPV6 /****************************************************************** @@ -783,14 +788,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, socklen_t sslen; char hbuf[NI_MAXHOST]; struct sockaddr *sa=(struct sockaddr *)&ss; - unsigned char *ap; - unsigned char *pp; - char portmsgbuf[1024], tmp[1024]; - const char *mode[] = { "EPRT", "LPRT", "PORT", NULL }; + char tmp[1024]; + const char *mode[] = { "EPRT", "PORT", NULL }; int rc; int error; char *host=NULL; struct Curl_dns_entry *h=NULL; + unsigned short port; + + /* Step 1, figure out what address that is requested */ if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) { /* attempt to get the address of the given interface name */ @@ -833,6 +839,9 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, else res = NULL; /* failure! */ + + /* step 2, create a socket for the requested address */ + portsock = CURL_SOCKET_BAD; error = 0; for (ai = res; ai; ai = ai->ai_next) { @@ -847,35 +856,65 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, error = Curl_ourerrno(); continue; } + break; + } + if(!ai) { + failf(data, "socket failure: %s", Curl_strerror(conn, error)); + return CURLE_FTP_PORT_FAILED; + } - if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) { - error = Curl_ourerrno(); + /* step 3, bind to a suitable local address */ + + /* Try binding the given address. */ + if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) { + + /* It failed. Bind the address used for the control connection instead */ + sslen = sizeof(ss); + + if (getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)sa, &sslen) < 0) { + failf(data, "getsockname() failed"); sclose(portsock); - portsock = CURL_SOCKET_BAD; - continue; + return CURLE_FTP_PORT_FAILED; } - if (listen(portsock, 1) < 0) { - error = Curl_ourerrno(); + /* set port number to zero to make bind() pick "any" */ + if(((struct sockaddr *)sa)->sa_family == AF_INET) + ((struct sockaddr_in *)sa)->sin_port=0; + else + ((struct sockaddr_in6 *)sa)->sin6_port =0; + + if(bind(portsock, (struct sockaddr *)sa, sslen) < 0) { + failf(data, "bind failed: %s", Curl_strerror(conn, Curl_ourerrno())); sclose(portsock); - portsock = CURL_SOCKET_BAD; - continue; + return CURLE_FTP_PORT_FAILED; } - - break; } - if (portsock == CURL_SOCKET_BAD) { - failf(data, "socket failure: %s", Curl_strerror(conn,error)); + /* get the name again after the bind() so that we can extract the + port number it uses now */ + sslen = sizeof(ss); + if(getsockname(portsock, (struct sockaddr *)sa, &sslen)<0) { + failf(data, "getsockname() failed: %s", + Curl_strerror(conn, Curl_ourerrno()) ); return CURLE_FTP_PORT_FAILED; } - sslen = sizeof(ss); - if (getsockname(portsock, sa, &sslen) < 0) { - failf(data, "getsockname(): %s", Curl_strerror(conn,Curl_ourerrno())); + /* step 4, listen on the socket */ + + if (listen(portsock, 1) < 0) { + error = Curl_ourerrno(); + sclose(portsock); + failf(data, "socket failure: %s", Curl_strerror(conn, error)); return CURLE_FTP_PORT_FAILED; } + /* step 5, send the proper FTP command */ + + /* get a plain printable version of the numerical address to work with + below */ + Curl_printable_address(ai, myhost, sizeof(myhost)); + #ifdef PF_INET6 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the @@ -884,107 +923,58 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, #endif for (; fcmd != DONE; fcmd++) { - int lprtaf, eprtaf; - int alen=0, plen=0; if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) /* if disabled, goto next */ continue; - if(!conn->bits.ftp_use_lprt && (LPRT == fcmd)) - /* if disabled, goto next */ - continue; - switch (sa->sa_family) { case AF_INET: - ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr; - alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr); - pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port; - plen = sizeof(((struct sockaddr_in *)&ss)->sin_port); - lprtaf = 4; - eprtaf = 1; + port = ntohs(((struct sockaddr_in *)sa)->sin_port); break; case AF_INET6: - ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr; - alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr); - pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port; - plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port); - lprtaf = 6; - eprtaf = 2; + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); break; default: - ap = pp = NULL; - lprtaf = eprtaf = -1; break; } if (EPRT == fcmd) { - if (eprtaf < 0) - continue; - if (getnameinfo((struct sockaddr *)&ss, sslen, - portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp), - NIFLAGS)) - continue; - - /* do not transmit IPv6 scope identifier to the wire */ - if (sa->sa_family == AF_INET6) { - char *q = strchr(portmsgbuf, '%'); - if (q) - *q = '\0'; - } + /* + * Two fine examples from RFC2428; + * + * EPRT |1|132.235.1.2|6275| + * + * EPRT |2|1080::8:800:200C:417A|5282| + */ - result = Curl_nbftpsendf(conn, "%s |%d|%s|%s|", mode[fcmd], eprtaf, - portmsgbuf, tmp); + result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd], + ai->ai_family == AF_INET?1:2, + myhost, port); if(result) return result; break; } - else if ((LPRT == fcmd) || (PORT == fcmd)) { - int i; + else if (PORT == fcmd) { + char *source = myhost; + char *dest = tmp; - if ((LPRT == fcmd) && lprtaf < 0) - continue; - if ((PORT == fcmd) && sa->sa_family != AF_INET) + if ((PORT == fcmd) && ai->ai_family != AF_INET) continue; - portmsgbuf[0] = '\0'; - if (LPRT == fcmd) { - snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen); - if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= - sizeof(portmsgbuf)) { - continue; - } - } - - for (i = 0; i < alen; i++) { - if (portmsgbuf[0]) - snprintf(tmp, sizeof(tmp), ",%u", ap[i]); + /* translate x.x.x.x to x,x,x,x */ + while(source && *source) { + if(*source == '.') + *dest=','; else - snprintf(tmp, sizeof(tmp), "%u", ap[i]); - - if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= - sizeof(portmsgbuf)) { - continue; - } - } - - if (LPRT == fcmd) { - snprintf(tmp, sizeof(tmp), ",%d", plen); - - if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) - continue; + *dest = *source; + dest++; + source++; } + *dest = 0; + snprintf(dest, 20, ",%d,%d", port>>8, port&0xff); - for (i = 0; i < plen; i++) { - snprintf(tmp, sizeof(tmp), ",%u", pp[i]); - - if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= - sizeof(portmsgbuf)) { - continue; - } - } - - result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], portmsgbuf); + result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp); if(result) return result; break; @@ -1007,7 +997,6 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, */ struct sockaddr_in sa; unsigned short porttouse; - char myhost[256] = ""; bool sa_filled_in = FALSE; Curl_addrinfo *addr = NULL; unsigned short ip[4]; @@ -1735,10 +1724,6 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn, infof(data, "disabling EPRT usage\n"); conn->bits.ftp_use_eprt = FALSE; } - else if (LPRT == fcmd) { - infof(data, "disabling LPRT usage\n"); - conn->bits.ftp_use_lprt = FALSE; - } fcmd++; if(fcmd == DONE) { @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2006, 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 @@ -326,7 +326,6 @@ CURLcode Curl_open(struct SessionHandle **curl) data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ - data->set.ftp_use_lprt = TRUE; /* FTP defaults to EPRT operations */ data->set.ftp_filemethod = FTPFILE_MULTICWD; data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ @@ -964,7 +963,6 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_FTP_USE_EPRT: data->set.ftp_use_eprt = va_arg(param, long)?TRUE:FALSE; - data->set.ftp_use_lprt = data->set.ftp_use_eprt; break; case CURLOPT_FTP_USE_EPSV: @@ -2365,7 +2363,6 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; - conn->bits.ftp_use_lprt = data->set.ftp_use_lprt; /* This initing continues below, see the comment "Continue connectdata * initialization here" */ diff --git a/lib/urldata.h b/lib/urldata.h index 94889234a..c3a76b45c 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2006, 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 @@ -427,9 +427,6 @@ struct ConnectBits { bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out EPRT doesn't work we disable it for the forthcoming requests */ - bool ftp_use_lprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out - LPRT doesn't work we disable it for the forthcoming - requests */ bool netrc; /* name+password provided by netrc */ bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response. @@ -1075,7 +1072,6 @@ struct UserDefined { bool expect100header; /* TRUE if we added Expect: 100-continue */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ bool ftp_use_eprt; /* if EPRT is to be attempted or not */ - bool ftp_use_lprt; /* if LPRT is to be attempted or not */ curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ bool no_signal; /* do not use any signal/alarm handler */ |