aboutsummaryrefslogtreecommitdiff
path: root/lib/ftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ftp.c')
-rw-r--r--lib/ftp.c187
1 files changed, 86 insertions, 101 deletions
diff --git a/lib/ftp.c b/lib/ftp.c
index 2361c89ec..3cdcc32ef 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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) {