}
addr = *AI;
-
addr.FreeAddrInfo(AI);
- /** Otherwise, Open data channel with the same local address as control channel (on a new random port!) */
- addr.SetPort(0);
- int fd = comm_open(SOCK_STREAM,
- IPPROTO_TCP,
- addr,
- COMM_NONBLOCKING,
- ftpState->entry->url());
-
- debugs(9, 3, HERE << "Unconnected data socket created on FD " << fd << " to " << addr);
-
- if (fd < 0) {
- ftpFail(ftpState);
- return;
- }
-
- ftpState->data.opened(fd, ftpState->dataCloser());
-
/** \par
* Send EPSV (ALL,2,1) or PASV on the control channel.
*
* - EPSV ALL is used if enabled.
- * - EPSV 2 is used if ALL is disabled and IPv6 is available.
- * - EPSV 1 is used if EPSV 2 (IPv6) fails or is not available.
+ * - EPSV 2 is used if ALL is disabled and IPv6 is available and ctrl channel is IPv6.
+ * - EPSV 1 is used if EPSV 2 (IPv6) fails or is not available or ctrl channel is IPv4.
* - PASV is used if EPSV 1 fails.
*/
switch (ftpState->state) {
- case SENT_EPSV_1: /* EPSV options exhausted. Try PASV now. */
- snprintf(cbuf, 1024, "PASV\r\n");
- ftpState->state = SENT_PASV;
- break;
+ case SENT_EPSV_ALL: /* EPSV ALL resulted in a bad response. Try ther EPSV methods. */
+ ftpState->flags.epsv_all_sent = true;
+ if (addr.IsIPv6()) {
+ snprintf(cbuf, 1024, "EPSV 2\r\n");
+ ftpState->state = SENT_EPSV_2;
+ break;
+ }
+ // else fall through to skip EPSV 2
case SENT_EPSV_2: /* EPSV IPv6 failed. Try EPSV IPv4 */
- snprintf(cbuf, 1024, "EPSV 1\r\n");
- ftpState->state = SENT_EPSV_1;
- break;
+ if (addr.IsIPv4()) {
+ snprintf(cbuf, 1024, "EPSV 1\r\n");
+ ftpState->state = SENT_EPSV_1;
+ }
+ else if (ftpState->flags.epsv_all_sent) {
+ debugs(9, DBG_IMPORTANT, "FTP does not allow PASV method after 'EPSV ALL' has been sent.");
+ ftpFail(ftpState);
+ return;
+ }
+ // else fall through to skip EPSV 1
- case SENT_EPSV_ALL: /* EPSV ALL resulted in a bad response. Try ther EPSV methods. */
- ftpState->flags.epsv_all_sent = true;
- snprintf(cbuf, 1024, "EPSV 2\r\n");
- ftpState->state = SENT_EPSV_2;
+ case SENT_EPSV_1: /* EPSV options exhausted. Try PASV now. */
+ snprintf(cbuf, 1024, "PASV\r\n");
+ ftpState->state = SENT_PASV;
break;
default:
break;
}
+ /** Otherwise, Open data channel with the same local address as control channel (on a new random port!) */
+ addr.SetPort(0);
+ int fd = comm_open(SOCK_STREAM,
+ IPPROTO_TCP,
+ addr,
+ COMM_NONBLOCKING,
+ ftpState->entry->url());
+
+ debugs(9, 3, HERE << "Unconnected data socket created on FD " << fd << " to " << addr);
+
+ if (fd < 0) {
+ ftpFail(ftpState);
+ return;
+ }
+
+ ftpState->data.opened(fd, ftpState->dataCloser());
ftpState->writeCommand(cbuf);
/*