diff options
-rw-r--r-- | CHANGES | 14 | ||||
-rw-r--r-- | lib/ftp.c | 187 | ||||
-rw-r--r-- | lib/url.c | 5 | ||||
-rw-r--r-- | lib/urldata.h | 6 | ||||
-rw-r--r-- | tests/data/test212 | 5 |
5 files changed, 101 insertions, 116 deletions
@@ -6,9 +6,19 @@ Changelog +Daniel (20 January 2006) +- 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). + Daniel (19 January 2006) -- Jon Turner pointed out that doing -P [hostname] with curl (built ipv4-only) - didn't work. +- Jon Turner pointed out that doing -P [hostname] (CURLOPT_FTPPORT) with curl + (built ipv4-only) didn't work. Daniel (18 January 2006) - As reported in bug #1408742 (http://curl.haxx.se/bug/view.cgi?id=1408742), @@ -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 */ diff --git a/tests/data/test212 b/tests/data/test212 index 8633ae5d4..3fac26bde 100644 --- a/tests/data/test212 +++ b/tests/data/test212 @@ -15,14 +15,13 @@ ipv6 ftp </server> <name> -Get two FTP files with no remote EPRT or LPRT support +Get two FTP files with no remote EPRT support </name> <command> ftp://%HOSTIP:%FTPPORT/a/path/212 ftp://%HOSTIP:%FTPPORT/a/path/212 -P - </command> <file name="log/ftpserver.cmd"> REPLY EPRT 500 no such command -REPLY LPRT 500 no such command </file> <stdout> data blobb @@ -34,7 +33,6 @@ data blobb <verify> <strippart> s/^(EPRT \|1\|127.0.0.1).*/$1/ -s/^(LPRT 4,4,127,0,0,1,).*/$1/ s/^(PORT 127,0,0,1,).*/$1/ </strippart> <protocol> @@ -44,7 +42,6 @@ PWD CWD a
CWD path
EPRT |1|127.0.0.1 -LPRT 4,4,127,0,0,1, PORT 127,0,0,1, TYPE I
SIZE 212
|