aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2015-10-08 11:30:36 -0700
committerKenny Root <kenny@the-b.org>2015-10-08 11:30:36 -0700
commit39aef25501455b50fff7e0cb3ddf5399ab4bfc29 (patch)
tree78ef34471bddab8095174b427c5eb9618352e962
parent5554072bac14a79a792fab0e890e888cc69ff98a (diff)
parentbd9f683112c37baef10fd5514ec2dfd571d0c0dc (diff)
downloadsshlib-39aef25501455b50fff7e0cb3ddf5399ab4bfc29.tar.gz
sshlib-39aef25501455b50fff7e0cb3ddf5399ab4bfc29.tar.bz2
sshlib-39aef25501455b50fff7e0cb3ddf5399ab4bfc29.zip
Merge pull request #5 from kruton/indirect-proxy
Allow indirect proxy classes to implement their own functions
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/Connection.java84
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/HTTPProxyData.java114
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/ProxyData.java17
-rw-r--r--sshlib/src/main/java/com/trilead/ssh2/transport/TransportManager.java152
4 files changed, 142 insertions, 225 deletions
diff --git a/sshlib/src/main/java/com/trilead/ssh2/Connection.java b/sshlib/src/main/java/com/trilead/ssh2/Connection.java
index 6badb09..a957b2a 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;
@@ -105,8 +103,6 @@ public class Connection
private TransportManager tm;
- private boolean tcpNoDelay = false;
-
private ProxyData proxyData = null;
private Vector<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>();
@@ -141,63 +137,6 @@ public class Connection
}
/**
- * 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).
- * <p>
- * If the authentication phase is complete, <code>true</code> will be
- * returned. If the server does not accept the request (or if further
- * authentication steps are needed), <code>false</code> is returned and
- * one can retry either by using this or any other authentication method
- * (use the <code>getRemainingAuthMethods</code> method to get a list of
- * the remaining possible methods).
- *
- * @param user
- * A <code>String</code> holding the username.
- * @param pem
- * A <code>String</code> 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 <code>null</code>.
- *
- * @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)
* authenticateWithKeyboardInteractivewith} a <code>null</code> submethod
@@ -813,8 +752,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);
@@ -1410,27 +1347,6 @@ public class Connection
}
/**
- * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the
- * underlying socket.
- * <p>
- * 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 <code>false</code>.
- *
- * @param enable
- * the argument passed to the <code>Socket.setTCPNoDelay()</code>
- * 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
* the {@link #connect() connect()} method.
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 <code>HTTPProxyData</code> 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, <code>null</code>, <code>null</code>)}
@@ -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 8f3406e..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,25 +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.SocketTimeoutException;
-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;
@@ -28,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;
/*
@@ -73,7 +65,7 @@ public class TransportManager
{
while (true)
{
- byte[] msg = null;
+ byte[] msg;
synchronized (asynchronousQueue)
{
@@ -126,7 +118,7 @@ public class TransportManager
String hostname;
int port;
- final Socket sock = new Socket();
+ Socket sock;
Object connectionSemaphore = new Object();
@@ -156,16 +148,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);
@@ -194,7 +176,8 @@ public class TransportManager
try
{
- sock.close();
+ if (sock != null)
+ sock.close();
}
catch (IOException ignore)
{
@@ -225,7 +208,8 @@ public class TransportManager
try
{
- sock.close();
+ if (sock != null)
+ sock.close();
}
catch (IOException ignore)
{
@@ -272,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,