From 08ab36bc773b1c270585d8020a65d6cd5e84a207 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 8 Oct 2015 09:47:04 -0700 Subject: Remove tcpNoDelay setting This conflicts with more advanced proxy transports that don't support this, so just remove it altogether. --- .../src/main/java/com/trilead/ssh2/Connection.java | 25 ---------------------- .../trilead/ssh2/transport/TransportManager.java | 11 ---------- 2 files changed, 36 deletions(-) diff --git a/sshlib/src/main/java/com/trilead/ssh2/Connection.java b/sshlib/src/main/java/com/trilead/ssh2/Connection.java index 8582ea4..1f605e0 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/Connection.java +++ b/sshlib/src/main/java/com/trilead/ssh2/Connection.java @@ -105,8 +105,6 @@ public class Connection private TransportManager tm; - private boolean tcpNoDelay = false; - private ProxyData proxyData = null; private Vector connectionMonitors = new Vector(); @@ -812,8 +810,6 @@ public class Connection "The connect() operation on the socket timed out.").initCause(se); } - tm.setTcpNoDelay(tcpNoDelay); - /* Wait until first KEX has finished */ ConnectionInfo ci = tm.getConnectionInfo(1); @@ -1408,27 +1404,6 @@ public class Connection cryptoWishList.serverHostKeyAlgorithms = algos; } - /** - * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the - * underlying socket. - *

- * Can be called at any time. If the connection has not yet been established - * then the passed value will be stored and set after the socket has been - * set up. The default value that will be used is false. - * - * @param enable - * the argument passed to the Socket.setTCPNoDelay() - * method. - * @throws IOException - */ - public synchronized void setTCPNoDelay(boolean enable) throws IOException - { - tcpNoDelay = enable; - - if (tm != null) - tm.setTcpNoDelay(enable); - } - /** * Used to tell the library that the connection shall be established through * a proxy server. It only makes sense to call this method before calling diff --git a/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java b/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java index 8f3406e..b991f3c 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java +++ b/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java @@ -7,7 +7,6 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Vector; @@ -156,16 +155,6 @@ public class TransportManager return tc.getPacketOverheadEstimate(); } - public void setTcpNoDelay(boolean state) throws IOException - { - sock.setTcpNoDelay(state); - } - - public void setSoTimeout(int timeout) throws IOException - { - sock.setSoTimeout(timeout); - } - public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException { return km.getOrWaitForConnectionInfo(kexNumber); -- cgit v1.2.3 From 0c73789e89238324ddcb233bda972c48ac94a1e2 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 8 Oct 2015 09:47:55 -0700 Subject: Remove the authenticateWithDSA method This has been deprecated for quite a while and using DSA should be discouraged. --- .../src/main/java/com/trilead/ssh2/Connection.java | 59 ---------------------- 1 file changed, 59 deletions(-) diff --git a/sshlib/src/main/java/com/trilead/ssh2/Connection.java b/sshlib/src/main/java/com/trilead/ssh2/Connection.java index 1f605e0..efb84b8 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/Connection.java +++ b/sshlib/src/main/java/com/trilead/ssh2/Connection.java @@ -9,8 +9,6 @@ import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.security.KeyPair; import java.security.SecureRandom; -import java.security.Security; -import java.util.Set; import java.util.Vector; import com.trilead.ssh2.auth.AuthenticationManager; @@ -138,63 +136,6 @@ public class Connection this.port = port; } - /** - * After a successful connect, one has to authenticate oneself. This method - * is based on DSA (it uses DSA to sign a challenge sent by the server). - *

- * If the authentication phase is complete, true will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), false is returned and - * one can retry either by using this or any other authentication method - * (use the getRemainingAuthMethods method to get a list of - * the remaining possible methods). - * - * @param user - * A String holding the username. - * @param pem - * A String containing the DSA private key of the - * user in OpenSSH key format (PEM, you can't miss the - * "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain - * linefeeds. - * @param password - * If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you - * must specify the password. Otherwise, this argument will be - * ignored and can be set to null. - * - * @return whether the connection is now authenticated. - * @throws IOException - * - * @deprecated You should use one of the - * {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()} - * methods, this method is just a wrapper for it and will - * disappear in future builds. - * - */ - public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - if (pem == null) - throw new IllegalArgumentException("pem argument is null"); - - authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND()); - - return authenticated; - } - /** * A wrapper that calls * {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback) -- cgit v1.2.3 From bd9f683112c37baef10fd5514ec2dfd571d0c0dc Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 8 Oct 2015 09:57:51 -0700 Subject: Move socket creation out to its own function Newer proxy types will need to have a way to create their own sockets, so move this out to its own function to allow that later. --- .../main/java/com/trilead/ssh2/HTTPProxyData.java | 114 ++++++++++++++++- .../src/main/java/com/trilead/ssh2/ProxyData.java | 17 ++- .../trilead/ssh2/transport/TransportManager.java | 141 +++------------------ 3 files changed, 142 insertions(+), 130 deletions(-) diff --git a/sshlib/src/main/java/com/trilead/ssh2/HTTPProxyData.java b/sshlib/src/main/java/com/trilead/ssh2/HTTPProxyData.java index 2edffe6..3c3c54a 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/HTTPProxyData.java +++ b/sshlib/src/main/java/com/trilead/ssh2/HTTPProxyData.java @@ -1,6 +1,16 @@ package com.trilead.ssh2; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; + +import com.trilead.ssh2.crypto.Base64; +import com.trilead.ssh2.transport.ClientServerHello; + /** * A HTTPProxyData object is used to specify the needed connection data * to connect through a HTTP proxy. @@ -13,11 +23,11 @@ package com.trilead.ssh2; public class HTTPProxyData implements ProxyData { - public final String proxyHost; - public final int proxyPort; - public final String proxyUser; - public final String proxyPass; - public final String[] requestHeaderLines; + private final String proxyHost; + private final int proxyPort; + private final String proxyUser; + private final String proxyPass; + private final String[] requestHeaderLines; /** * Same as calling {@link #HTTPProxyData(String, int, String, String) HTTPProxyData(proxyHost, proxyPort, null, null)} @@ -80,4 +90,98 @@ public class HTTPProxyData implements ProxyData this.proxyPass = proxyPass; this.requestHeaderLines = requestHeaderLines; } + + @Override + public Socket openConnection(String hostname, int port, int connectTimeout) throws IOException { + Socket sock = new Socket(); + + InetAddress addr = InetAddress.getByName(proxyHost); + sock.connect(new InetSocketAddress(addr, proxyPort), connectTimeout); + sock.setSoTimeout(0); + + /* OK, now tell the proxy where we actually want to connect to */ + + StringBuffer sb = new StringBuffer(); + + sb.append("CONNECT "); + sb.append(hostname); + sb.append(':'); + sb.append(port); + sb.append(" HTTP/1.0\r\n"); + + if ((proxyUser != null) && (proxyPass != null)) + { + String credentials = proxyUser + ":" + proxyPass; + char[] encoded = Base64.encode(credentials.getBytes("ISO-8859-1")); + sb.append("Proxy-Authorization: Basic "); + sb.append(encoded); + sb.append("\r\n"); + } + + if (requestHeaderLines != null) + { + for (int i = 0; i < requestHeaderLines.length; i++) + { + if (requestHeaderLines[i] != null) + { + sb.append(requestHeaderLines[i]); + sb.append("\r\n"); + } + } + } + + sb.append("\r\n"); + + OutputStream out = sock.getOutputStream(); + + out.write(sb.toString().getBytes("ISO-8859-1")); + out.flush(); + + /* Now parse the HTTP response */ + + byte[] buffer = new byte[1024]; + InputStream in = sock.getInputStream(); + + int len = ClientServerHello.readLineRN(in, buffer); + + String httpReponse = new String(buffer, 0, len, "ISO-8859-1"); + + if (httpReponse.startsWith("HTTP/") == false) + throw new IOException("The proxy did not send back a valid HTTP response."); + + /* "HTTP/1.X XYZ X" => 14 characters minimum */ + + if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) + throw new IOException("The proxy did not send back a valid HTTP response."); + + int errorCode = 0; + + try + { + errorCode = Integer.parseInt(httpReponse.substring(9, 12)); + } + catch (NumberFormatException ignore) + { + throw new IOException("The proxy did not send back a valid HTTP response."); + } + + if ((errorCode < 0) || (errorCode > 999)) + throw new IOException("The proxy did not send back a valid HTTP response."); + + if (errorCode != 200) + { + throw new HTTPProxyException(httpReponse.substring(13), errorCode); + } + + /* OK, read until empty line */ + + while (true) + { + len = ClientServerHello.readLineRN(in, buffer); + if (len == 0) + break; + } + + return sock; + } } diff --git a/sshlib/src/main/java/com/trilead/ssh2/ProxyData.java b/sshlib/src/main/java/com/trilead/ssh2/ProxyData.java index 059a6e3..864d7a0 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/ProxyData.java +++ b/sshlib/src/main/java/com/trilead/ssh2/ProxyData.java @@ -1,8 +1,11 @@ package com.trilead.ssh2; +import java.io.IOException; +import java.net.Socket; + /** - * An abstract marker interface implemented by all proxy data implementations. + * An abstract interface implemented by all proxy data implementations. * * @see HTTPProxyData * @@ -10,6 +13,16 @@ package com.trilead.ssh2; * @version $Id: ProxyData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ */ -public abstract interface ProxyData +public interface ProxyData { + /** + * Connects the socket to the given destination using the proxy method that this instance + * represents. + * @param hostname hostname of end host (not proxy) + * @param port port of end host (not proxy) + * @param connectTimeout number of seconds before giving up on connecting to end host + * @throws IOException if the connection could not be completed + * @return connected socket instance + */ + Socket openConnection(String hostname, int port, int connectTimeout) throws IOException; } diff --git a/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java b/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java index b991f3c..4c56e30 100644 --- a/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java +++ b/sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java @@ -2,24 +2,18 @@ package com.trilead.ssh2.transport; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Vector; import com.trilead.ssh2.ConnectionInfo; import com.trilead.ssh2.ConnectionMonitor; import com.trilead.ssh2.DHGexParameters; -import com.trilead.ssh2.HTTPProxyData; -import com.trilead.ssh2.HTTPProxyException; import com.trilead.ssh2.ProxyData; import com.trilead.ssh2.ServerHostKeyVerifier; import com.trilead.ssh2.compression.ICompressor; -import com.trilead.ssh2.crypto.Base64; import com.trilead.ssh2.crypto.CryptoWishList; import com.trilead.ssh2.crypto.cipher.BlockCipher; import com.trilead.ssh2.crypto.digest.MAC; @@ -27,7 +21,6 @@ import com.trilead.ssh2.log.Logger; import com.trilead.ssh2.packets.PacketDisconnect; import com.trilead.ssh2.packets.Packets; import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.util.Tokenizer; /* @@ -72,7 +65,7 @@ public class TransportManager { while (true) { - byte[] msg = null; + byte[] msg; synchronized (asynchronousQueue) { @@ -125,7 +118,7 @@ public class TransportManager String hostname; int port; - final Socket sock = new Socket(); + Socket sock; Object connectionSemaphore = new Object(); @@ -183,7 +176,8 @@ public class TransportManager try { - sock.close(); + if (sock != null) + sock.close(); } catch (IOException ignore) { @@ -214,7 +208,8 @@ public class TransportManager try { - sock.close(); + if (sock != null) + sock.close(); } catch (IOException ignore) { @@ -261,122 +256,22 @@ public class TransportManager } } - private static void tryAllAddresses(Socket sock, String host, int port, int connectTimeout) throws IOException { - InetAddress[] addresses = InetAddress.getAllByName(host); - for (InetAddress addr : addresses) { - try { - sock.connect(new InetSocketAddress(addr, port), connectTimeout); - return; - } catch (SocketTimeoutException e) { - } - } - throw new SocketTimeoutException("Could not connect; socket timed out"); - } - private void establishConnection(ProxyData proxyData, int connectTimeout) throws IOException { if (proxyData == null) - { - tryAllAddresses(sock, hostname, port, connectTimeout); - sock.setSoTimeout(0); - return; - } - - if (proxyData instanceof HTTPProxyData) - { - HTTPProxyData pd = (HTTPProxyData) proxyData; - - /* At the moment, we only support HTTP proxies */ - - tryAllAddresses(sock, pd.proxyHost, pd.proxyPort, connectTimeout); - sock.setSoTimeout(0); - - /* OK, now tell the proxy where we actually want to connect to */ - - StringBuffer sb = new StringBuffer(); - - sb.append("CONNECT "); - sb.append(hostname); - sb.append(':'); - sb.append(port); - sb.append(" HTTP/1.0\r\n"); - - if ((pd.proxyUser != null) && (pd.proxyPass != null)) - { - String credentials = pd.proxyUser + ":" + pd.proxyPass; - char[] encoded = Base64.encode(credentials.getBytes("ISO-8859-1")); - sb.append("Proxy-Authorization: Basic "); - sb.append(encoded); - sb.append("\r\n"); - } - - if (pd.requestHeaderLines != null) - { - for (int i = 0; i < pd.requestHeaderLines.length; i++) - { - if (pd.requestHeaderLines[i] != null) - { - sb.append(pd.requestHeaderLines[i]); - sb.append("\r\n"); - } - } - } - - sb.append("\r\n"); - - OutputStream out = sock.getOutputStream(); - - out.write(sb.toString().getBytes("ISO-8859-1")); - out.flush(); - - /* Now parse the HTTP response */ - - byte[] buffer = new byte[1024]; - InputStream in = sock.getInputStream(); - - int len = ClientServerHello.readLineRN(in, buffer); - - String httpReponse = new String(buffer, 0, len, "ISO-8859-1"); - - if (httpReponse.startsWith("HTTP/") == false) - throw new IOException("The proxy did not send back a valid HTTP response."); - - /* "HTTP/1.X XYZ X" => 14 characters minimum */ - - if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) - throw new IOException("The proxy did not send back a valid HTTP response."); - - int errorCode = 0; - - try - { - errorCode = Integer.parseInt(httpReponse.substring(9, 12)); - } - catch (NumberFormatException ignore) - { - throw new IOException("The proxy did not send back a valid HTTP response."); - } - - if ((errorCode < 0) || (errorCode > 999)) - throw new IOException("The proxy did not send back a valid HTTP response."); - - if (errorCode != 200) - { - throw new HTTPProxyException(httpReponse.substring(13), errorCode); - } - - /* OK, read until empty line */ - - while (true) - { - len = ClientServerHello.readLineRN(in, buffer); - if (len == 0) - break; - } - return; - } + sock = connectDirect(hostname, port, connectTimeout); + else + sock = proxyData.openConnection(hostname, port, connectTimeout); + } - throw new IOException("Unsupported ProxyData"); + private static Socket connectDirect(String hostname, int port, int connectTimeout) + throws IOException + { + Socket sock = new Socket(); + InetAddress addr = InetAddress.getByName(hostname); + sock.connect(new InetSocketAddress(addr, port), connectTimeout); + sock.setSoTimeout(0); + return sock; } public void initialize(CryptoWishList cwl, ServerHostKeyVerifier verifier, DHGexParameters dhgex, -- cgit v1.2.3