b3433bd3690adf7488695c3d43c7d1d9b553c859 galt Tue Jul 20 02:24:50 2021 -0700 Adding needed EPSV extended passive command for IPv6 FTP. fixes #27860 diff --git src/lib/net.c src/lib/net.c index f57e054..f44a066 100644 --- src/lib/net.c +++ src/lib/net.c @@ -848,70 +848,88 @@ if (strlen(startLastLine)>4) if ( isdigit(startLastLine[0]) && isdigit(startLastLine[1]) && isdigit(startLastLine[2]) && startLastLine[3]==' ') break; if (readSize == 0) break; // EOF /* must be some text info we can't use, ignore it till we get status code */ } int reply = atoi(startLastLine); +if (retCode) + *retCode = reply; if ((reply < 200) || (reply > 399)) { + if (!(sameString(cmd,"PASV\r\n") && reply==501)) warn("ftp server error on cmd=[%s] response=[%s]",cmd,rs->string); return FALSE; } if (retReply) *retReply = rs; else dyStringFree(&rs); -if (retCode) - *retCode = reply; return TRUE; } static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply, int *retCode) /* send command to ftp server and check resulting reply code, * warn and return FALSE if not desired reply. If retReply is non-NULL, store reply text there. */ { sendFtpCommandOnly(sd, cmd); return receiveFtpReply(sd, cmd, retReply, retCode); } static int parsePasvPort(char *rs) /* parse PASV reply to get the port and return it */ { char *words[7]; int wordCount; char *rsStart = strchr(rs,'('); char *rsEnd = strchr(rs,')'); int result = 0; rsStart++; *rsEnd=0; wordCount = chopString(rsStart, ",", words, ArraySize(words)); if (wordCount != 6) errAbort("PASV reply does not parse correctly"); result = atoi(words[4])*256+atoi(words[5]); return result; } +static int parseEpsvPort(char *rs) +/* parse EPSV reply to get the port and return it */ +{ +char *words[6]; +int wordCount; +char *rsStart = strchr(rs,'('); +char *rsEnd = strchr(rs,')'); +int result = 0; +rsStart++; +*rsEnd=0; +wordCount = chopString(rsStart, "|", words, ArraySize(words)); +if (wordCount != 1) + errAbort("EPSV reply does not parse correctly"); +result = atoi(words[0]); // multiple separators treated as one. +return result; +} + static long long parseFtpSIZE(char *rs) /* parse reply to SIZE and return it */ { char *words[3]; int wordCount; char *rsStart = rs; long long result = 0; wordCount = chopString(rsStart, " ", words, ArraySize(words)); if (wordCount != 2) errAbort("SIZE reply does not parse correctly"); result = atoll(words[1]); return result; } @@ -1132,57 +1150,70 @@ char proxyUser[4096]; safef(proxyUser, sizeof proxyUser, "%s@%s:%s", npu.user, npu.host, npu.port); sd = openFtpControlSocket(pxy.host, atoi(pxy.port), proxyUser, npu.password); char *logProxy = getenv("log_proxy"); if (sameOk(logProxy,"on")) verbose(1, "%s as %s via proxy %s\n", url, proxyUser, proxyUrl); } else { sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password); } if (sd == -1) return -1; +int retCode = 0; struct dyString *rs = NULL; -if (!sendFtpCommand(sd, "PASV\r\n", &rs, NULL)) +sendFtpCommand(sd, "PASV\r\n", &rs, &retCode); +/* 227 Entering Passive Mode (128,231,210,81,222,250) */ +boolean isIpv6 = FALSE; +if (retCode == 501) + { + + if (!sendFtpCommand(sd, "EPSV\r\n", &rs, NULL)) + /* 229 Entering Extended Passive Mode (|||44022|) */ + { + close(sd); + return -1; + } + isIpv6 = TRUE; + + } +else if (retCode != 227) { close(sd); return -1; } -/* 227 Entering Passive Mode (128,231,210,81,222,250) */ if (npu.byteRangeStart != -1) { safef(cmd,sizeof(cmd),"REST %lld\r\n", (long long) npu.byteRangeStart); if (!sendFtpCommand(sd, cmd, NULL, NULL)) { + dyStringFree(&rs); close(sd); return -1; } } /* RETR for files, LIST for directories ending in / */ safef(cmd,sizeof(cmd),"%s %s\r\n",((npu.file[strlen(npu.file)-1]) == '/') ? "LIST" : "RETR", npu.file); sendFtpCommandOnly(sd, cmd); int sdata = -1; -if (proxyUrl) - sdata = netConnect(pxy.host, parsePasvPort(rs->string)); -else - sdata = netConnect(npu.host, parsePasvPort(rs->string)); +sdata = netConnect(proxyUrl ? pxy.host : npu.host, isIpv6 ? parseEpsvPort(rs->string) : parsePasvPort(rs->string)); dyStringFree(&rs); if (sdata < 0) { close(sd); return -1; } int secondsWaited = 0; while (TRUE) { if (secondsWaited >= 10) { warn("ftp server error on cmd=[%s] timed-out waiting for data or error", cmd); close(sd); close(sdata);