This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-net.git
The following commit(s) were added to refs/heads/master by this push:
new c9f1179d NET-642 using execPROT on FTPSClients with Proxy Settings
removes Proxy Settings do not reset proxy settings when re-setting the socket
factory create method identical to open _openDataConnection_ for FTPS where
proxy is used and ssl socket is created from ssl context
new f9e0035e Merge pull request #90 from YaniM/master
c9f1179d is described below
commit c9f1179dd95c642aab01ae23b8f1262d73f58b25
Author: Yani Mihaylov <[email protected]>
AuthorDate: Fri Oct 22 10:19:29 2021 +0300
NET-642 using execPROT on FTPSClients with Proxy Settings removes Proxy
Settings
do not reset proxy settings when re-setting the socket factory
create method identical to open _openDataConnection_ for FTPS where proxy
is used and ssl socket is created from ssl context
---
.../java/org/apache/commons/net/SocketClient.java | 4 -
.../java/org/apache/commons/net/ftp/FTPClient.java | 6 +-
.../org/apache/commons/net/ftp/FTPSClient.java | 185 ++++++++++++++++++++-
3 files changed, 187 insertions(+), 8 deletions(-)
diff --git a/src/main/java/org/apache/commons/net/SocketClient.java
b/src/main/java/org/apache/commons/net/SocketClient.java
index f8149c10..f3037d3a 100644
--- a/src/main/java/org/apache/commons/net/SocketClient.java
+++ b/src/main/java/org/apache/commons/net/SocketClient.java
@@ -821,10 +821,6 @@ public abstract class SocketClient
} else {
_socketFactory_ = factory;
}
- // re-setting the socket factory makes the proxy setting useless,
- // so set the field to null so that getProxy() doesn't return a
- // Proxy that we're actually not using.
- connProxy = null;
}
/**
diff --git a/src/main/java/org/apache/commons/net/ftp/FTPClient.java
b/src/main/java/org/apache/commons/net/ftp/FTPClient.java
index f2184fe9..24f0bc0c 100644
--- a/src/main/java/org/apache/commons/net/ftp/FTPClient.java
+++ b/src/main/java/org/apache/commons/net/ftp/FTPClient.java
@@ -1682,7 +1682,7 @@ public class FTPClient extends FTP implements
Configurable {
*
* @return The client port for active mode.
*/
- private int getActivePort()
+ protected int getActivePort()
{
if (activeMinPort > 0 && activeMaxPort >= activeMinPort)
{
@@ -1848,7 +1848,7 @@ public class FTPClient extends FTP implements
Configurable {
* @return __activeExternalHost if non-null, else getLocalAddress()
* @see #setActiveExternalIPAddress(String)
*/
- private InetAddress getHostAddress()
+ protected InetAddress getHostAddress()
{
if (activeExternalHost != null)
{
@@ -1969,7 +1969,7 @@ public class FTPClient extends FTP implements
Configurable {
*
* @return __reportActiveExternalHost if non-null, else getHostAddress();
*/
- private InetAddress getReportHostAddress() {
+ protected InetAddress getReportHostAddress() {
if (reportActiveExternalHost != null) {
return reportActiveExternalHost ;
}
diff --git a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
index 7f0875b8..e1673abd 100644
--- a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
+++ b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
@@ -22,6 +22,10 @@ import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.HostnameVerifier;
@@ -262,7 +266,7 @@ public class FTPSClient extends FTPClient {
*/
@Override
protected Socket _openDataConnection_(final String command, final String
arg) throws IOException {
- final Socket socket = super._openDataConnection_(command, arg);
+ final Socket socket = openDataSecureConnection(command, arg);
_prepareDataSocket_(socket);
if (socket instanceof SSLSocket) {
final SSLSocket sslSocket = (SSLSocket) socket;
@@ -287,6 +291,170 @@ public class FTPSClient extends FTPClient {
return socket;
}
+ /**
+ * Establishes a data connection with the FTP server, returning
+ * a Socket for the connection if successful. If a restart
+ * offset has been set with {@link #setRestartOffset(long)},
+ * a REST command is issued to the server with the offset as
+ * an argument before establishing the data connection. Active
+ * mode connections also cause a local PORT command to be issued.
+ *
+ * @param command The text representation of the FTP command to send.
+ * @param arg The arguments to the FTP command. If this parameter is
+ * set to null, then the command is sent with no argument.
+ * @return A Socket corresponding to the established data connection.
+ * Null is returned if an FTP protocol error is reported at
+ * any point during the establishment and initialization of
+ * the connection.
+ * @throws IOException If an I/O error occurs while either sending a
+ * command to the server or receiving a reply from the server.
+ * @since 3.1
+ */
+ private Socket openDataSecureConnection(String command, String arg) throws
IOException {
+ if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE &&
+ getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE)
{
+ return null;
+ }
+
+ final boolean isInet6Address = getRemoteAddress() instanceof
Inet6Address;
+
+ final Socket socket;
+ Socket sslSocket = null;
+ final int soTimeoutMillis =
DurationUtils.toMillisInt(getDataTimeout());
+ if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE)
+ {
+ // if no activePortRange was set (correctly) -> getActivePort() = 0
+ // -> new ServerSocket(0) -> bind to any free local port
+ try (final ServerSocket server =
_serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress()))
{
+ // Try EPRT only if remote server is over IPv6, if not use
PORT,
+ // because EPRT has no advantage over PORT on IPv4.
+ // It could even have the disadvantage,
+ // that EPRT will make the data connection fail, because
+ // today's intelligent NAT Firewalls are able to
+ // substitute IP addresses in the PORT command,
+ // but might not be able to recognize the EPRT command.
+ if (isInet6Address) {
+ if
(!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(),
server.getLocalPort()))) {
+ return null;
+ }
+ } else if
(!FTPReply.isPositiveCompletion(port(getReportHostAddress(),
server.getLocalPort()))) {
+ return null;
+ }
+
+ if ((getRestartOffset() > 0) && !restart(getRestartOffset())) {
+ return null;
+ }
+
+ if (!FTPReply.isPositivePreliminary(sendCommand(command,
arg))) {
+ return null;
+ }
+
+ // For now, let's just use the data timeout value for waiting
for
+ // the data connection. It may be desirable to let this be a
+ // separately configurable value. In any case, we really want
+ // to allow preventing the accept from blocking indefinitely.
+ if (soTimeoutMillis >= 0) {
+ server.setSoTimeout(soTimeoutMillis);
+ }
+ socket = server.accept();
+
+ // Ensure the timeout is set before any commands are issued on
the new socket
+ if (soTimeoutMillis >= 0) {
+ socket.setSoTimeout(soTimeoutMillis);
+ }
+ if (getReceiveDataSocketBufferSize() > 0) {
+
socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
+ }
+ if (getSendDataSocketBufferSize() > 0) {
+ socket.setSendBufferSize(getSendDataSocketBufferSize());
+ }
+ }
+ }
+ else
+ { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
+
+ // Try EPSV command first on IPv6 - and IPv4 if enabled.
+ // When using IPv4 with NAT it has the advantage
+ // to work with more rare configurations.
+ // E.g. if FTP server has a static PASV address (external network)
+ // and the client is coming from another internal network.
+ // In that case the data connection after PASV command would fail,
+ // while EPSV would make the client succeed by taking just the
port.
+ final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
+ if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE)
+ {
+ _parseExtendedPassiveModeReply(_replyLines.get(0));
+ }
+ else
+ {
+ if (isInet6Address) {
+ return null; // Must use EPSV for IPV6
+ }
+ // If EPSV failed on IPV4, revert to PASV
+ if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
+ return null;
+ }
+ _parsePassiveModeReply(_replyLines.get(0));
+ }
+
+ if (getProxy() != null) {
+ socket = new Socket(getProxy());
+ } else {
+ socket = _socketFactory_.createSocket();
+ }
+
+ if (getReceiveDataSocketBufferSize() > 0) {
+ socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
+ }
+ if (getSendDataSocketBufferSize() > 0) {
+ socket.setSendBufferSize(getSendDataSocketBufferSize());
+ }
+ if (getPassiveLocalIPAddress() != null) {
+ socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(),
0));
+ }
+
+ // For now, let's just use the data timeout value for waiting for
+ // the data connection. It may be desirable to let this be a
+ // separately configurable value. In any case, we really want
+ // to allow preventing the accept from blocking indefinitely.
+ if (soTimeoutMillis >= 0) {
+ socket.setSoTimeout(soTimeoutMillis);
+ }
+
+ socket.connect(new InetSocketAddress(getPassiveHost(),
getPassivePort()), connectTimeout);
+
+ if (getProxy() != null) {
+ sslSocket = context.getSocketFactory().createSocket(socket,
getPassiveHost(), getPassivePort(), true);
+ }
+
+ if ((getRestartOffset() > 0) && !restart(getRestartOffset()))
+ {
+ closeSockets(socket, sslSocket);
+ return null;
+ }
+
+ if (!FTPReply.isPositivePreliminary(sendCommand(command, arg)))
+ {
+ closeSockets(socket, sslSocket);
+ return null;
+ }
+ }
+
+ if (isRemoteVerificationEnabled() && !verifyRemote(socket))
+ {
+ // Grab the host before we close the socket to avoid NET-663
+ final InetAddress socketHost = socket.getInetAddress();
+
+ closeSockets(socket, sslSocket);
+
+ throw new IOException(
+ "Host attempting data connection " +
socketHost.getHostAddress() +
+ " is not same as server " +
getRemoteAddress().getHostAddress());
+ }
+
+ return getProxy() != null ? sslSocket : socket;
+ }
+
/**
* Performs any custom initialization for a newly created SSLSocket
(before the SSL handshake happens). Called
* by {@link #_openDataConnection_(int, String)} immediately after
creating the socket. The default
@@ -910,5 +1078,20 @@ public class FTPSClient extends FTPClient {
}
}
+ /**
+ * Close open sockets.
+ * @param socket main socket for proxy if enabled
+ * @param sslSocket ssl socket
+ * @throws IOException closing sockets is not successful
+ */
+ private void closeSockets(Socket socket, Socket sslSocket) throws
IOException {
+ if (socket != null) {
+ socket.close();
+ }
+ if (sslSocket != null) {
+ sslSocket.close();
+ }
+ }
+
}
/* kate: indent-width 4; replace-tabs on; */