From 6f9ecf69e4bcb685e512a68386711e080c118a5b Mon Sep 17 00:00:00 2001 From: David Solin Date: Sun, 14 Aug 2016 14:06:40 -0500 Subject: [PATCH 1/4] Reordered connect methods so that the similar ones are grouped together. Also, eliminated all use of InetAddress.getByName, because we'll want to be able to connect even when the target host is only visible to DNS from the Proxy, or the SocketFactory. --- .../java/net/schmizz/sshj/SocketClient.java | 119 ++++++++++-------- 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/SocketClient.java b/src/main/java/net/schmizz/sshj/SocketClient.java index 7d7dd9d1..7a843380 100644 --- a/src/main/java/net/schmizz/sshj/SocketClient.java +++ b/src/main/java/net/schmizz/sshj/SocketClient.java @@ -48,12 +48,50 @@ public abstract class SocketClient { this.defaultPort = defaultPort; } - public void connect(InetAddress host, int port) throws IOException { - socket = socketFactory.createSocket(); - socket.connect(new InetSocketAddress(host, port), connectTimeout); + /** + * Connect to a host via a proxy. + * @param hostname The host name to connect to. + * @param proxy The proxy to connect via. + * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} + * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. + */ + @Deprecated + public void connect(String hostname, Proxy proxy) throws IOException { + connect(hostname, defaultPort, proxy); + } + + /** + * Connect to a host via a proxy. + * @param hostname The host name to connect to. + * @param port The port to connect to. + * @param proxy The proxy to connect via. + * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} + * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. + */ + @Deprecated + public void connect(String hostname, int port, Proxy proxy) throws IOException { + this.hostname = hostname; + if (JavaVersion.isJava7OrEarlier() && proxy.type() == Proxy.Type.HTTP) { + // Java7 and earlier have no support for HTTP Connect proxies, return our custom socket. + socket = new Jdk7HttpProxySocket(proxy); + } else { + socket = new Socket(proxy); + } + socket.connect(new InetSocketAddress(hostname, port), connectTimeout); onConnect(); } + /** + * Connect to a host via a proxy. + * @param host The host address to connect to. + * @param proxy The proxy to connect via. + * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} + * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. + */ + @Deprecated + public void connect(InetAddress host, Proxy proxy) throws IOException { + connect(host, defaultPort, proxy); + } /** * Connect to a host via a proxy. @@ -75,23 +113,33 @@ public abstract class SocketClient { onConnect(); } - public void connect(String hostname, int port) throws IOException { - this.hostname = hostname; - connect(InetAddress.getByName(hostname), port); + public void connect(String hostname) throws IOException { + connect(hostname, defaultPort); } - /** - * Connect to a host via a proxy. - * @param hostname The host name to connect to. - * @param port The port to connect to. - * @param proxy The proxy to connect via. - * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} - * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. - */ - @Deprecated - public void connect(String hostname, int port, Proxy proxy) throws IOException { + public void connect(String hostname, int port) throws IOException { this.hostname = hostname; - connect(InetAddress.getByName(hostname), port, proxy); + socket = socketFactory.createSocket(); + socket.connect(new InetSocketAddress(hostname, port), connectTimeout); + onConnect(); + } + + public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException { + this.hostname = hostname; + socket = socketFactory.createSocket(); + socket.bind(new InetSocketAddress(localAddr, localPort)); + socket.connect(new InetSocketAddress(hostname, port), connectTimeout); + onConnect(); + } + + public void connect(InetAddress host) throws IOException { + connect(host, defaultPort); + } + + public void connect(InetAddress host, int port) throws IOException { + socket = socketFactory.createSocket(); + socket.connect(new InetSocketAddress(host, port), connectTimeout); + onConnect(); } public void connect(InetAddress host, int port, InetAddress localAddr, int localPort) @@ -102,43 +150,6 @@ public abstract class SocketClient { onConnect(); } - public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException { - this.hostname = hostname; - connect(InetAddress.getByName(hostname), port, localAddr, localPort); - } - - public void connect(InetAddress host) throws IOException { - connect(host, defaultPort); - } - - public void connect(String hostname) throws IOException { - connect(hostname, defaultPort); - } - - /** - * Connect to a host via a proxy. - * @param host The host address to connect to. - * @param proxy The proxy to connect via. - * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} - * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. - */ - @Deprecated - public void connect(InetAddress host, Proxy proxy) throws IOException { - connect(host, defaultPort, proxy); - } - - /** - * Connect to a host via a proxy. - * @param hostname The host name to connect to. - * @param proxy The proxy to connect via. - * @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory} - * into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor. - */ - @Deprecated - public void connect(String hostname, Proxy proxy) throws IOException { - connect(hostname, defaultPort, proxy); - } - public void disconnect() throws IOException { if (socket != null) { socket.close(); From ba347f927d34ad25d709161bfeffe24e78cca3f7 Mon Sep 17 00:00:00 2001 From: David Solin Date: Mon, 15 Aug 2016 00:17:48 -0500 Subject: [PATCH 2/4] Close any LocalPortForwarders with the SSHClient that produced them (assuming they're still open). --- src/main/java/net/schmizz/sshj/SSHClient.java | 18 +++++++++- .../channel/direct/LocalPortForwarder.java | 33 ++++++++++++++++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/SSHClient.java b/src/main/java/net/schmizz/sshj/SSHClient.java index b391a866..a24cf4ae 100644 --- a/src/main/java/net/schmizz/sshj/SSHClient.java +++ b/src/main/java/net/schmizz/sshj/SSHClient.java @@ -139,6 +139,8 @@ public class SSHClient /** {@code ssh-connection} service */ protected final Connection conn; + private List forwarders; + /** Default constructor. Initializes this object using {@link DefaultConfig}. */ public SSHClient() { this(new DefaultConfig()); @@ -431,6 +433,15 @@ public class SSHClient @Override public void disconnect() throws IOException { + if (forwarders != null) { + for (LocalPortForwarder forwarder : forwarders) { + try { + forwarder.close(); + } catch (IOException e) { + log.warn("Error closing forwarder", e); + } + } + } trans.disconnect(); super.disconnect(); } @@ -648,7 +659,12 @@ public class SSHClient */ public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters, ServerSocket serverSocket) { - return new LocalPortForwarder(conn, parameters, serverSocket); + if (forwarders == null) { + forwarders = new ArrayList(); + } + LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket); + forwarders.add(forwarder); + return forwarder; } /** diff --git a/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java b/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java index a3511cac..1721e5a8 100644 --- a/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java +++ b/src/main/java/net/schmizz/sshj/connection/channel/direct/LocalPortForwarder.java @@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; import java.util.concurrent.TimeUnit; import static com.hierynomus.sshj.backport.Sockets.asCloseable; @@ -134,11 +135,33 @@ public class LocalPortForwarder { throws IOException { log.info("Listening on {}", serverSocket.getLocalSocketAddress()); while (!Thread.currentThread().isInterrupted()) { - final Socket socket = serverSocket.accept(); - log.debug("Got connection from {}", socket.getRemoteSocketAddress()); - startChannel(socket); + try { + final Socket socket = serverSocket.accept(); + log.debug("Got connection from {}", socket.getRemoteSocketAddress()); + startChannel(socket); + } catch (SocketException e) { + if (!serverSocket.isClosed()) { + throw e; + } + } + } + if (serverSocket.isClosed()) { + log.debug("LocalPortForwarder closed"); + } else { + log.debug("LocalPortForwarder interrupted!"); } - log.debug("Interrupted!"); } -} \ No newline at end of file + /** + * Close the ServerSocket that's listening for connections to forward. + * + * @throws IOException + */ + public void close() throws IOException { + if (!serverSocket.isClosed()) { + log.info("Closing listener on {}", serverSocket.getLocalSocketAddress()); + serverSocket.close(); + } + } + +} From 4183776adbb9ef8eae632c4e878747be053e22d6 Mon Sep 17 00:00:00 2001 From: David Solin Date: Tue, 16 Aug 2016 09:17:30 -0500 Subject: [PATCH 3/4] Updates per Jeroen van Erp. --- src/main/java/net/schmizz/sshj/SSHClient.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/SSHClient.java b/src/main/java/net/schmizz/sshj/SSHClient.java index a24cf4ae..daecc5a6 100644 --- a/src/main/java/net/schmizz/sshj/SSHClient.java +++ b/src/main/java/net/schmizz/sshj/SSHClient.java @@ -139,7 +139,7 @@ public class SSHClient /** {@code ssh-connection} service */ protected final Connection conn; - private List forwarders; + private final List forwarders = new ArrayList(); /** Default constructor. Initializes this object using {@link DefaultConfig}. */ public SSHClient() { @@ -433,15 +433,14 @@ public class SSHClient @Override public void disconnect() throws IOException { - if (forwarders != null) { - for (LocalPortForwarder forwarder : forwarders) { - try { - forwarder.close(); - } catch (IOException e) { - log.warn("Error closing forwarder", e); - } + for (LocalPortForwarder forwarder : forwarders) { + try { + forwarder.close(); + } catch (IOException e) { + log.warn("Error closing forwarder", e); } } + forwarders.clear(); trans.disconnect(); super.disconnect(); } @@ -659,9 +658,6 @@ public class SSHClient */ public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters, ServerSocket serverSocket) { - if (forwarders == null) { - forwarders = new ArrayList(); - } LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket); forwarders.add(forwarder); return forwarder; From 1caa7ac722a4691bf63cfe041663966bbc9bb778 Mon Sep 17 00:00:00 2001 From: David Solin Date: Tue, 16 Aug 2016 10:26:57 -0500 Subject: [PATCH 4/4] For null hostnames, use the loopback InetAddress (for backward-compatibility). --- .../java/net/schmizz/sshj/SocketClient.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/SocketClient.java b/src/main/java/net/schmizz/sshj/SocketClient.java index 7a843380..e831bffa 100644 --- a/src/main/java/net/schmizz/sshj/SocketClient.java +++ b/src/main/java/net/schmizz/sshj/SocketClient.java @@ -118,18 +118,26 @@ public abstract class SocketClient { } public void connect(String hostname, int port) throws IOException { - this.hostname = hostname; - socket = socketFactory.createSocket(); - socket.connect(new InetSocketAddress(hostname, port), connectTimeout); - onConnect(); + if (hostname == null) { + connect(InetAddress.getByName(null), port); + } else { + this.hostname = hostname; + socket = socketFactory.createSocket(); + socket.connect(new InetSocketAddress(hostname, port), connectTimeout); + onConnect(); + } } public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException { - this.hostname = hostname; - socket = socketFactory.createSocket(); - socket.bind(new InetSocketAddress(localAddr, localPort)); - socket.connect(new InetSocketAddress(hostname, port), connectTimeout); - onConnect(); + if (hostname == null) { + connect(InetAddress.getByName(null), port, localAddr, localPort); + } else { + this.hostname = hostname; + socket = socketFactory.createSocket(); + socket.bind(new InetSocketAddress(localAddr, localPort)); + socket.connect(new InetSocketAddress(hostname, port), connectTimeout); + onConnect(); + } } public void connect(InetAddress host) throws IOException {