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